Merge branch 'release-candidate' into release
This commit is contained in:
		
						commit
						d21e5bd56e
					
				
							
								
								
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -76,8 +76,8 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           run: | |           run: | | ||||||
|             set -e |             set -e | ||||||
|             make -C assets clean |             make assets_rebuild assets_manifest | ||||||
|             make -C assets |             git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) | ||||||
| 
 | 
 | ||||||
|       - name: 'Build the firmware in docker' |       - name: 'Build the firmware in docker' | ||||||
|         uses: ./.github/actions/docker |         uses: ./.github/actions/docker | ||||||
| @ -117,7 +117,6 @@ jobs: | |||||||
|       - name: 'Bundle resources' |       - name: 'Bundle resources' | ||||||
|         if: ${{ !github.event.pull_request.head.repo.fork }} |         if: ${{ !github.event.pull_request.head.repo.fork }} | ||||||
|         run: | |         run: | | ||||||
|           ./scripts/assets.py manifest assets/resources |  | ||||||
|           tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources |           tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources | ||||||
| 
 | 
 | ||||||
|       - name: 'Bundle core2 firmware' |       - name: 'Bundle core2 firmware' | ||||||
|  | |||||||
							
								
								
									
										25
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								Makefile
									
									
									
									
									
								
							| @ -51,6 +51,10 @@ flash: firmware_flash | |||||||
| debug: | debug: | ||||||
| 	@$(MAKE) -C firmware -j$(NPROCS) debug | 	@$(MAKE) -C firmware -j$(NPROCS) debug | ||||||
| 
 | 
 | ||||||
|  | .PHONY: debug_other | ||||||
|  | debug_other: | ||||||
|  | 	@$(MAKE) -C firmware -j$(NPROCS) debug_other | ||||||
|  | 
 | ||||||
| .PHONY: blackmagic | .PHONY: blackmagic | ||||||
| blackmagic: | blackmagic: | ||||||
| 	@$(MAKE) -C firmware -j$(NPROCS) blackmagic | 	@$(MAKE) -C firmware -j$(NPROCS) blackmagic | ||||||
| @ -75,7 +79,6 @@ ifeq ($(FORCE), 1) | |||||||
| endif | endif | ||||||
| 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash | 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| .PHONY: updater | .PHONY: updater | ||||||
| updater: | updater: | ||||||
| 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all | 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all | ||||||
| @ -88,10 +91,22 @@ updater_clean: | |||||||
| updater_debug: | updater_debug: | ||||||
| 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug | 	@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug | ||||||
| 
 | 
 | ||||||
| .PHONY: updater_package | .PHONY: updater_package_bin | ||||||
| updater_package: firmware_all updater | updater_package_bin: firmware_all updater | ||||||
| 	@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)" | 	@$(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 | .PHONY: flash_radio | ||||||
| flash_radio: | flash_radio: | ||||||
| 	@$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin | 	@$(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 | .PHONY: flash_radio_fus_please_i_m_not_going_to_complain | ||||||
| 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_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_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.bin | ||||||
| 	@$(PROJECT_ROOT)/scripts/ob.py set | 	@$(PROJECT_ROOT)/scripts/ob.py set | ||||||
| 
 | 
 | ||||||
| .PHONY: lint | .PHONY: lint | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ extern int32_t usb_test_app(void* p); | |||||||
| extern int32_t vibro_test_app(void* p); | extern int32_t vibro_test_app(void* p); | ||||||
| extern int32_t bt_hid_app(void* p); | extern int32_t bt_hid_app(void* p); | ||||||
| extern int32_t battery_test_app(void* p); | extern int32_t battery_test_app(void* p); | ||||||
|  | extern int32_t text_box_test_app(void* p); | ||||||
| 
 | 
 | ||||||
| // Plugins
 | // Plugins
 | ||||||
| extern int32_t music_player_app(void* p); | extern int32_t music_player_app(void* p); | ||||||
| @ -304,6 +305,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | |||||||
| #ifdef APP_BATTERY_TEST | #ifdef APP_BATTERY_TEST | ||||||
|     {.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL}, |     {.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #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); | const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS); | ||||||
|  | |||||||
| @ -165,6 +165,12 @@ CFLAGS		+= -DAPP_DISPLAY_TEST | |||||||
| SRV_GUI = 1 | SRV_GUI = 1 | ||||||
| endif | 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 | APP_BATTERY_TEST ?= 0 | ||||||
| ifeq ($(APP_BATTERY_TEST), 1) | ifeq ($(APP_BATTERY_TEST), 1) | ||||||
| CFLAGS		+= -DAPP_BATTERY_TEST | CFLAGS		+= -DAPP_BATTERY_TEST | ||||||
|  | |||||||
| @ -391,14 +391,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) { | |||||||
|     furi_assert(browser); |     furi_assert(browser); | ||||||
|     furi_assert(name); |     furi_assert(name); | ||||||
| 
 | 
 | ||||||
|     uint8_t browser_depth = 0; |     if(string_size(name) >= (MAX_NAME_LEN - 1)) { | ||||||
|     with_view_model( |  | ||||||
|         browser->view, (ArchiveBrowserViewModel * model) { |  | ||||||
|             browser_depth = idx_last_array_size(model->idx_last); |  | ||||||
|             return false; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     if(browser_depth > BROWSER_DEPTH_MAX) { |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| 
 | 
 | ||||||
| #define TAB_RIGHT InputKeyRight //default tab swith direction
 | #define TAB_RIGHT InputKeyRight //default tab swith direction
 | ||||||
| #define FILE_LIST_BUF_LEN 100 | #define FILE_LIST_BUF_LEN 100 | ||||||
| #define BROWSER_DEPTH_MAX 8 |  | ||||||
| 
 | 
 | ||||||
| static const char* tab_default_paths[] = { | static const char* tab_default_paths[] = { | ||||||
|     [ArchiveTabFavorites] = "/any/favorites", |     [ArchiveTabFavorites] = "/any/favorites", | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ void archive_scene_delete_on_enter(void* context) { | |||||||
|     ArchiveApp* app = (ArchiveApp*)context; |     ArchiveApp* app = (ArchiveApp*)context; | ||||||
| 
 | 
 | ||||||
|     widget_add_button_element( |     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( |     widget_add_button_element( | ||||||
|         app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); |         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]; |     char delete_str[64]; | ||||||
|     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name); |     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); |     view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -189,6 +189,8 @@ static void bt_cli_print_usage() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void bt_cli(Cli* cli, string_t args, void* context) { | static void bt_cli(Cli* cli, string_t args, void* context) { | ||||||
|  |     furi_record_open("bt"); | ||||||
|  | 
 | ||||||
|     string_t cmd; |     string_t cmd; | ||||||
|     string_init(cmd); |     string_init(cmd); | ||||||
|     BtSettings bt_settings; |     BtSettings bt_settings; | ||||||
| @ -235,14 +237,13 @@ static void bt_cli(Cli* cli, string_t args, void* context) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(cmd); |     string_clear(cmd); | ||||||
|  |     furi_record_close("bt"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bt_on_system_start() { | void bt_on_system_start() { | ||||||
| #ifdef SRV_CLI | #ifdef SRV_CLI | ||||||
|     Cli* cli = furi_record_open("cli"); |     Cli* cli = furi_record_open("cli"); | ||||||
|     furi_record_open("bt"); |  | ||||||
|     cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL); |     cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL); | ||||||
|     furi_record_close("bt"); |  | ||||||
|     furi_record_close("cli"); |     furi_record_close("cli"); | ||||||
| #else | #else | ||||||
|     UNUSED(bt_cli); |     UNUSED(bt_cli); | ||||||
|  | |||||||
| @ -320,7 +320,7 @@ int32_t bt_srv() { | |||||||
|     Bt* bt = bt_alloc(); |     Bt* bt = bt_alloc(); | ||||||
| 
 | 
 | ||||||
|     // Read keys
 |     // Read keys
 | ||||||
|     if(!bt_load_key_storage(bt)) { |     if(!bt_keys_storage_load(bt)) { | ||||||
|         FURI_LOG_W(TAG, "Failed to load bonding keys"); |         FURI_LOG_W(TAG, "Failed to load bonding keys"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -365,11 +365,11 @@ int32_t bt_srv() { | |||||||
|             // Display PIN code
 |             // Display PIN code
 | ||||||
|             bt_pin_code_show(bt, message.data.pin_code); |             bt_pin_code_show(bt, message.data.pin_code); | ||||||
|         } else if(message.type == BtMessageTypeKeysStorageUpdated) { |         } else if(message.type == BtMessageTypeKeysStorageUpdated) { | ||||||
|             bt_save_key_storage(bt); |             bt_keys_storage_save(bt); | ||||||
|         } else if(message.type == BtMessageTypeSetProfile) { |         } else if(message.type == BtMessageTypeSetProfile) { | ||||||
|             bt_change_profile(bt, &message); |             bt_change_profile(bt, &message); | ||||||
|         } else if(message.type == BtMessageTypeForgetBondedDevices) { |         } else if(message.type == BtMessageTypeForgetBondedDevices) { | ||||||
|             bt_delete_key_storage(bt); |             bt_keys_storage_delete(bt); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
|  | |||||||
| @ -1,46 +1,47 @@ | |||||||
| #include "bt_keys_storage.h" | #include "bt_keys_storage.h" | ||||||
|  | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <file_worker.h> | #include <lib/toolbox/saved_struct.h> | ||||||
| 
 | 
 | ||||||
| #define BT_KEYS_STORAGE_TAG "bt keys storage" |  | ||||||
| #define BT_KEYS_STORAGE_PATH "/int/bt.keys" | #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); |     furi_assert(bt); | ||||||
| 
 |  | ||||||
|     bool file_loaded = false; |     bool file_loaded = false; | ||||||
|     furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size); |  | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(true); |     furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size); | ||||||
|     if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { |     furi_hal_bt_nvm_sram_sem_acquire(); | ||||||
|         furi_hal_bt_nvm_sram_sem_acquire(); |     file_loaded = saved_struct_load( | ||||||
|         if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { |         BT_KEYS_STORAGE_PATH, | ||||||
|             file_loaded = true; |         bt->bt_keys_addr_start, | ||||||
|         } |         bt->bt_keys_size, | ||||||
|         furi_hal_bt_nvm_sram_sem_release(); |         BT_KEYS_STORAGE_MAGIC, | ||||||
|     } |         BT_KEYS_STORAGE_VERSION); | ||||||
|     file_worker_free(file_worker); |     furi_hal_bt_nvm_sram_sem_release(); | ||||||
|  | 
 | ||||||
|     return file_loaded; |     return file_loaded; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bt_save_key_storage(Bt* bt) { | bool bt_keys_storage_save(Bt* bt) { | ||||||
|     furi_assert(bt); |     furi_assert(bt); | ||||||
|     furi_assert(bt->bt_keys_addr_start); |     furi_assert(bt->bt_keys_addr_start); | ||||||
| 
 |  | ||||||
|     bool file_saved = false; |     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(); | ||||||
|         furi_hal_bt_nvm_sram_sem_acquire(); |     file_saved = saved_struct_save( | ||||||
|         if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { |         BT_KEYS_STORAGE_PATH, | ||||||
|             file_saved = true; |         bt->bt_keys_addr_start, | ||||||
|         } |         bt->bt_keys_size, | ||||||
|         furi_hal_bt_nvm_sram_sem_release(); |         BT_KEYS_STORAGE_MAGIC, | ||||||
|     } |         BT_KEYS_STORAGE_VERSION); | ||||||
|     file_worker_free(file_worker); |     furi_hal_bt_nvm_sram_sem_release(); | ||||||
|  | 
 | ||||||
|     return file_saved; |     return file_saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bt_delete_key_storage(Bt* bt) { | bool bt_keys_storage_delete(Bt* bt) { | ||||||
|     furi_assert(bt); |     furi_assert(bt); | ||||||
|     bool delete_succeed = false; |     bool delete_succeed = false; | ||||||
|     bool bt_is_active = furi_hal_bt_is_active(); |     bool bt_is_active = furi_hal_bt_is_active(); | ||||||
|  | |||||||
| @ -2,8 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| #include "bt_i.h" | #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); | ||||||
|  | |||||||
| @ -1,50 +1,22 @@ | |||||||
| #include "bt_settings.h" | #include "bt_settings.h" | ||||||
| #include <furi.h> |  | ||||||
| #include <file_worker.h> |  | ||||||
| 
 | 
 | ||||||
| #define TAG "BtSettings" | #include <furi.h> | ||||||
|  | #include <lib/toolbox/saved_struct.h> | ||||||
|  | 
 | ||||||
| #define BT_SETTINGS_PATH "/int/bt.settings" | #define BT_SETTINGS_PATH "/int/bt.settings" | ||||||
|  | #define BT_SETTINGS_VERSION (0) | ||||||
|  | #define BT_SETTINGS_MAGIC (0x19) | ||||||
| 
 | 
 | ||||||
| bool bt_settings_load(BtSettings* bt_settings) { | bool bt_settings_load(BtSettings* bt_settings) { | ||||||
|     furi_assert(bt_settings); |     furi_assert(bt_settings); | ||||||
|     bool file_loaded = false; |  | ||||||
|     BtSettings settings = {}; |  | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); |     return saved_struct_load( | ||||||
|     FileWorker* file_worker = file_worker_alloc(true); |         BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); | ||||||
|     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; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bt_settings_save(BtSettings* bt_settings) { | bool bt_settings_save(BtSettings* bt_settings) { | ||||||
|     furi_assert(bt_settings); |     furi_assert(bt_settings); | ||||||
|     bool result = false; |  | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(true); |     return saved_struct_save( | ||||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { |         BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); | ||||||
|         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; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,10 +3,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #define BT_SETTINGS_VERSION (0) |  | ||||||
| 
 |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t version; |  | ||||||
|     bool enabled; |     bool enabled; | ||||||
| } BtSettings; | } BtSettings; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										126
									
								
								applications/debug_tools/text_box_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								applications/debug_tools/text_box_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
|  | #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; | ||||||
|  | } | ||||||
| @ -161,8 +161,9 @@ void animation_manager_new_idle_process(AnimationManager* animation_manager) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* reaction to animation_manager->interact_callback() */ | /* 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); |     furi_assert(animation_manager); | ||||||
|  |     bool consumed = true; | ||||||
| 
 | 
 | ||||||
|     if(animation_manager->levelup_pending) { |     if(animation_manager->levelup_pending) { | ||||||
|         animation_manager->levelup_pending = false; |         animation_manager->levelup_pending = false; | ||||||
| @ -181,7 +182,11 @@ void animation_manager_interact_process(AnimationManager* animation_manager) { | |||||||
|         if(!blocked) { |         if(!blocked) { | ||||||
|             animation_manager_start_new_idle(animation_manager); |             animation_manager_start_new_idle(animation_manager); | ||||||
|         } |         } | ||||||
|  |     } else { | ||||||
|  |         consumed = false; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void animation_manager_start_new_idle(AnimationManager* animation_manager) { | static void animation_manager_start_new_idle(AnimationManager* animation_manager) { | ||||||
|  | |||||||
| @ -130,8 +130,9 @@ void animation_manager_set_interact_callback( | |||||||
|  * set_new_idle_callback's call. |  * set_new_idle_callback's call. | ||||||
|  * |  * | ||||||
|  * @animation_manager   instance |  * @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
 | /** Check if animation loaded
 | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -117,6 +117,7 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void desktop_lock(Desktop* desktop) { | void desktop_lock(Desktop* desktop) { | ||||||
|  |     furi_hal_rtc_set_pin_fails(0); | ||||||
|     desktop_auto_lock_inhibit(desktop); |     desktop_auto_lock_inhibit(desktop); | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); |         desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); | ||||||
|  | |||||||
| @ -116,7 +116,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | |||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
| 
 |  | ||||||
|         case DesktopAnimationEventCheckAnimation: |         case DesktopAnimationEventCheckAnimation: | ||||||
|             animation_manager_check_blocking_process(desktop->animation_manager); |             animation_manager_check_blocking_process(desktop->animation_manager); | ||||||
|             consumed = true; |             consumed = true; | ||||||
| @ -126,7 +125,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | |||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopAnimationEventInteractAnimation: |         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; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopLockedEventUpdate: |         case DesktopLockedEventUpdate: | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ typedef enum { | |||||||
|     DesktopMainEventOpenFavorite, |     DesktopMainEventOpenFavorite, | ||||||
|     DesktopMainEventOpenMenu, |     DesktopMainEventOpenMenu, | ||||||
|     DesktopMainEventOpenDebug, |     DesktopMainEventOpenDebug, | ||||||
|     DesktopMainEventRightShort, |     DesktopMainEventOpenPassport, /**< Broken, don't use it */ | ||||||
| 
 | 
 | ||||||
|     DesktopLockedEventUnlocked, |     DesktopLockedEventUnlocked, | ||||||
|     DesktopLockedEventUpdate, |     DesktopLockedEventUpdate, | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ bool desktop_main_input(InputEvent* event, void* context) { | |||||||
|         } else if(event->key == InputKeyLeft) { |         } else if(event->key == InputKeyLeft) { | ||||||
|             main_view->callback(DesktopMainEventOpenFavorite, main_view->context); |             main_view->callback(DesktopMainEventOpenFavorite, main_view->context); | ||||||
|         } else if(event->key == InputKeyRight) { |         } else if(event->key == InputKeyRight) { | ||||||
|             main_view->callback(DesktopMainEventRightShort, main_view->context); |             main_view->callback(DesktopMainEventOpenPassport, main_view->context); | ||||||
|         } |         } | ||||||
|     } else if(event->type == InputTypeLong) { |     } else if(event->type == InputTypeLong) { | ||||||
|         if(event->key == InputKeyDown) { |         if(event->key == InputKeyDown) { | ||||||
|  | |||||||
| @ -197,7 +197,11 @@ static size_t | |||||||
|     uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); |     uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); | ||||||
|     uint8_t px_left = 0; |     uint8_t px_left = 0; | ||||||
|     if(horizontal == AlignCenter) { |     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) { |     } else if(horizontal == AlignLeft) { | ||||||
|         px_left = canvas_width(canvas) - x; |         px_left = canvas_width(canvas) - x; | ||||||
|     } else if(horizontal == AlignRight) { |     } else if(horizontal == AlignRight) { | ||||||
| @ -208,13 +212,13 @@ static size_t | |||||||
| 
 | 
 | ||||||
|     if(len_px > px_left) { |     if(len_px > px_left) { | ||||||
|         uint8_t excess_symbols_approximately = |         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
 |         // 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(excess_symbols_approximately > 0) { | ||||||
|         if(text_size > (excess_symbols_approximately + 5)) { |             excess_symbols_approximately = MAX(excess_symbols_approximately, 5); | ||||||
|             result = text_size - excess_symbols_approximately - 5; |             result = text_size - excess_symbols_approximately - 1; | ||||||
|         } else { |         } else { | ||||||
|             result = text_size - 1; |             result = text_size; | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         result = text_size; |         result = text_size; | ||||||
| @ -258,12 +262,17 @@ void elements_multiline_text_aligned( | |||||||
| 
 | 
 | ||||||
|         if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { |         if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { | ||||||
|             string_init_printf(line, "%.*s", chars_fit, start); |             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 { |         } else { | ||||||
|             string_init_printf(line, "%.*s-\n", chars_fit, start); |             string_init_printf(line, "%.*s-\n", chars_fit, start); | ||||||
|         } |         } | ||||||
|         canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); |         canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); | ||||||
|         string_clear(line); |         string_clear(line); | ||||||
|         y += font_height; |         y += font_height; | ||||||
|  |         if(y > canvas_height(canvas)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         start += chars_fit; |         start += chars_fit; | ||||||
|         start += start[0] == '\n' ? 1 : 0; |         start += start[0] == '\n' ? 1 : 0; | ||||||
| @ -547,7 +556,8 @@ void elements_text_box( | |||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text) { |     const char* text, | ||||||
|  |     bool strip_to_dots) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
| 
 | 
 | ||||||
|     ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; |     ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; | ||||||
| @ -571,6 +581,7 @@ void elements_text_box( | |||||||
|     uint8_t total_height_default = 0; |     uint8_t total_height_default = 0; | ||||||
|     uint16_t i = 0; |     uint16_t i = 0; | ||||||
|     bool full_text_processed = false; |     bool full_text_processed = false; | ||||||
|  |     uint16_t dots_width = canvas_string_width(canvas, "..."); | ||||||
| 
 | 
 | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
| 
 | 
 | ||||||
| @ -663,31 +674,29 @@ void elements_text_box( | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Set vertical alignment for all lines
 |     // Set vertical alignment for all lines
 | ||||||
|     if(full_text_processed) { |     if(total_height_default < height) { | ||||||
|         if(total_height_default < height) { |         if(vertical == AlignTop) { | ||||||
|             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; |  | ||||||
|             line[0].y = y + line[0].height; |             line[0].y = y + line[0].height; | ||||||
|             while(fill_pixel < free_pixel_num) { |         } else if(vertical == AlignCenter) { | ||||||
|                 line[j].y = line[j - 1].y + line[j - 1].leading_min + 1; |             line[0].y = y + line[0].height + (height - total_height_default) / 2; | ||||||
|                 fill_pixel++; |         } else if(vertical == AlignBottom) { | ||||||
|                 j = j % (line_num - 1) + 1; |             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
 |     // Draw line by line
 | ||||||
| @ -733,6 +742,13 @@ void elements_text_box( | |||||||
|                 canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); |                 canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); | ||||||
|                 canvas_invert_color(canvas); |                 canvas_invert_color(canvas); | ||||||
|             } else { |             } 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]); |                 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]); |             line[i].x += canvas_glyph_width(canvas, line[i].text[j]); | ||||||
|  | |||||||
| @ -194,17 +194,18 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width); | |||||||
| 
 | 
 | ||||||
| /** Draw text box element
 | /** Draw text box element
 | ||||||
|  * |  * | ||||||
|  * @param       canvas      Canvas instance |  * @param       canvas          Canvas instance | ||||||
|  * @param       x           x coordinate |  * @param       x               x coordinate | ||||||
|  * @param       y           y coordinate |  * @param       y               y coordinate | ||||||
|  * @param       width       width to fit text |  * @param       width           width to fit text | ||||||
|  * @param       height      height to fit text |  * @param       height          height to fit text | ||||||
|  * @param       horizontal  Align instance |  * @param       horizontal      Align instance | ||||||
|  * @param       vertical    Align instance |  * @param       vertical        Align instance | ||||||
|  * @param[in]   text        Formatted text. The following formats are available: |  * @param[in]   text            Formatted text. The following formats are available: | ||||||
|  *                          "\e#Bold text\e#" - bold font is used |  *                              "\e#Bold text\e#" - bold font is used | ||||||
|  *                          "\e*Monospaced text\e*" - monospaced font is used |  *                              "\e*Monospaced text\e*" - monospaced font is used | ||||||
|  *                          "\e#Inversed text\e#" - white text on black background |  *                              "\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( | void elements_text_box( | ||||||
|     Canvas* canvas, |     Canvas* canvas, | ||||||
| @ -214,7 +215,8 @@ void elements_text_box( | |||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text); |     const char* text, | ||||||
|  |     bool strip_to_dots); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -314,6 +314,7 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { | |||||||
|     view_port_gui_set(view_port, gui); |     view_port_gui_set(view_port, gui); | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| 
 | 
 | ||||||
|  |     // Request redraw
 | ||||||
|     gui_update(gui); |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -322,7 +323,6 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) { | |||||||
|     furi_assert(view_port); |     furi_assert(view_port); | ||||||
| 
 | 
 | ||||||
|     gui_lock(gui); |     gui_lock(gui); | ||||||
| 
 |  | ||||||
|     view_port_gui_set(view_port, NULL); |     view_port_gui_set(view_port, NULL); | ||||||
|     ViewPortArray_it_t it; |     ViewPortArray_it_t it; | ||||||
|     for(size_t i = 0; i < GuiLayerMAX; i++) { |     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) { |     if(gui->ongoing_input_view_port == view_port) { | ||||||
|         gui->ongoing_input_view_port = NULL; |         gui->ongoing_input_view_port = NULL; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
|  | 
 | ||||||
|  |     // Request redraw
 | ||||||
|  |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) { | 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
 |     // Return to the top
 | ||||||
|     ViewPortArray_push_back(gui->layers[layer], view_port); |     ViewPortArray_push_back(gui->layers[layer], view_port); | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
|  | 
 | ||||||
|  |     // Request redraw
 | ||||||
|  |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { | 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
 |     // Return to the top
 | ||||||
|     ViewPortArray_push_at(gui->layers[layer], 0, view_port); |     ViewPortArray_push_at(gui->layers[layer], 0, view_port); | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
|  | 
 | ||||||
|  |     // Request redraw
 | ||||||
|  |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { | 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}; |     const CanvasCallbackPair p = {callback, context}; | ||||||
| 
 | 
 | ||||||
|     gui_lock(gui); |     gui_lock(gui); | ||||||
| 
 |  | ||||||
|     furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0); |     furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0); | ||||||
|     CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p); |     CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p); | ||||||
| 
 |  | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
|  | 
 | ||||||
|  |     // Request redraw
 | ||||||
|     gui_update(gui); |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -415,10 +422,8 @@ void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, | |||||||
|     const CanvasCallbackPair p = {callback, context}; |     const CanvasCallbackPair p = {callback, context}; | ||||||
| 
 | 
 | ||||||
|     gui_lock(gui); |     gui_lock(gui); | ||||||
| 
 |  | ||||||
|     furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1); |     furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1); | ||||||
|     CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p); |     CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p); | ||||||
| 
 |  | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -429,9 +434,12 @@ size_t gui_get_framebuffer_size(Gui* gui) { | |||||||
| 
 | 
 | ||||||
| void gui_set_lockdown(Gui* gui, bool lockdown) { | void gui_set_lockdown(Gui* gui, bool lockdown) { | ||||||
|     furi_assert(gui); |     furi_assert(gui); | ||||||
|  | 
 | ||||||
|     gui_lock(gui); |     gui_lock(gui); | ||||||
|     gui->lockdown = lockdown; |     gui->lockdown = lockdown; | ||||||
|     gui_unlock(gui); |     gui_unlock(gui); | ||||||
|  | 
 | ||||||
|  |     // Request redraw
 | ||||||
|     gui_update(gui); |     gui_update(gui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								applications/gui/modules/widget.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										7
									
								
								applications/gui/modules/widget.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -154,10 +154,11 @@ void widget_add_text_box_element( | |||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text) { |     const char* text, | ||||||
|  |     bool strip_to_dots) { | ||||||
|     furi_assert(widget); |     furi_assert(widget); | ||||||
|     WidgetElement* text_box_element = |     WidgetElement* text_box_element = widget_element_text_box_create( | ||||||
|         widget_element_text_box_create(x, y, width, height, horizontal, vertical, text); |         x, y, width, height, horizontal, vertical, text, strip_to_dots); | ||||||
|     widget_add_element(widget, text_box_element); |     widget_add_element(widget, text_box_element); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -81,17 +81,18 @@ void widget_add_string_element( | |||||||
| 
 | 
 | ||||||
| /** Add Text Box Element
 | /** Add Text Box Element
 | ||||||
|  * |  * | ||||||
|  * @param      widget      Widget instance |  * @param      widget           Widget instance | ||||||
|  * @param      x           x coordinate |  * @param      x                x coordinate | ||||||
|  * @param      y           y coordinate |  * @param      y                y coordinate | ||||||
|  * @param      width       width to fit text |  * @param      width            width to fit text | ||||||
|  * @param      height      height to fit text |  * @param      height           height to fit text | ||||||
|  * @param      horizontal  Align instance |  * @param      horizontal       Align instance | ||||||
|  * @param      vertical    Align instance |  * @param      vertical         Align instance | ||||||
|  * @param[in]  text        Formatted text. The following formats are available: |  * @param[in]  text             Formatted text. The following formats are available: | ||||||
|  *                          "\e#Bold text\e#" - bold font is used |  *                               "\e#Bold text\e#" - bold font is used | ||||||
|  *                          "\e*Monospaced text\e*" - monospaced font is used |  *                               "\e*Monospaced text\e*" - monospaced font is used | ||||||
|  *                          "\e#Inversed text\e#" - white text on black background |  *                               "\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( | void widget_add_text_box_element( | ||||||
|     Widget* widget, |     Widget* widget, | ||||||
| @ -101,7 +102,8 @@ void widget_add_text_box_element( | |||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text); |     const char* text, | ||||||
|  |     bool strip_to_dots); | ||||||
| 
 | 
 | ||||||
| /** Add Button Element
 | /** Add Button Element
 | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -60,7 +60,8 @@ WidgetElement* widget_element_text_box_create( | |||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text); |     const char* text, | ||||||
|  |     bool strip_to_dots); | ||||||
| 
 | 
 | ||||||
| /** Create button element */ | /** Create button element */ | ||||||
| WidgetElement* widget_element_button_create( | WidgetElement* widget_element_button_create( | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ typedef struct { | |||||||
|     Align horizontal; |     Align horizontal; | ||||||
|     Align vertical; |     Align vertical; | ||||||
|     string_t text; |     string_t text; | ||||||
|  |     bool strip_to_dots; | ||||||
| } GuiTextBoxModel; | } GuiTextBoxModel; | ||||||
| 
 | 
 | ||||||
| static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) { | 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->height, | ||||||
|             model->horizontal, |             model->horizontal, | ||||||
|             model->vertical, |             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, |     uint8_t height, | ||||||
|     Align horizontal, |     Align horizontal, | ||||||
|     Align vertical, |     Align vertical, | ||||||
|     const char* text) { |     const char* text, | ||||||
|  |     bool strip_to_dots) { | ||||||
|     furi_assert(text); |     furi_assert(text); | ||||||
| 
 | 
 | ||||||
|     // Allocate and init model
 |     // Allocate and init model
 | ||||||
| @ -58,6 +61,7 @@ WidgetElement* widget_element_text_box_create( | |||||||
|     model->horizontal = horizontal; |     model->horizontal = horizontal; | ||||||
|     model->vertical = vertical; |     model->vertical = vertical; | ||||||
|     string_init_set_str(model->text, text); |     string_init_set_str(model->text, text); | ||||||
|  |     model->strip_to_dots = strip_to_dots; | ||||||
| 
 | 
 | ||||||
|     // Allocate and init Element
 |     // Allocate and init Element
 | ||||||
|     WidgetElement* gui_string = malloc(sizeof(WidgetElement)); |     WidgetElement* gui_string = malloc(sizeof(WidgetElement)); | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) { | |||||||
| 
 | 
 | ||||||
|     app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); |     app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); | ||||||
|     widget_add_text_box_element( |     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, GuiButtonTypeLeft, "Cancel", widget_callback, app); | ||||||
|     widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); |     widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) { | |||||||
| 
 | 
 | ||||||
|     app->set_text_store("%s", ibutton_key_get_name_p(key)); |     app->set_text_store("%s", ibutton_key_get_name_p(key)); | ||||||
|     widget_add_text_box_element( |     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)) { |     switch(ibutton_key_get_type(key)) { | ||||||
|     case iButtonKeyDS1990: |     case iButtonKeyDS1990: | ||||||
|  | |||||||
| @ -2,9 +2,9 @@ | |||||||
| #include "../ibutton_app.h" | #include "../ibutton_app.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuIndexWrite, |  | ||||||
|     SubmenuIndexEmulate, |  | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
|  |     SubmenuIndexEmulate, | ||||||
|  |     SubmenuIndexWrite, | ||||||
| } SubmenuIndex; | } SubmenuIndex; | ||||||
| 
 | 
 | ||||||
| static void submenu_callback(void* context, uint32_t index) { | 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(); |     iButtonAppViewManager* view_manager = app->get_view_manager(); | ||||||
|     Submenu* submenu = view_manager->get_submenu(); |     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) { |     if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { | ||||||
|         submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); |         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); |     submenu_set_selected_item(submenu, submenu_item_selected); | ||||||
| 
 | 
 | ||||||
|     view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); |     view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); | ||||||
|  | |||||||
| @ -14,14 +14,17 @@ int32_t InfraredApp::run(void* args) { | |||||||
|     if(args) { |     if(args) { | ||||||
|         std::string path = static_cast<const char*>(args); |         std::string path = static_cast<const char*>(args); | ||||||
|         std::string remote_name(path, path.find_last_of('/') + 1, path.size()); |         std::string remote_name(path, path.find_last_of('/') + 1, path.size()); | ||||||
|         remote_name.erase(remote_name.find_last_of('.')); |         auto last_dot = remote_name.find_last_of('.'); | ||||||
|         path.erase(path.find_last_of('/')); |         if(last_dot != std::string::npos) { | ||||||
|         bool result = remote_manager.load(path, remote_name); |             remote_name.erase(last_dot); | ||||||
|         if(result) { |             path.erase(path.find_last_of('/')); | ||||||
|             current_scene = InfraredApp::Scene::Remote; |             bool result = remote_manager.load(path, remote_name); | ||||||
|         } else { |             if(result) { | ||||||
|             printf("Failed to load remote \'%s\'\r\n", remote_name.c_str()); |                 current_scene = InfraredApp::Scene::Remote; | ||||||
|             return -1; |             } 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() { | InfraredApp::InfraredApp() { | ||||||
|     furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); |     furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); | ||||||
|     notification = static_cast<NotificationApp*>(furi_record_open("notification")); |     notification = static_cast<NotificationApp*>(furi_record_open("notification")); | ||||||
|  |     dialogs = static_cast<DialogsApp*>(furi_record_open("dialogs")); | ||||||
|     infrared_worker = infrared_worker_alloc(); |     infrared_worker = infrared_worker_alloc(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| InfraredApp::~InfraredApp() { | InfraredApp::~InfraredApp() { | ||||||
|     infrared_worker_free(infrared_worker); |     infrared_worker_free(infrared_worker); | ||||||
|     furi_record_close("notification"); |     furi_record_close("notification"); | ||||||
|  |     furi_record_close("dialogs"); | ||||||
|     for(auto& [key, scene] : scenes) delete scene; |     for(auto& [key, scene] : scenes) delete scene; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -248,6 +253,10 @@ void InfraredApp::notify_blink_green() { | |||||||
|     notification_message(notification, &sequence); |     notification_message(notification, &sequence); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | DialogsApp* InfraredApp::get_dialogs() { | ||||||
|  |     return dialogs; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void InfraredApp::notify_green_on() { | void InfraredApp::notify_green_on() { | ||||||
|     notification_message(notification, &sequence_set_only_green_255); |     notification_message(notification, &sequence_set_only_green_255); | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include <forward_list> | #include <forward_list> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
|  | #include <dialogs/dialogs.h> | ||||||
| #include <infrared_worker.h> | #include <infrared_worker.h> | ||||||
| 
 | 
 | ||||||
| #include "scene/infrared_app_scene.h" | #include "scene/infrared_app_scene.h" | ||||||
| @ -228,6 +229,9 @@ public: | |||||||
|     /** Blink green light */ |     /** Blink green light */ | ||||||
|     void notify_blink_green(); |     void notify_blink_green(); | ||||||
| 
 | 
 | ||||||
|  |     /** Get Dialogs instance */ | ||||||
|  |     DialogsApp* get_dialogs(); | ||||||
|  | 
 | ||||||
|     /** Text input callback
 |     /** Text input callback
 | ||||||
|  * |  * | ||||||
|  * @param context - context to pass to callback |  * @param context - context to pass to callback | ||||||
| @ -286,6 +290,8 @@ private: | |||||||
| 
 | 
 | ||||||
|     /** Notification instance */ |     /** Notification instance */ | ||||||
|     NotificationApp* notification; |     NotificationApp* notification; | ||||||
|  |     /** Dialogs instance */ | ||||||
|  |     DialogsApp* dialogs; | ||||||
|     /** View manager instance */ |     /** View manager instance */ | ||||||
|     InfraredAppViewManager view_manager; |     InfraredAppViewManager view_manager; | ||||||
|     /** Remote manager instance */ |     /** Remote manager instance */ | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ | |||||||
| #include <memory> | #include <memory> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <file_worker_cpp.h> |  | ||||||
| 
 | 
 | ||||||
| void InfraredAppBruteForce::add_record(int index, const char* name) { | void InfraredAppBruteForce::add_record(int index, const char* name) { | ||||||
|     records[name].index = index; |     records[name].index = index; | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| #include <file_worker_cpp.h> |  | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| #include "infrared_app_remote_manager.h" | #include "infrared_app_remote_manager.h" | ||||||
| #include "infrared/helpers/infrared_parser.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) { | std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) { | ||||||
|     bool exist = true; |     std::string result_name; | ||||||
|     FileWorkerCpp file_worker; |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
| 
 | 
 | ||||||
|     if(!file_worker.is_file_exist( |     FS_Error error = storage_common_stat( | ||||||
|            make_full_name(InfraredApp::infrared_directory, name).c_str(), &exist)) { |         storage, make_full_name(InfraredApp::infrared_directory, name).c_str(), NULL); | ||||||
|         return std::string(); | 
 | ||||||
|     } else if(!exist) { |     if(error == FSE_NOT_EXIST) { | ||||||
|         return name; |         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(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* if suggested name is occupied, try another one (name2, name3, etc) */ |     furi_record_close("storage"); | ||||||
|     uint32_t i = 1; |     return result_name; | ||||||
|     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); |  | ||||||
| 
 |  | ||||||
|     return !exist ? name + std::to_string(i) : std::string(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { | 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 InfraredAppRemoteManager::delete_remote() { | ||||||
|     bool result; |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|     FileWorkerCpp file_worker; |  | ||||||
|     result = file_worker.remove(make_full_name(remote->path, remote->name).c_str()); |  | ||||||
| 
 | 
 | ||||||
|  |     FS_Error error = | ||||||
|  |         storage_common_remove(storage, make_full_name(remote->path, remote->name).c_str()); | ||||||
|     reset_remote(); |     reset_remote(); | ||||||
|     return result; | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     return (error == FSE_OK || error == FSE_NOT_EXIST); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void InfraredAppRemoteManager::reset_remote() { | void InfraredAppRemoteManager::reset_remote() { | ||||||
| @ -129,14 +138,15 @@ bool InfraredAppRemoteManager::rename_remote(const char* str) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FileWorkerCpp file_worker; |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|  | 
 | ||||||
|     std::string old_filename = make_full_name(remote->path, remote->name); |     std::string old_filename = make_full_name(remote->path, remote->name); | ||||||
|     std::string new_filename = make_full_name(remote->path, new_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; |     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) { | 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 InfraredAppRemoteManager::store(void) { | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     FileWorkerCpp file_worker; |  | ||||||
| 
 |  | ||||||
|     if(!file_worker.mkdir(InfraredApp::infrared_directory)) return false; |  | ||||||
| 
 |  | ||||||
|     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); |     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||||
|  | 
 | ||||||
|  |     if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false; | ||||||
|  | 
 | ||||||
|     FlipperFormat* ff = flipper_format_file_alloc(storage); |     FlipperFormat* ff = flipper_format_file_alloc(storage); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I( |     FURI_LOG_I( | ||||||
|  | |||||||
| @ -23,9 +23,9 @@ void InfraredAppSceneEdit::on_enter(InfraredApp* app) { | |||||||
|     InfraredAppViewManager* view_manager = app->get_view_manager(); |     InfraredAppViewManager* view_manager = app->get_view_manager(); | ||||||
|     Submenu* submenu = view_manager->get_submenu(); |     Submenu* submenu = view_manager->get_submenu(); | ||||||
| 
 | 
 | ||||||
|     submenu_add_item(submenu, "Add Key", SubmenuIndexAddKey, submenu_callback, app); |     submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app); | ||||||
|     submenu_add_item(submenu, "Rename Key", SubmenuIndexRenameKey, submenu_callback, app); |     submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app); | ||||||
|     submenu_add_item(submenu, "Delete Key", SubmenuIndexDeleteKey, 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, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app); | ||||||
|     submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); |     submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); | ||||||
|     submenu_set_selected_item(submenu, submenu_item_selected); |     submenu_set_selected_item(submenu, submenu_item_selected); | ||||||
|  | |||||||
| @ -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_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); | ||||||
|     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); |     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_right_button_text(dialog_ex, "Delete"); | ||||||
|     dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); |     dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); | ||||||
|     dialog_ex_set_context(dialog_ex, app); |     dialog_ex_set_context(dialog_ex, app); | ||||||
|  | |||||||
| @ -16,8 +16,9 @@ void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) { | |||||||
|     Submenu* submenu = view_manager->get_submenu(); |     Submenu* submenu = view_manager->get_submenu(); | ||||||
|     int item_number = 0; |     int item_number = 0; | ||||||
| 
 | 
 | ||||||
|     const char* header = |     const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ? | ||||||
|         app->get_edit_action() == InfraredApp::EditAction::Rename ? "Rename key:" : "Delete key:"; |                              "Rename Button:" : | ||||||
|  |                              "Delete Button:"; | ||||||
|     submenu_set_header(submenu, header); |     submenu_set_header(submenu, header); | ||||||
| 
 | 
 | ||||||
|     auto remote_manager = app->get_remote_manager(); |     auto remote_manager = app->get_remote_manager(); | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ void InfraredAppSceneEditRename::on_enter(InfraredApp* app) { | |||||||
|         strncpy(buffer_str, button_name.c_str(), max_len); |         strncpy(buffer_str, button_name.c_str(), max_len); | ||||||
|         buffer_str[max_len + 1] = 0; |         buffer_str[max_len + 1] = 0; | ||||||
|         enter_name_length = max_len; |         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 { |     } else { | ||||||
|         auto remote_name = remote_manager->get_remote_name(); |         auto remote_name = remote_manager->get_remote_name(); | ||||||
|         strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); |         strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) { | |||||||
|         app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); |         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_set_result_callback( | ||||||
|         text_input, |         text_input, | ||||||
|         InfraredApp::text_input_callback, |         InfraredApp::text_input_callback, | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| #include <gui/modules/dialog_ex.h> | #include <gui/modules/dialog_ex.h> | ||||||
| #include <file_worker_cpp.h> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| @ -88,13 +87,8 @@ bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent* | |||||||
|             break; |             break; | ||||||
|         case DialogExResultRight: { |         case DialogExResultRight: { | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             FileWorkerCpp file_worker; |  | ||||||
|             if(!button_pressed) { |             if(!button_pressed) { | ||||||
|                 if(file_worker.check_errors()) { |                 app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); | ||||||
|                     app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); |  | ||||||
|                 } else { |  | ||||||
|                     app->switch_to_previous_scene(); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,12 +1,10 @@ | |||||||
| #include "../infrared_app.h" | #include "../infrared_app.h" | ||||||
| #include "infrared/infrared_app_event.h" | #include "infrared/infrared_app_event.h" | ||||||
| #include <text_store.h> | #include <text_store.h> | ||||||
| #include <file_worker_cpp.h> |  | ||||||
| 
 | 
 | ||||||
| void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { | void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { | ||||||
|     furi_assert(app); |     furi_assert(app); | ||||||
| 
 | 
 | ||||||
|     FileWorkerCpp file_worker; |  | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     bool file_select_result; |     bool file_select_result; | ||||||
|     auto remote_manager = app->get_remote_manager(); |     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; |         last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; | ||||||
|     auto filename_ts = |     auto filename_ts = | ||||||
|         std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length); |         std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length); | ||||||
|  |     DialogsApp* dialogs = app->get_dialogs(); | ||||||
| 
 | 
 | ||||||
|     InfraredAppViewManager* view_manager = app->get_view_manager(); |     InfraredAppViewManager* view_manager = app->get_view_manager(); | ||||||
|     ButtonMenu* button_menu = view_manager->get_button_menu(); |     ButtonMenu* button_menu = view_manager->get_button_menu(); | ||||||
|     button_menu_reset(button_menu); |     button_menu_reset(button_menu); | ||||||
|     view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); |     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_directory, | ||||||
|         InfraredApp::infrared_extension, |         InfraredApp::infrared_extension, | ||||||
|         filename_ts->text, |         filename_ts->text, | ||||||
|  | |||||||
| @ -24,19 +24,15 @@ static void input_cli_dump(Cli* cli, string_t args, Input* input) { | |||||||
|     FuriPubSubSubscription* input_subscription = |     FuriPubSubSubscription* input_subscription = | ||||||
|         furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue); |         furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue); | ||||||
| 
 | 
 | ||||||
|     bool stop = false; |  | ||||||
|     InputEvent input_event; |     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) { |         if(osMessageQueueGet(input_queue, &input_event, NULL, 100) == osOK) { | ||||||
|             printf( |             printf( | ||||||
|                 "key: %s type: %s\r\n", |                 "key: %s type: %s\r\n", | ||||||
|                 input_get_key_name(input_event.key), |                 input_get_key_name(input_event.key), | ||||||
|                 input_get_type_name(input_event.type)); |                 input_get_type_name(input_event.type)); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         if(cli_cmd_interrupt_received(cli)) { |  | ||||||
|             stop = true; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     furi_pubsub_unsubscribe(input->event_pubsub, input_subscription); |     furi_pubsub_unsubscribe(input->event_pubsub, input_subscription); | ||||||
|  | |||||||
| @ -1,17 +1,17 @@ | |||||||
| #include "lfrfid_app_scene_read_menu.h" | #include "lfrfid_app_scene_read_menu.h" | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubmenuWrite, |  | ||||||
|     SubmenuSave, |     SubmenuSave, | ||||||
|     SubmenuEmulate, |     SubmenuEmulate, | ||||||
|  |     SubmenuWrite, | ||||||
| } SubmenuIndex; | } SubmenuIndex; | ||||||
| 
 | 
 | ||||||
| void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { | void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { | ||||||
|     auto submenu = app->view_controller.get<SubmenuVM>(); |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
| 
 | 
 | ||||||
|     submenu->add_item("Write", SubmenuWrite, submenu_callback, app); |  | ||||||
|     submenu->add_item("Save", SubmenuSave, submenu_callback, app); |     submenu->add_item("Save", SubmenuSave, submenu_callback, app); | ||||||
|     submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); |     submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); | ||||||
|  |     submenu->add_item("Write", SubmenuWrite, submenu_callback, app); | ||||||
| 
 | 
 | ||||||
|     if(need_restore) { |     if(need_restore) { | ||||||
|         submenu->set_selected_item(submenu_item_selected); |         submenu->set_selected_item(submenu_item_selected); | ||||||
|  | |||||||
| @ -92,7 +92,7 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { | |||||||
|         application = loader_find_application_by_name_in_list( |         application = loader_find_application_by_name_in_list( | ||||||
|             name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT); |             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( |         application = loader_find_application_by_name_in_list( | ||||||
|             name, FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT); |             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; |         event.type = LoaderEventTypeApplicationStarted; | ||||||
|         furi_pubsub_publish(loader_instance->pubsub, &event); |         furi_pubsub_publish(loader_instance->pubsub, &event); | ||||||
|         furi_hal_power_insomnia_enter(); |         furi_hal_power_insomnia_enter(); | ||||||
| 
 |  | ||||||
|         // Snapshot current memory usage
 |  | ||||||
|         instance->free_heap_size = memmgr_get_free_heap(); |  | ||||||
|     } else if(thread_state == FuriThreadStateStopped) { |     } 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( |         FURI_LOG_I( | ||||||
|             TAG, |             TAG, | ||||||
|             "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", |             "Application thread stopped. Free heap: %d. Thread allocation balance: %d.", | ||||||
|             heap_diff, |             memmgr_get_free_heap(), | ||||||
|             furi_thread_get_heap_size(instance->application_thread)); |             furi_thread_get_heap_size(instance->application_thread)); | ||||||
| 
 | 
 | ||||||
|         if(loader_instance->application_arguments) { |         if(loader_instance->application_arguments) { | ||||||
| @ -455,18 +440,17 @@ void loader_update_menu() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t loader_srv(void* p) { | 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_instance = loader_alloc(); | ||||||
| 
 | 
 | ||||||
|     loader_build_menu(); |     loader_build_menu(); | ||||||
|     loader_build_submenu(); |     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_LOG_I(TAG, "Started"); | ||||||
| 
 | 
 | ||||||
|     furi_record_create("loader", loader_instance); |     furi_record_create("loader", loader_instance); | ||||||
|  | |||||||
| @ -30,7 +30,6 @@ struct Loader { | |||||||
|     Submenu* debug_menu; |     Submenu* debug_menu; | ||||||
|     Submenu* settings_menu; |     Submenu* settings_menu; | ||||||
| 
 | 
 | ||||||
|     size_t free_heap_size; |  | ||||||
|     volatile uint8_t lock_count; |     volatile uint8_t lock_count; | ||||||
| 
 | 
 | ||||||
|     FuriPubSub* pubsub; |     FuriPubSub* pubsub; | ||||||
|  | |||||||
| @ -3,19 +3,19 @@ | |||||||
| 
 | 
 | ||||||
| bool nfc_custom_event_callback(void* context, uint32_t event) { | bool nfc_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     return scene_manager_handle_custom_event(nfc->scene_manager, event); |     return scene_manager_handle_custom_event(nfc->scene_manager, event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_back_event_callback(void* context) { | bool nfc_back_event_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     return scene_manager_handle_back_event(nfc->scene_manager); |     return scene_manager_handle_back_event(nfc->scene_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_tick_event_callback(void* context) { | void nfc_tick_event_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     scene_manager_handle_tick_event(nfc->scene_manager); |     scene_manager_handle_tick_event(nfc->scene_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -169,11 +169,16 @@ int32_t nfc_app(void* p) { | |||||||
|     char* args = p; |     char* args = p; | ||||||
| 
 | 
 | ||||||
|     // Check argument and run corresponding scene
 |     // Check argument and run corresponding scene
 | ||||||
|     if((*args != '\0') && nfc_device_load(nfc->dev, p)) { |     if((*args != '\0')) { | ||||||
|         if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |         if(nfc_device_load(nfc->dev, p)) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); |             if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|  |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); | ||||||
|  |             } else { | ||||||
|  |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||||
|  |             } | ||||||
|         } else { |         } else { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |             // Exit app
 | ||||||
|  |             view_dispatcher_stop(nfc->view_dispatcher); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); | ||||||
|  | |||||||
| @ -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
 |     // Check if nfc worker is not busy
 | ||||||
|     if(furi_hal_nfc_is_busy()) { |     if(furi_hal_nfc_is_busy()) { | ||||||
|         printf("Nfc is busy\r\n"); |         printf("Nfc is busy\r\n"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     rfalNfcDevice* dev_list; | 
 | ||||||
|     uint8_t dev_cnt = 0; |     FuriHalNfcDevData dev_data = {}; | ||||||
|     bool cmd_exit = false; |     bool cmd_exit = false; | ||||||
|     furi_hal_nfc_exit_sleep(); |     furi_hal_nfc_exit_sleep(); | ||||||
|     printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); |     printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); | ||||||
|     while(!cmd_exit) { |     while(!cmd_exit) { | ||||||
|         cmd_exit |= cli_cmd_interrupt_received(cli); |         cmd_exit |= cli_cmd_interrupt_received(cli); | ||||||
|         cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true); |         if(furi_hal_nfc_detect(&dev_data, 400)) { | ||||||
|         if(dev_cnt > 0) { |             printf("found: %s ", nfc_get_dev_type(dev_data.type)); | ||||||
|             printf("Found %d devices\r\n", dev_cnt); |             printf("UID length: %d, UID:", dev_data.uid_len); | ||||||
|             for(uint8_t i = 0; i < dev_cnt; i++) { |             for(size_t i = 0; i < dev_data.uid_len; i++) { | ||||||
|                 printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type)); |                 printf("%02X", dev_data.uid[i]); | ||||||
|                 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"); |  | ||||||
|             } |             } | ||||||
|  |             printf("\r\n"); | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|  |         furi_hal_nfc_sleep(); | ||||||
|         osDelay(50); |         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
 |     // Check if nfc worker is not busy
 | ||||||
|     if(furi_hal_nfc_is_busy()) { |     if(furi_hal_nfc_is_busy()) { | ||||||
|         printf("Nfc is busy\r\n"); |         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("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"); |     printf("Press Ctrl+C to abort\r\n"); | ||||||
| 
 | 
 | ||||||
|     NfcDeviceCommonData params = { |     FuriHalNfcDevData params = { | ||||||
|         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, |         .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, | ||||||
|         .uid_len = 7, |         .uid_len = 7, | ||||||
|         .atqa = {0x44, 0x00}, |         .atqa = {0x44, 0x00}, | ||||||
|         .sak = 0x00, |         .sak = 0x00, | ||||||
|         .device = NfcDeviceNfca, |         .type = FuriHalNfcTypeA, | ||||||
|         .protocol = NfcDeviceProtocolMifareUl, |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     while(!cli_cmd_interrupt_received(cli)) { |     while(!cli_cmd_interrupt_received(cli)) { | ||||||
|         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { |         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { | ||||||
|             printf("Reader detected\r\n"); |             printf("Reader detected\r\n"); | ||||||
|             furi_hal_nfc_deactivate(); |             furi_hal_nfc_sleep(); | ||||||
|         } |         } | ||||||
|         osDelay(50); |         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
 |     // Check if nfc worker is not busy
 | ||||||
|     if(furi_hal_nfc_is_busy()) { |     if(furi_hal_nfc_is_busy()) { | ||||||
|         printf("Nfc is busy\r\n"); |         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_field_off(); | ||||||
|     furi_hal_nfc_deactivate(); |     furi_hal_nfc_sleep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void nfc_cli(Cli* cli, string_t args, void* context) { | static void nfc_cli(Cli* cli, string_t args, void* context) { | ||||||
|  | |||||||
| @ -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) { | static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||||
|     if(string_start_with_str_p(format_string, "UID")) { |     if(string_start_with_str_p(format_string, "UID")) { | ||||||
|         dev->format = NfcDeviceSaveFormatUid; |         dev->format = NfcDeviceSaveFormatUid; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; |         dev->dev_data.protocol = NfcDeviceProtocolUnknown; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     if(string_start_with_str_p(format_string, "Bank card")) { |     if(string_start_with_str_p(format_string, "Bank card")) { | ||||||
|         dev->format = NfcDeviceSaveFormatBankCard; |         dev->format = NfcDeviceSaveFormatBankCard; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; |         dev->dev_data.protocol = NfcDeviceProtocolEMV; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     // Check Mifare Ultralight types
 |     // Check Mifare Ultralight types
 | ||||||
|     for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { |     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->format = NfcDeviceSaveFormatMifareUl; | ||||||
|             dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; |             dev->dev_data.protocol = NfcDeviceProtocolMifareUl; | ||||||
|             dev->dev_data.mf_ul_data.type = type; |             dev->dev_data.mf_ul_data.type = type; | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if(string_start_with_str_p(format_string, "Mifare Classic")) { |     if(string_start_with_str_p(format_string, "Mifare Classic")) { | ||||||
|         dev->format = NfcDeviceSaveFormatMifareClassic; |         dev->format = NfcDeviceSaveFormatMifareClassic; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic; |         dev->dev_data.protocol = NfcDeviceProtocolMifareClassic; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     if(string_start_with_str_p(format_string, "Mifare DESFire")) { |     if(string_start_with_str_p(format_string, "Mifare DESFire")) { | ||||||
|         dev->format = NfcDeviceSaveFormatMifareDesfire; |         dev->format = NfcDeviceSaveFormatMifareDesfire; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire; |         dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     return false; |     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) { | static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { | ||||||
|     bool saved = false; |     bool saved = false; | ||||||
|     MifareUlData* data = &dev->dev_data.mf_ul_data; |     MfUltralightData* data = &dev->dev_data.mf_ul_data; | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(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 nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     MifareUlData* data = &dev->dev_data.mf_ul_data; |     MfUltralightData* data = &dev->dev_data.mf_ul_data; | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(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) { | static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { | ||||||
|     bool saved = false; |     bool saved = false; | ||||||
|     NfcEmvData* data = &dev->dev_data.emv_data; |     EmvData* data = &dev->dev_data.emv_data; | ||||||
|     uint32_t data_temp = 0; |     uint32_t data_temp = 0; | ||||||
| 
 | 
 | ||||||
|     do { |     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 nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     NfcEmvData* data = &dev->dev_data.emv_data; |     EmvData* data = &dev->dev_data.emv_data; | ||||||
|     memset(data, 0, sizeof(NfcEmvData)); |     memset(data, 0, sizeof(EmvData)); | ||||||
|     uint32_t data_cnt = 0; |     uint32_t data_cnt = 0; | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
| @ -700,7 +700,7 @@ static bool nfc_device_save_file( | |||||||
| 
 | 
 | ||||||
|     bool saved = false; |     bool saved = false; | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(dev->storage); |     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_t temp_str; | ||||||
|     string_init(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) { | static bool nfc_device_load_data(NfcDevice* dev, string_t path) { | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(dev->storage); |     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; |     uint32_t data_cnt = 0; | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(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; |         if(!nfc_device_parse_format_string(dev, temp_str)) break; | ||||||
|         // Read and parse UID, ATQA and SAK
 |         // Read and parse UID, ATQA and SAK
 | ||||||
|         if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; |         if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; | ||||||
|  |         if(!(data_cnt == 4 || data_cnt == 7)) break; | ||||||
|         data->uid_len = data_cnt; |         data->uid_len = data_cnt; | ||||||
|         if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; |         if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; | ||||||
|         if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) 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) { | 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); |         mf_df_clear(&dev_data->mf_df_data); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <dialogs/dialogs.h> | #include <dialogs/dialogs.h> | ||||||
| 
 | 
 | ||||||
|  | #include <furi_hal_nfc.h> | ||||||
|  | #include <lib/nfc_protocols/emv.h> | ||||||
| #include <lib/nfc_protocols/mifare_ultralight.h> | #include <lib/nfc_protocols/mifare_ultralight.h> | ||||||
| #include <lib/nfc_protocols/mifare_classic.h> | #include <lib/nfc_protocols/mifare_classic.h> | ||||||
| #include <lib/nfc_protocols/mifare_desfire.h> | #include <lib/nfc_protocols/mifare_desfire.h> | ||||||
| @ -17,13 +19,6 @@ | |||||||
| #define NFC_APP_EXTENSION ".nfc" | #define NFC_APP_EXTENSION ".nfc" | ||||||
| #define NFC_APP_SHADOW_EXTENSION ".shd" | #define NFC_APP_SHADOW_EXTENSION ".shd" | ||||||
| 
 | 
 | ||||||
| typedef enum { |  | ||||||
|     NfcDeviceNfca, |  | ||||||
|     NfcDeviceNfcb, |  | ||||||
|     NfcDeviceNfcf, |  | ||||||
|     NfcDeviceNfcv, |  | ||||||
| } NfcDeviceType; |  | ||||||
| 
 |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     NfcDeviceProtocolUnknown, |     NfcDeviceProtocolUnknown, | ||||||
|     NfcDeviceProtocolEMV, |     NfcDeviceProtocolEMV, | ||||||
| @ -40,38 +35,18 @@ typedef enum { | |||||||
|     NfcDeviceSaveFormatMifareDesfire, |     NfcDeviceSaveFormatMifareDesfire, | ||||||
| } NfcDeviceSaveFormat; | } 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 { | typedef struct { | ||||||
|     uint8_t data[NFC_READER_DATA_MAX_SIZE]; |     uint8_t data[NFC_READER_DATA_MAX_SIZE]; | ||||||
|     uint16_t size; |     uint16_t size; | ||||||
| } NfcReaderRequestData; | } NfcReaderRequestData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     NfcDeviceCommonData nfc_data; |     FuriHalNfcDevData nfc_data; | ||||||
|  |     NfcProtocol protocol; | ||||||
|     NfcReaderRequestData reader_data; |     NfcReaderRequestData reader_data; | ||||||
|     union { |     union { | ||||||
|         NfcEmvData emv_data; |         EmvData emv_data; | ||||||
|         MifareUlData mf_ul_data; |         MfUltralightData mf_ul_data; | ||||||
|         MfClassicData mf_classic_data; |         MfClassicData mf_classic_data; | ||||||
|         MifareDesfireData mf_df_data; |         MifareDesfireData mf_df_data; | ||||||
|     }; |     }; | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ struct Nfc { | |||||||
|     NotificationApp* notifications; |     NotificationApp* notifications; | ||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     NfcDevice* dev; |     NfcDevice* dev; | ||||||
|     NfcDeviceCommonData dev_edit_data; |     FuriHalNfcDevData dev_edit_data; | ||||||
| 
 | 
 | ||||||
|     char text_store[NFC_TEXT_STORE_SIZE + 1]; |     char text_store[NFC_TEXT_STORE_SIZE + 1]; | ||||||
|     string_t text_box_store; |     string_t text_box_store; | ||||||
|  | |||||||
| @ -1,48 +1,14 @@ | |||||||
| #include "nfc_types.h" | #include "nfc_types.h" | ||||||
| 
 | 
 | ||||||
| const char* nfc_get_rfal_type(rfalNfcDevType type) { | const char* nfc_get_dev_type(FuriHalNfcType type) { | ||||||
|     if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { |     if(type == FuriHalNfcTypeA) { | ||||||
|         return "NFC-A"; |         return "NFC-A"; | ||||||
|     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) { |     } else if(type == FuriHalNfcTypeB) { | ||||||
|         return "NFC-B"; |         return "NFC-B"; | ||||||
|     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) { |     } else if(type == FuriHalNfcTypeF) { | ||||||
|         return "NFC-F"; |         return "NFC-F"; | ||||||
|     } else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) { |     } else if(type == FuriHalNfcTypeV) { | ||||||
|         return "NFC-V"; |         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 { |     } else { | ||||||
|         return "Unknown"; |         return "Unknown"; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,16 +1,8 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "st_errno.h" | #include "nfc_device.h" | ||||||
| #include "rfal_nfc.h" |  | ||||||
| 
 | 
 | ||||||
| #include <gui/view_dispatcher.h> | const char* nfc_get_dev_type(FuriHalNfcType type); | ||||||
| #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_guess_protocol(NfcProtocol protocol); | const char* nfc_guess_protocol(NfcProtocol protocol); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,8 @@ | |||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| #include <lib/nfc_protocols/nfc_util.h> | #include <lib/nfc_protocols/nfc_util.h> | ||||||
| #include <lib/nfc_protocols/emv_decoder.h> | #include <lib/nfc_protocols/emv.h> | ||||||
|  | #include <lib/nfc_protocols/mifare_common.h> | ||||||
| #include <lib/nfc_protocols/mifare_ultralight.h> | #include <lib/nfc_protocols/mifare_ultralight.h> | ||||||
| #include <lib/nfc_protocols/mifare_classic.h> | #include <lib/nfc_protocols/mifare_classic.h> | ||||||
| #include <lib/nfc_protocols/mifare_desfire.h> | #include <lib/nfc_protocols/mifare_desfire.h> | ||||||
| @ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) { | |||||||
|         nfc_worker_emulate(nfc_worker); |         nfc_worker_emulate(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { |     } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { | ||||||
|         nfc_worker_read_emv_app(nfc_worker); |         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); |         nfc_worker_read_emv(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { |     } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { | ||||||
|         nfc_worker_emulate_apdu(nfc_worker); |         nfc_worker_emulate_apdu(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMifareUl) { |     } else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) { | ||||||
|         nfc_worker_read_mifare_ul(nfc_worker); |         nfc_worker_read_mifare_ultralight(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { |     } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { | ||||||
|         nfc_worker_emulate_mifare_ul(nfc_worker); |         nfc_worker_emulate_mifare_ul(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { |     } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||||
|         nfc_worker_mifare_classic_dict_attack(nfc_worker); |         nfc_worker_mifare_classic_dict_attack(nfc_worker); | ||||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { |     } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { | ||||||
|         nfc_worker_read_mifare_desfire(nfc_worker); |         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); |     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); | ||||||
|     furi_hal_power_insomnia_exit(); |     furi_hal_power_insomnia_exit(); | ||||||
| 
 | 
 | ||||||
| @ -117,579 +116,225 @@ int32_t nfc_worker_task(void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_detect(NfcWorker* nfc_worker) { | void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     rfalNfcDevice* dev; |  | ||||||
|     uint8_t dev_cnt; |  | ||||||
|     nfc_device_data_clear(nfc_worker->dev_data); |     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) { |     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
 |             // Process first found device
 | ||||||
|             dev = &dev_list[0]; |             if(nfc_data->type == FuriHalNfcTypeA) { | ||||||
|             result->uid_len = dev->nfcidLen; |                 if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { | ||||||
|             memcpy(result->uid, dev->nfcid, dev->nfcidLen); |                     dev_data->protocol = NfcDeviceProtocolMifareUl; | ||||||
|             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; |  | ||||||
|                 } else if(mf_classic_check_card_type( |                 } else if(mf_classic_check_card_type( | ||||||
|                               dev->dev.nfca.sensRes.anticollisionInfo, |                               nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { | ||||||
|                               dev->dev.nfca.sensRes.platformInfo, |                     dev_data->protocol = NfcDeviceProtocolMifareClassic; | ||||||
|                               dev->dev.nfca.selRes.sak)) { |  | ||||||
|                     result->protocol = NfcDeviceProtocolMifareClassic; |  | ||||||
|                 } else if(mf_df_check_card_type( |                 } else if(mf_df_check_card_type( | ||||||
|                               dev->dev.nfca.sensRes.anticollisionInfo, |                               nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { | ||||||
|                               dev->dev.nfca.sensRes.platformInfo, |                     dev_data->protocol = NfcDeviceProtocolMifareDesfire; | ||||||
|                               dev->dev.nfca.selRes.sak)) { |                 } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { | ||||||
|                     result->protocol = NfcDeviceProtocolMifareDesfire; |                     dev_data->protocol = NfcDeviceProtocolEMV; | ||||||
|                 } else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) { |  | ||||||
|                     result->protocol = NfcDeviceProtocolEMV; |  | ||||||
|                 } else { |                 } 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
 |             // Notify caller and exit
 | ||||||
|             if(nfc_worker->callback) { |             if(nfc_worker->callback) { | ||||||
|                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); |                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         furi_hal_nfc_sleep(); | ||||||
|         osDelay(100); |         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; |  | ||||||
|     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) { | void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||||
|     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; |     FuriHalNfcTxRxContext tx_rx = {}; | ||||||
|  |     FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; | ||||||
|  |     NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; | ||||||
|  | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { |     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|         furi_hal_nfc_emulate_nfca( |         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) { | ||||||
|             data->uid, |             if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { | ||||||
|             data->uid_len, |                 reader_data->size = tx_rx.rx_bits / 8; | ||||||
|             data->atqa, |                 if(reader_data->size > 0) { | ||||||
|             data->sak, |                     memcpy(reader_data->data, tx_rx.rx_data, reader_data->size); | ||||||
|             nfc_worker_emulate_uid_callback, |                     if(nfc_worker->callback) { | ||||||
|             nfc_worker, |                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||||
|             1000); |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 FURI_LOG_E(TAG, "Failed to get reader commands"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     FuriHalNfcTxRxContext tx_rx = {}; | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     EmvApplication emv_app = {}; |     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; |     NfcDeviceData* result = nfc_worker->dev_data; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||||
|     nfc_device_data_clear(result); |     nfc_device_data_clear(result); | ||||||
| 
 | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadEMVApp) { |     while(nfc_worker->state == NfcWorkerStateReadEMVApp) { | ||||||
|         memset(&emv_app, 0, sizeof(emv_app)); |         if(furi_hal_nfc_detect(nfc_data, 1000)) { | ||||||
|         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { |  | ||||||
|             // Card was found. Check that it supports EMV
 |             // Card was found. Check that it supports EMV
 | ||||||
|             if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { |             if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { | ||||||
|                 result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; |                 result->protocol = NfcDeviceProtocolEMV; | ||||||
|                 result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; |                 if(emv_search_application(&tx_rx, &emv_app)) { | ||||||
|                 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"); |  | ||||||
|                     // Notify caller and exit
 |                     // Notify caller and exit
 | ||||||
|                     result->emv_data.aid_len = emv_app.aid_len; |                     result->emv_data.aid_len = emv_app.aid_len; | ||||||
|                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); |                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); | ||||||
|                     if(nfc_worker->callback) { |                     if(nfc_worker->callback) { | ||||||
|                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); |                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||||
|                     } |                     } | ||||||
|                     break; |  | ||||||
|                 } else { |  | ||||||
|                     FURI_LOG_D(TAG, "Can't find pay application"); |  | ||||||
|                     furi_hal_nfc_deactivate(); |  | ||||||
|                     continue; |  | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // Can't find EMV card
 |  | ||||||
|                 FURI_LOG_W(TAG, "Card doesn't support EMV"); |                 FURI_LOG_W(TAG, "Card doesn't support EMV"); | ||||||
|                 furi_hal_nfc_deactivate(); |  | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             // Can't find EMV card
 |  | ||||||
|             FURI_LOG_D(TAG, "Can't find any cards"); |             FURI_LOG_D(TAG, "Can't find any cards"); | ||||||
|             furi_hal_nfc_deactivate(); |  | ||||||
|         } |         } | ||||||
|  |         furi_hal_nfc_sleep(); | ||||||
|         osDelay(20); |         osDelay(20); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_read_emv(NfcWorker* nfc_worker) { | void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     FuriHalNfcTxRxContext tx_rx = {}; | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     EmvApplication emv_app = {}; |     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; |     NfcDeviceData* result = nfc_worker->dev_data; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||||
|     nfc_device_data_clear(result); |     nfc_device_data_clear(result); | ||||||
| 
 | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadEMV) { |     while(nfc_worker->state == NfcWorkerStateReadEMVData) { | ||||||
|         memset(&emv_app, 0, sizeof(emv_app)); |         if(furi_hal_nfc_detect(nfc_data, 1000)) { | ||||||
|         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { |  | ||||||
|             // Card was found. Check that it supports EMV
 |             // Card was found. Check that it supports EMV
 | ||||||
|             if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { |             if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { | ||||||
|                 result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; |                 result->protocol = NfcDeviceProtocolEMV; | ||||||
|                 result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; |                 if(emv_read_bank_card(&tx_rx, &emv_app)) { | ||||||
|                 result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; |                     result->emv_data.number_len = emv_app.card_number_len; | ||||||
|                 result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; |                     memcpy( | ||||||
|                 memcpy( |                         result->emv_data.number, emv_app.card_number, result->emv_data.number_len); | ||||||
|                     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"); |  | ||||||
|                     result->emv_data.aid_len = emv_app.aid_len; |                     result->emv_data.aid_len = emv_app.aid_len; | ||||||
|                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); |                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); | ||||||
|                 } else { |                     if(emv_app.name_found) { | ||||||
|                     FURI_LOG_D(TAG, "Can't find pay application"); |                         memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); | ||||||
|                     furi_hal_nfc_deactivate(); |                     } | ||||||
|                     continue; |                     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; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_D(TAG, "Starting application ..."); |             } else { | ||||||
|                 tx_len = emv_prepare_select_app(tx_buff, &emv_app); |                 FURI_LOG_W(TAG, "Card doesn't support EMV"); | ||||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |             } | ||||||
|                 if(err != ERR_NONE) { |         } else { | ||||||
|                     FURI_LOG_D(TAG, "Error during application selection request: %d", err); |             FURI_LOG_D(TAG, "Can't find any cards"); | ||||||
|                     furi_hal_nfc_deactivate(); |         } | ||||||
|                     continue; |         furi_hal_nfc_sleep(); | ||||||
|                 } |         osDelay(20); | ||||||
|                 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)); | void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | ||||||
|                 } else if(emv_app.pdol.size > 0) { |     FuriHalNfcTxRxContext tx_rx = {}; | ||||||
|                     FURI_LOG_D(TAG, "Can't find card name, but PDOL is present."); |     FuriHalNfcDevData params = { | ||||||
|                 } else { |         .uid = {0xCF, 0x72, 0xd4, 0x40}, | ||||||
|                     FURI_LOG_D(TAG, "Can't find card name or PDOL"); |         .uid_len = 4, | ||||||
|                     furi_hal_nfc_deactivate(); |         .atqa = {0x00, 0x04}, | ||||||
|                     continue; |         .sak = 0x20, | ||||||
|                 } |         .type = FuriHalNfcTypeA, | ||||||
|                 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); |     while(nfc_worker->state == NfcWorkerStateEmulateApdu) { | ||||||
|                 if(err != ERR_NONE) { |         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { | ||||||
|                     FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err); |             FURI_LOG_D(TAG, "POS terminal detected"); | ||||||
|                     furi_hal_nfc_deactivate(); |             if(emv_card_emulation(&tx_rx)) { | ||||||
|                     continue; |                 FURI_LOG_D(TAG, "EMV card emulated"); | ||||||
|                 } |             } | ||||||
|                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { |         } else { | ||||||
|                     FURI_LOG_D(TAG, "Card number parsed"); |             FURI_LOG_D(TAG, "Can't find reader"); | ||||||
|                     result->emv_data.number_len = emv_app.card_number_len; |         } | ||||||
|                     memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); |         furi_hal_nfc_sleep(); | ||||||
|  |         osDelay(20); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { | ||||||
|  |     FuriHalNfcTxRxContext tx_rx = {}; | ||||||
|  |     MfUltralightReader reader = {}; | ||||||
|  |     MfUltralightData data = {}; | ||||||
|  |     NfcDeviceData* result = nfc_worker->dev_data; | ||||||
|  |     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
 |                     // Notify caller and exit
 | ||||||
|                     if(nfc_worker->callback) { |                     if(nfc_worker->callback) { | ||||||
|                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); |                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|                 } else { |                 } else { | ||||||
|                     // Mastercard doesn't give PAN / card number as GPO response
 |                     FURI_LOG_D(TAG, "Failed reading Mifare Ultralight"); | ||||||
|                     // 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 { |             } else { | ||||||
|                 // Can't find EMV card
 |                 FURI_LOG_W(TAG, "Tag is not Mifare Ultralight"); | ||||||
|                 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(); |  | ||||||
|         } |  | ||||||
|         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 = { |  | ||||||
|         .uid = {0xCF, 0x72, 0xd4, 0x40}, |  | ||||||
|         .uid_len = 4, |  | ||||||
|         .atqa = {0x00, 0x04}, |  | ||||||
|         .sak = 0x20, |  | ||||||
|         .device = NfcDeviceNfca, |  | ||||||
|         .protocol = NfcDeviceProtocolEMV, |  | ||||||
|     }; |  | ||||||
|     // 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; |  | ||||||
|             } |  | ||||||
|             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"); |  | ||||||
|         } |  | ||||||
|         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; |  | ||||||
|     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); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } 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); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 // 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"); |  | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_D(TAG, "Can't find any tags"); |             FURI_LOG_D(TAG, "Can't find any tags"); | ||||||
|         } |         } | ||||||
|  |         furi_hal_nfc_sleep(); | ||||||
|         osDelay(100); |         osDelay(100); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||||
|     NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data; |     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||||
|     MifareUlDevice mf_ul_emulate; |     MfUltralightEmulator emulator = {}; | ||||||
|     mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data); |     mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { |     while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { | ||||||
|         furi_hal_nfc_emulate_nfca( |         furi_hal_nfc_emulate_nfca( | ||||||
|             nfc_common->uid, |             nfc_data->uid, | ||||||
|             nfc_common->uid_len, |             nfc_data->uid_len, | ||||||
|             nfc_common->atqa, |             nfc_data->atqa, | ||||||
|             nfc_common->sak, |             nfc_data->sak, | ||||||
|             mf_ul_prepare_emulation_response, |             mf_ul_prepare_emulation_response, | ||||||
|             &mf_ul_emulate, |             &emulator, | ||||||
|             5000); |             5000); | ||||||
|         // Check if data was modified
 |         // Check if data was modified
 | ||||||
|         if(mf_ul_emulate.data_changed) { |         if(emulator.data_changed) { | ||||||
|             nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; |             nfc_worker->dev_data->mf_ul_data = emulator.data; | ||||||
|             if(nfc_worker->callback) { |             if(nfc_worker->callback) { | ||||||
|                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); |                 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) { | void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | ||||||
|     furi_assert(nfc_worker->callback); |     furi_assert(nfc_worker->callback); | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     rfalNfcDevice* dev; |  | ||||||
|     NfcDeviceCommonData* nfc_common; |  | ||||||
|     uint8_t dev_cnt = 0; |  | ||||||
|     FuriHalNfcTxRxContext tx_rx_ctx = {}; |     FuriHalNfcTxRxContext tx_rx_ctx = {}; | ||||||
|     MfClassicAuthContext auth_ctx = {}; |     MfClassicAuthContext auth_ctx = {}; | ||||||
|     MfClassicReader reader = {}; |     MfClassicReader reader = {}; | ||||||
| @ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | |||||||
|     uint16_t curr_sector = 0; |     uint16_t curr_sector = 0; | ||||||
|     uint8_t total_sectors = 0; |     uint8_t total_sectors = 0; | ||||||
|     NfcWorkerEvent event; |     NfcWorkerEvent event; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||||
| 
 | 
 | ||||||
|     // Open dictionary
 |     // Open dictionary
 | ||||||
|     nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage); |     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
 |     // Detect Mifare Classic card
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { |     while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||||
|         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { |         if(furi_hal_nfc_detect(nfc_data, 300)) { | ||||||
|             dev = &dev_list[0]; |  | ||||||
|             if(mf_classic_get_type( |             if(mf_classic_get_type( | ||||||
|                    dev->nfcid, |                    nfc_data->uid, | ||||||
|                    dev->nfcidLen, |                    nfc_data->uid_len, | ||||||
|                    dev->dev.nfca.sensRes.anticollisionInfo, |                    nfc_data->atqa[0], | ||||||
|                    dev->dev.nfca.sensRes.platformInfo, |                    nfc_data->atqa[1], | ||||||
|                    dev->dev.nfca.selRes.sak, |                    nfc_data->sak, | ||||||
|                    &reader)) { |                    &reader)) { | ||||||
|                 total_sectors = mf_classic_get_total_sectors_num(&reader); |                 total_sectors = mf_classic_get_total_sectors_num(&reader); | ||||||
|                 if(reader.type == MfClassicType1k) { |                 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); |             mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector); | ||||||
|             bool sector_key_found = false; |             bool sector_key_found = false; | ||||||
|             while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) { |             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(furi_hal_nfc_activate_nfca(300, &reader.cuid)) { | ||||||
|                     if(!card_found_notified) { |                     if(!card_found_notified) { | ||||||
|                         if(reader.type == MfClassicType1k) { |                         if(reader.type == MfClassicType1k) { | ||||||
| @ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | |||||||
|         uint8_t sectors_read = |         uint8_t sectors_read = | ||||||
|             mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); |             mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); | ||||||
|         if(sectors_read) { |         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; |             event = NfcWorkerEventSuccess; | ||||||
|  |             nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; | ||||||
|             FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); |             FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); | ||||||
|         } else { |         } else { | ||||||
|             event = NfcWorkerEventFail; |             event = NfcWorkerEventFail; | ||||||
| @ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | |||||||
|     stream_free(nfc_worker->dict_stream); |     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) { | void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     ReturnCode err; | ||||||
|     rfalNfcDevice* dev_list; |  | ||||||
|     uint8_t dev_cnt = 0; |  | ||||||
|     uint8_t tx_buff[64] = {}; |     uint8_t tx_buff[64] = {}; | ||||||
|     uint16_t tx_len = 0; |     uint16_t tx_len = 0; | ||||||
|     uint8_t rx_buff[512] = {}; |     uint8_t rx_buff[512] = {}; | ||||||
| @ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|     NfcDeviceData* result = nfc_worker->dev_data; |     NfcDeviceData* result = nfc_worker->dev_data; | ||||||
|     nfc_device_data_clear(result); |     nfc_device_data_clear(result); | ||||||
|     MifareDesfireData* data = &result->mf_df_data; |     MifareDesfireData* data = &result->mf_df_data; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; | ||||||
| 
 | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { |     while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { | ||||||
|         furi_hal_nfc_deactivate(); |         furi_hal_nfc_sleep(); | ||||||
|         if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { |         if(!furi_hal_nfc_detect(nfc_data, 300)) { | ||||||
|             osDelay(100); |             osDelay(100); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         memset(data, 0, sizeof(MifareDesfireData)); |         memset(data, 0, sizeof(MifareDesfireData)); | ||||||
|         if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA || |         if(nfc_data->type != FuriHalNfcTypeA || | ||||||
|            !mf_df_check_card_type( |            !mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { | ||||||
|                dev_list[0].dev.nfca.sensRes.anticollisionInfo, |  | ||||||
|                dev_list[0].dev.nfca.sensRes.platformInfo, |  | ||||||
|                dev_list[0].dev.nfca.selRes.sak)) { |  | ||||||
|             FURI_LOG_D(TAG, "Tag is not DESFire"); |             FURI_LOG_D(TAG, "Tag is not DESFire"); | ||||||
|             osDelay(100); |             osDelay(100); | ||||||
|             continue; |             continue; | ||||||
| @ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
| 
 | 
 | ||||||
|         FURI_LOG_D(TAG, "Found DESFire tag"); |         FURI_LOG_D(TAG, "Found DESFire tag"); | ||||||
| 
 | 
 | ||||||
|         // Fill non-DESFire result data
 |         result->protocol = NfcDeviceProtocolMifareDesfire; | ||||||
|         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); |  | ||||||
| 
 | 
 | ||||||
|         // Get DESFire version
 |         // Get DESFire version
 | ||||||
|         tx_len = mf_df_prepare_get_version(tx_buff); |         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) { |         if(err != ERR_NONE) { | ||||||
|             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); |             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); | ||||||
|             continue; |             continue; | ||||||
| @ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         tx_len = mf_df_prepare_get_free_memory(tx_buff); |         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) { |         if(err == ERR_NONE) { | ||||||
|             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); |             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); | ||||||
|             memset(data->free_memory, 0, 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); |         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) { |         if(err != ERR_NONE) { | ||||||
|             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); |             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); | ||||||
|         } else { |         } else { | ||||||
| @ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|                 &data->master_key_settings->key_version_head; |                 &data->master_key_settings->key_version_head; | ||||||
|             for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { |             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); |                 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) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); |                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||||
|                     continue; |                     continue; | ||||||
| @ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         tx_len = mf_df_prepare_get_application_ids(tx_buff); |         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) { |         if(err != ERR_NONE) { | ||||||
|             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); |             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); | ||||||
|         } else { |         } else { | ||||||
| @ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
| 
 | 
 | ||||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { |         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||||
|             tx_len = mf_df_prepare_select_application(tx_buff, app->id); |             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)) { |             if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { | ||||||
|                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); |                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             tx_len = mf_df_prepare_get_key_settings(tx_buff); |             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) { |             if(err != ERR_NONE) { | ||||||
|                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); |                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); | ||||||
|             } else { |             } else { | ||||||
| @ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|                 MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; |                 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++) { |                 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); |                     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) { |                     if(err != ERR_NONE) { | ||||||
|                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); |                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||||
|                         continue; |                         continue; | ||||||
| @ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             tx_len = mf_df_prepare_get_file_ids(tx_buff); |             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) { |             if(err != ERR_NONE) { | ||||||
|                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); |                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); | ||||||
|             } else { |             } else { | ||||||
| @ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
| 
 | 
 | ||||||
|             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { |             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||||
|                 tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); |                 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) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); |                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); | ||||||
|                     continue; |                     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); |                     tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); | ||||||
|                     break; |                     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) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); |                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); | ||||||
|                     continue; |                     continue; | ||||||
| @ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | |||||||
|         break; |         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(); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -13,11 +13,11 @@ typedef enum { | |||||||
|     NfcWorkerStateDetect, |     NfcWorkerStateDetect, | ||||||
|     NfcWorkerStateEmulate, |     NfcWorkerStateEmulate, | ||||||
|     NfcWorkerStateReadEMVApp, |     NfcWorkerStateReadEMVApp, | ||||||
|     NfcWorkerStateReadEMV, |     NfcWorkerStateReadEMVData, | ||||||
|     NfcWorkerStateEmulateApdu, |     NfcWorkerStateEmulateApdu, | ||||||
|     NfcWorkerStateField, |     NfcWorkerStateField, | ||||||
|     NfcWorkerStateReadMifareUl, |     NfcWorkerStateReadMifareUltralight, | ||||||
|     NfcWorkerStateEmulateMifareUl, |     NfcWorkerStateEmulateMifareUltralight, | ||||||
|     NfcWorkerStateReadMifareClassic, |     NfcWorkerStateReadMifareClassic, | ||||||
|     NfcWorkerStateReadMifareDesfire, |     NfcWorkerStateReadMifareDesfire, | ||||||
|     // Transition
 |     // Transition
 | ||||||
|  | |||||||
| @ -4,19 +4,8 @@ | |||||||
| #include "nfc_worker.h" | #include "nfc_worker.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <stdbool.h> |  | ||||||
| #include <lib/toolbox/stream/file_stream.h> | #include <lib/toolbox/stream/file_stream.h> | ||||||
| 
 | 
 | ||||||
| #include <rfal_analogConfig.h> |  | ||||||
| #include <rfal_rf.h> |  | ||||||
| #include <rfal_nfc.h> |  | ||||||
| #include <rfal_nfca.h> |  | ||||||
| #include <rfal_nfcb.h> |  | ||||||
| #include <rfal_nfcf.h> |  | ||||||
| #include <rfal_nfcv.h> |  | ||||||
| #include <st25r3916.h> |  | ||||||
| #include <st25r3916_irq.h> |  | ||||||
| 
 |  | ||||||
| struct NfcWorker { | struct NfcWorker { | ||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|     Storage* storage; |     Storage* storage; | ||||||
| @ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker); | |||||||
| 
 | 
 | ||||||
| void nfc_worker_emulate(NfcWorker* nfc_worker); | void nfc_worker_emulate(NfcWorker* nfc_worker); | ||||||
| 
 | 
 | ||||||
| void nfc_worker_field(NfcWorker* nfc_worker); | void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker); | ||||||
| 
 |  | ||||||
| void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker); |  | ||||||
| 
 | 
 | ||||||
| void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); | void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) { |     if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Run Compatible App", |             "Run Compatible App", | ||||||
| @ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == SubmenuIndexRunApp) { |         if(event.event == SubmenuIndexRunApp) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); |                 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); |                 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); |                 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); |                 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); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); | ||||||
|             } |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start) | |||||||
| ADD_SCENE(nfc, read_card, ReadCard) | ADD_SCENE(nfc, read_card, ReadCard) | ||||||
| ADD_SCENE(nfc, read_card_success, ReadCardSuccess) | ADD_SCENE(nfc, read_card_success, ReadCardSuccess) | ||||||
| ADD_SCENE(nfc, card_menu, CardMenu) | ADD_SCENE(nfc, card_menu, CardMenu) | ||||||
| ADD_SCENE(nfc, not_implemented, NotImplemented) |  | ||||||
| ADD_SCENE(nfc, emulate_uid, EmulateUid) | ADD_SCENE(nfc, emulate_uid, EmulateUid) | ||||||
| ADD_SCENE(nfc, save_name, SaveName) | ADD_SCENE(nfc, save_name, SaveName) | ||||||
| ADD_SCENE(nfc, save_success, SaveSuccess) | ADD_SCENE(nfc, save_success, SaveSuccess) | ||||||
|  | |||||||
| @ -6,13 +6,13 @@ enum SubmenuDebugIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_debug_on_enter(void* context) { | void nfc_scene_debug_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     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) { | bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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) { | void nfc_scene_debug_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,29 +1,29 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { | void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     if(type == InputTypeShort) { |     if(type == InputTypeShort) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_on_enter(void* context) { | void nfc_scene_delete_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     char delete_str[64]; |     char temp_str[64]; | ||||||
|     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name); |     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, delete_str); |     widget_add_text_box_element( | ||||||
|  |         nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); |         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); |         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); | ||||||
|     char uid_str[32]; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |  | ||||||
|     if(data->uid_len == 4) { |     if(data->uid_len == 4) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             temp_str, | ||||||
|             sizeof(uid_str), |             sizeof(temp_str), | ||||||
|             "UID: %02X %02X %02X %02X", |             "UID: %02X %02X %02X %02X", | ||||||
|             data->uid[0], |             data->uid[0], | ||||||
|             data->uid[1], |             data->uid[1], | ||||||
| @ -31,8 +31,8 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
|             data->uid[3]); |             data->uid[3]); | ||||||
|     } else if(data->uid_len == 7) { |     } else if(data->uid_len == 7) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             temp_str, | ||||||
|             sizeof(uid_str), |             sizeof(temp_str), | ||||||
|             "UID: %02X %02X %02X %02X %02X %02X %02X", |             "UID: %02X %02X %02X %02X %02X %02X %02X", | ||||||
|             data->uid[0], |             data->uid[0], | ||||||
|             data->uid[1], |             data->uid[1], | ||||||
| @ -42,12 +42,13 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
|             data->uid[5], |             data->uid[5], | ||||||
|             data->uid[6]); |             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; |     const char* protocol_name = NULL; | ||||||
|     if(data->protocol == NfcDeviceProtocolEMV) { |     NfcProtocol protocol = nfc->dev->dev_data.protocol; | ||||||
|         protocol_name = nfc_guess_protocol(data->protocol); |     if(protocol == NfcDeviceProtocolEMV) { | ||||||
|     } else if(data->protocol == NfcDeviceProtocolMifareUl) { |         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); |         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); | ||||||
|     } |     } | ||||||
|     if(protocol_name) { |     if(protocol_name) { | ||||||
| @ -56,18 +57,17 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     // TODO change dinamically
 |     // TODO change dinamically
 | ||||||
|     widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); |     widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); | ||||||
|     char sak_str[16]; |     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); | ||||||
|     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); |     widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||||
|     widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str); |     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); | ||||||
|     char atqa_str[16]; |     widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str); | ||||||
|     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); |  | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         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( |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|                     nfc->scene_manager, NfcSceneStart); |                     nfc->scene_manager, NfcSceneStart); | ||||||
|             } |             } | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_on_exit(void* context) { | void nfc_scene_delete_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     widget_reset(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_success_popup_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_success_on_enter(void* context) { | void nfc_scene_delete_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventViewExit) { |         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); |                 nfc->scene_manager, NfcSceneStart); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_success_on_exit(void* context) { | void nfc_scene_delete_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
| @ -36,19 +36,19 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatBankCard); |                                   (nfc->dev->format == NfcDeviceSaveFormatBankCard); | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     widget_add_text_box_element( |     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( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); |         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); | ||||||
|     if(data_display_supported) { |     if(data_display_supported) { | ||||||
|         widget_add_button_element( |         widget_add_button_element( | ||||||
|             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); |             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); | ||||||
|     } |     } | ||||||
|     char uid_str[32]; |     char temp_str[32]; | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     if(data->uid_len == 4) { |     if(data->uid_len == 4) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             temp_str, | ||||||
|             sizeof(uid_str), |             sizeof(temp_str), | ||||||
|             "UID: %02X %02X %02X %02X", |             "UID: %02X %02X %02X %02X", | ||||||
|             data->uid[0], |             data->uid[0], | ||||||
|             data->uid[1], |             data->uid[1], | ||||||
| @ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|             data->uid[3]); |             data->uid[3]); | ||||||
|     } else if(data->uid_len == 7) { |     } else if(data->uid_len == 7) { | ||||||
|         snprintf( |         snprintf( | ||||||
|             uid_str, |             temp_str, | ||||||
|             sizeof(uid_str), |             sizeof(temp_str), | ||||||
|             "UID: %02X %02X %02X %02X %02X %02X %02X", |             "UID: %02X %02X %02X %02X %02X %02X %02X", | ||||||
|             data->uid[0], |             data->uid[0], | ||||||
|             data->uid[1], |             data->uid[1], | ||||||
| @ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|             data->uid[5], |             data->uid[5], | ||||||
|             data->uid[6]); |             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; |     const char* protocol_name = NULL; | ||||||
|     if(data->protocol == NfcDeviceProtocolEMV || |     NfcProtocol protocol = nfc->dev->dev_data.protocol; | ||||||
|        data->protocol == NfcDeviceProtocolMifareDesfire) { |     if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { | ||||||
|         protocol_name = nfc_guess_protocol(data->protocol); |         protocol_name = nfc_guess_protocol(protocol); | ||||||
|     } else if(data->protocol == NfcDeviceProtocolMifareUl) { |     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); |         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); |         protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); | ||||||
|     } |     } | ||||||
|     if(protocol_name) { |     if(protocol_name) { | ||||||
| @ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     // TODO change dinamically
 |     // TODO change dinamically
 | ||||||
|     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); |     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); | ||||||
|     char sak_str[16]; |     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); | ||||||
|     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); |     widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||||
|     widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str); |     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); | ||||||
|     char atqa_str[16]; |     widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str); | ||||||
|     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); |  | ||||||
| 
 | 
 | ||||||
|     // Setup Data View
 |     // Setup Data View
 | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { |     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_context(dialog_ex, nfc); | ||||||
|         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); |         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |     } 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; |         TextBox* text_box = nfc->text_box; | ||||||
|         text_box_set_font(text_box, TextBoxFontHex); |         text_box_set_font(text_box, TextBoxFontHex); | ||||||
|         for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { |         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( |         widget_add_string_element( | ||||||
|             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); |             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |     } 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; |         BankCard* bank_card = nfc->bank_card; | ||||||
|         bank_card_set_name(bank_card, emv_data->name); |         bank_card_set_name(bank_card, emv_data->name); | ||||||
|         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); |         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) { | 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); |     widget_reset(nfc->widget); | ||||||
| 
 |  | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { |     if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||||
|         // Clear Dialog
 |         dialog_ex_reset(nfc->dialog_ex); | ||||||
|         DialogEx* dialog_ex = nfc->dialog_ex; |  | ||||||
|         dialog_ex_reset(dialog_ex); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|         // Clear TextBox
 |  | ||||||
|         text_box_reset(nfc->text_box); |         text_box_reset(nfc->text_box); | ||||||
|         string_reset(nfc->text_box_store); |         string_reset(nfc->text_box_store); | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|         // Clear Bank Card
 |  | ||||||
|         bank_card_clear(nfc->bank_card); |         bank_card_clear(nfc->bank_card); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,36 +1,34 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { | void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
| 
 |  | ||||||
|     popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); |     popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|     // Setup and start worker
 |     // Setup and start worker
 | ||||||
| 
 |  | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
|     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); |     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { | 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) { |     if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         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) { | void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 |  | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(nfc->popup); | ||||||
|     popup_reset(popup); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,13 +5,14 @@ | |||||||
| #define NFC_MF_UL_DATA_CHANGED (1UL) | #define NFC_MF_UL_DATA_CHANGED (1UL) | ||||||
| 
 | 
 | ||||||
| void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { | void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); |         nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_emulate_mifare_ul_on_enter(void* context) { | void nfc_scene_emulate_mifare_ul_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); |     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // 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); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateEmulateMifareUl, |         NfcWorkerStateEmulateMifareUltralight, | ||||||
|         &nfc->dev->dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_emulate_mifare_ul_worker_callback, |         nfc_emulate_mifare_ul_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeTick) { |     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) { | void nfc_scene_emulate_mifare_ul_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
|  | #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) | ||||||
|  | 
 | ||||||
| enum { | enum { | ||||||
|     NfcSceneEmulateUidStateWidget, |     NfcSceneEmulateUidStateWidget, | ||||||
|     NfcSceneEmulateUidStateTextBox, |     NfcSceneEmulateUidStateTextBox, | ||||||
| @ -28,14 +30,14 @@ void nfc_emulate_uid_textbox_callback(void* context) { | |||||||
| 
 | 
 | ||||||
| // Add widget with device name or inform that data received
 | // Add widget with device name or inform that data received
 | ||||||
| static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool 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* widget = nfc->widget; | ||||||
|     widget_reset(widget); |     widget_reset(widget); | ||||||
|     string_t info_str; |     string_t info_str; | ||||||
|     string_init(info_str); |     string_init(info_str); | ||||||
| 
 | 
 | ||||||
|     widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); |     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, "")) { |     if(strcmp(nfc->dev->dev_name, "")) { | ||||||
|         string_printf(info_str, "%s", nfc->dev->dev_name); |         string_printf(info_str, "%s", nfc->dev->dev_name); | ||||||
|     } else { |     } else { | ||||||
| @ -45,7 +47,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { | |||||||
|     } |     } | ||||||
|     string_strim(info_str); |     string_strim(info_str); | ||||||
|     widget_add_text_box_element( |     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); |     string_clear(info_str); | ||||||
|     if(data_received) { |     if(data_received) { | ||||||
|         widget_add_button_element( |         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); |                 nfc_scene_emulate_uid_widget_config(nfc, true); | ||||||
|             } |             } | ||||||
|             // Update TextBox data
 |             // Update TextBox data
 | ||||||
|             string_cat_printf(nfc->text_box_store, "R:"); |             if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) { | ||||||
|             for(uint16_t i = 0; i < reader_data->size; i++) { |                 string_cat_printf(nfc->text_box_store, "R:"); | ||||||
|                 string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); |                 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)); |             memset(reader_data, 0, sizeof(NfcReaderRequestData)); | ||||||
|             text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { |         } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_field_on_enter(void* context) { | void nfc_scene_field_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     furi_hal_nfc_field_on(); |     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) { | void nfc_scene_field_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 |  | ||||||
|     notification_internal_message(nfc->notifications, &sequence_reset_blue); |  | ||||||
| 
 |  | ||||||
|     Popup* popup = nfc->popup; |  | ||||||
|     popup_reset(popup); |  | ||||||
| 
 | 
 | ||||||
|     furi_hal_nfc_field_off(); |     furi_hal_nfc_field_off(); | ||||||
|  |     notification_internal_message(nfc->notifications, &sequence_reset_blue); | ||||||
|  |     popup_reset(nfc->popup); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_file_select_on_enter(void* context) { | void nfc_scene_file_select_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     // Process file_select return
 |     // Process file_select return
 | ||||||
|     if(nfc_file_select(nfc->dev)) { |     if(nfc_file_select(nfc->dev)) { | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); | ||||||
|  | |||||||
| @ -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) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_desfire_app_on_enter(void* context) { | void nfc_scene_mifare_desfire_app_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
|     MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); |     MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); | ||||||
|     if(!app) { |     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) { | 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); |     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp); | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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)); |         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); | ||||||
|         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|         return true; |         consumed = true; | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(state & 1) { |         if(state & 1) { | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); |                 nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_desfire_app_on_exit(void* context) { | 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); |     text_box_reset(nfc->text_box); | ||||||
|     string_reset(nfc->text_box_store); |     string_reset(nfc->text_box_store); | ||||||
| 
 |  | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -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) { | void nfc_scene_mifare_desfire_data_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); |     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; |     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) { | 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); |     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; |     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, |                 nfc->scene_manager, | ||||||
|                 NfcSceneMifareDesfireData, |                 NfcSceneMifareDesfireData, | ||||||
|                 MifareDesfireDataStateItem + SubmenuIndexCardInfo); |                 MifareDesfireDataStateItem + SubmenuIndexCardInfo); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else { |         } else { | ||||||
|             uint16_t index = event.event - SubmenuIndexDynamic; |             uint16_t index = event.event - SubmenuIndexDynamic; | ||||||
|             scene_manager_set_scene_state( |             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( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); |                 nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(state >= MifareDesfireDataStateItem) { |         if(state >= MifareDesfireDataStateItem) { | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); |                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_desfire_data_on_exit(void* context) { | 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); |     text_box_reset(nfc->text_box); | ||||||
|     string_reset(nfc->text_box_store); |     string_reset(nfc->text_box_store); | ||||||
| 
 |  | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,13 +5,13 @@ enum SubmenuIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_desfire_menu_on_enter(void* context) { | void nfc_scene_mifare_desfire_menu_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexSave) { |         if(event.event == SubmenuIndexSave) { | ||||||
| @ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve | |||||||
|             // Clear device name
 |             // Clear device name
 | ||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             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) { | void nfc_scene_mifare_desfire_menu_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     // Clear view
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,13 +6,13 @@ enum SubmenuIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mifare_ul_menu_on_enter(void* context) { | void nfc_scene_mifare_ul_menu_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexSave) { |         if(event.event == SubmenuIndexSave) { | ||||||
| @ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             // Clear device name
 |             // Clear device name
 | ||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); |                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         return scene_manager_search_and_switch_to_previous_scene( |         consumed = | ||||||
|             nfc->scene_manager, NfcSceneStart); |             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) { | void nfc_scene_mifare_ul_menu_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     // Clear view
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -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); |  | ||||||
| } |  | ||||||
| @ -2,12 +2,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_card_on_enter(void* context) { | void nfc_scene_read_card_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // 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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventWorkerExit) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         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) { | void nfc_scene_read_card_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 |  | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback( | |||||||
|     void* context) { |     void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|     if(type == InputTypeShort) { |     if(type == InputTypeShort) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_card_success_on_enter(void* context) { | void nfc_scene_read_card_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|     string_t data_str; |     string_t data_str; | ||||||
|     string_t uid_str; |     string_t uid_str; | ||||||
|     string_init(data_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); |     notification_message(nfc->notifications, &sequence_success); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     Widget* widget = nfc->widget; |     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:"); |     string_set_str(uid_str, "UID:"); | ||||||
|     for(uint8_t i = 0; i < data->uid_len; i++) { |     for(uint8_t i = 0; i < data->uid_len; i++) { | ||||||
|         string_cat_printf(uid_str, " %02X", data->uid[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_add_button_element( | ||||||
|         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); |         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); | ||||||
|     if(data->device == NfcDeviceNfca) { |     if(data->type == FuriHalNfcTypeA) { | ||||||
|         widget_add_button_element( |         widget_add_button_element( | ||||||
|             widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc); |             widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc); | ||||||
|         widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); |         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( |         string_printf( | ||||||
|             data_str, |             data_str, | ||||||
|             "%s\nATQA: %02X%02X SAK: %02X", |             "%s\nATQA: %02X%02X SAK: %02X", | ||||||
|             nfc_guess_protocol(data->protocol), |             nfc_guess_protocol(nfc->dev->dev_data.protocol), | ||||||
|             data->atqa[0], |             data->atqa[0], | ||||||
|             data->atqa[1], |             data->atqa[1], | ||||||
|             data->sak); |             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) { | bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); |             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
 |             // Clear device name
 | ||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu); |             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) { | void nfc_scene_read_card_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|     widget_reset(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_app_on_enter(void* context) { | void nfc_scene_read_emv_app_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // 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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventWorkerExit) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); |                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         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) { | void nfc_scene_read_emv_app_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,27 +2,38 @@ | |||||||
| #include "../helpers/nfc_emv_parser.h" | #include "../helpers/nfc_emv_parser.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
| 
 |     Nfc* nfc = context; | ||||||
| void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) { |     if(type == InputTypeShort) { | ||||||
|     Nfc* nfc = (Nfc*)context; |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| 
 |     } | ||||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_app_success_on_enter(void* context) { | void nfc_scene_read_emv_app_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; |     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     Widget* widget = nfc->widget; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     widget_add_button_element( | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "Run app"); |         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc); | ||||||
|     dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter); |     widget_add_button_element( | ||||||
|     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); |         widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc); | ||||||
|     // Display UID and AID
 |     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_t aid; | ||||||
|     string_init(aid); |     string_init(aid); | ||||||
|     bool aid_found = |     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]); |             string_cat_printf(aid, "%02X", emv_data->aid[i]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     nfc_text_store_set( |     string_cat(temp_str, aid); | ||||||
|         nfc, |     widget_add_string_element( | ||||||
|         NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT |         widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|                                      "Application:\n%s", |     string_clear(temp_str); | ||||||
|         nfc_data->uid[0], |  | ||||||
|         nfc_data->uid[1], |  | ||||||
|         nfc_data->uid[2], |  | ||||||
|         nfc_data->uid[3], |  | ||||||
|         string_get_cstr(aid)); |  | ||||||
|     string_clear(aid); |     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
 |     // Send notification
 | ||||||
|     if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) == |     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); |             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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == DialogExResultLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             return scene_manager_previous_scene(nfc->scene_manager); |             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if(event.event == DialogExResultRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm); |             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) { | void nfc_scene_read_emv_app_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     // Clear views
 | ||||||
|     dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); |     widget_reset(nfc->widget); | ||||||
|     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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_data_on_enter(void* context) { | void nfc_scene_read_emv_data_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
| @ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) { | |||||||
|     // Start worker
 |     // Start worker
 | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateReadEMV, |         NfcWorkerStateReadEMVData, | ||||||
|         &nfc->dev->dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_read_emv_data_worker_callback, |         nfc_read_emv_data_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventWorkerExit) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); |                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         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) { | void nfc_scene_read_emv_data_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 |  | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback( | |||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
|     InputType type, |     InputType type, | ||||||
|     void* context) { |     void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     if(type == InputTypeShort) { |     if(type == InputTypeShort) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_data_success_on_enter(void* context) { | void nfc_scene_read_emv_data_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; |     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // 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(disp_currency); | ||||||
|     } |     } | ||||||
|     string_clear(currency_name); |     string_clear(currency_name); | ||||||
|  |     char temp_str[32]; | ||||||
|     // Add ATQA
 |     // Add ATQA
 | ||||||
|     char atqa_str[16]; |     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); | ||||||
|     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, temp_str); | ||||||
|     widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str); |  | ||||||
|     // Add UID
 |     // Add UID
 | ||||||
|     char uid_str[32]; |  | ||||||
|     snprintf( |     snprintf( | ||||||
|         uid_str, |         temp_str, | ||||||
|         sizeof(uid_str), |         sizeof(temp_str), | ||||||
|         "UID: %02X %02X %02X %02X", |         "UID: %02X %02X %02X %02X", | ||||||
|         nfc_data->uid[0], |         nfc_data->uid[0], | ||||||
|         nfc_data->uid[1], |         nfc_data->uid[1], | ||||||
|         nfc_data->uid[2], |         nfc_data->uid[2], | ||||||
|         nfc_data->uid[3]); |         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
 |     // Add SAK
 | ||||||
|     char sak_str[16]; |     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak); | ||||||
|     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); |     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str); | ||||||
|     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str); |  | ||||||
|     // Add expiration date
 |     // Add expiration date
 | ||||||
|     if(emv_data->exp_mon) { |     if(emv_data->exp_mon) { | ||||||
|         char exp_str[16]; |         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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         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); |                 nfc->scene_manager, NfcSceneReadEmvAppSuccess); | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             // Clear device name
 |             // Clear device name
 | ||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatBankCard; |             nfc->dev->format = NfcDeviceSaveFormatBankCard; | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } 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); |             nfc->scene_manager, NfcSceneReadEmvAppSuccess); | ||||||
|     } |     } | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_emv_data_success_on_exit(void* context) { | void nfc_scene_read_emv_data_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     // Clear view
 | ||||||
|     widget_reset(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_desfire_on_enter(void* context) { | void nfc_scene_read_mifare_desfire_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); |     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // 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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventWorkerExit) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         notification_message(nfc->notifications, &sequence_blink_blue_10); | ||||||
|         DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |         DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|         return true; |         consumed = true; | ||||||
|     } |     } | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_desfire_on_exit(void* context) { | void nfc_scene_read_mifare_desfire_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 |  | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,13 +9,13 @@ enum { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { | 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; |     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     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) { | bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|     uint32_t state = |     uint32_t state = | ||||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); |         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); | ||||||
|     bool consumed = false; |  | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) { |         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) { | void nfc_scene_read_mifare_desfire_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clean dialog
 |     // Clean dialog
 | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     dialog_ex_reset(nfc->dialog_ex); | ||||||
|     dialog_ex_reset(dialog_ex); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) { | |||||||
|     // Start worker
 |     // Start worker
 | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateReadMifareUl, |         NfcWorkerStateReadMifareUltralight, | ||||||
|         &nfc->dev->dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_read_mifare_ul_worker_callback, |         nfc_read_mifare_ul_worker_callback, | ||||||
|         nfc); |         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) { | void nfc_scene_read_mifare_ul_on_exit(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|  | |||||||
| @ -9,21 +9,21 @@ enum { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Send notification
 |     // Send notification
 | ||||||
|     notification_message(nfc->notifications, &sequence_success); |     notification_message(nfc->notifications, &sequence_success); | ||||||
| 
 | 
 | ||||||
|     // Setup dialog view
 |     // Setup dialog view
 | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; |     MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |     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) { | bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|     uint32_t state = |     uint32_t state = | ||||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess); |         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess); | ||||||
|     bool consumed = false; |  | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { |         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) { | void nfc_scene_read_mifare_ul_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clean dialog
 |     // Clean views
 | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     dialog_ex_reset(nfc->dialog_ex); | ||||||
|     dialog_ex_reset(dialog_ex); |     text_box_reset(nfc->text_box); | ||||||
| 
 |  | ||||||
|     // Clean TextBox
 |  | ||||||
|     TextBox* text_box = nfc->text_box; |  | ||||||
|     text_box_reset(text_box); |  | ||||||
|     string_reset(nfc->text_box_store); |     string_reset(nfc->text_box_store); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_restore_original_popup_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_restore_original_on_enter(void* context) { | void nfc_scene_restore_original_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     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) { | bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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) { | void nfc_scene_restore_original_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,15 +1,13 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " |  | ||||||
| 
 |  | ||||||
| void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_run_emv_app_confirm_on_enter(void* context) { | void nfc_scene_run_emv_app_confirm_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Back"); |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == DialogExResultLeft) { |         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) { |         } else if(event.event == DialogExResultRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData); |             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) { | void nfc_scene_run_emv_app_confirm_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     // Clean view
 | ||||||
|     dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); |     dialog_ex_reset(nfc->dialog_ex); | ||||||
|     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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,13 +3,13 @@ | |||||||
| #include <gui/modules/validators.h> | #include <gui/modules/validators.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_name_text_input_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_name_on_enter(void* context) { | void nfc_scene_save_name_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     TextInput* text_input = nfc->text_input; |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventTextInputDone) { |         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); |             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); | ||||||
|             if(nfc_device_save(nfc->dev, nfc->text_store)) { |             if(nfc_device_save(nfc->dev, nfc->text_store)) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||||
|                 return true; |                 consumed = true; | ||||||
|             } else { |             } else { | ||||||
|                 return scene_manager_search_and_switch_to_previous_scene( |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|                     nfc->scene_manager, NfcSceneStart); |                     nfc->scene_manager, NfcSceneStart); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_name_on_exit(void* context) { | void nfc_scene_save_name_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     void* validator_context = text_input_get_validator_callback_context(nfc->text_input); |     void* validator_context = text_input_get_validator_callback_context(nfc->text_input); | ||||||
|  | |||||||
| @ -2,12 +2,12 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_success_popup_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_save_success_on_enter(void* context) { | void nfc_scene_save_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcSave); |     DOLPHIN_DEED(DolphinDeedNfcSave); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // 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) { | bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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) { | void nfc_scene_save_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     popup_reset(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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,13 +9,13 @@ enum SubmenuIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_saved_menu_on_enter(void* context) { | void nfc_scene_saved_menu_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid || |     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) { | bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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) { | void nfc_scene_saved_menu_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_atqa_byte_input_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_atqa_on_enter(void* context) { | void nfc_scene_set_atqa_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     ByteInput* byte_input = nfc->byte_input; |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); |             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) { | void nfc_scene_set_atqa_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); |     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_sak_byte_input_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_sak_on_enter(void* context) { | void nfc_scene_set_sak_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     ByteInput* byte_input = nfc->byte_input; |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); |             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) { | void nfc_scene_set_sak_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); |     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); | ||||||
|  | |||||||
| @ -6,13 +6,13 @@ enum SubmenuIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_type_on_enter(void* context) { | void nfc_scene_set_type_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
|     // Clear device name
 |     // Clear device name
 | ||||||
|     nfc_device_set_name(nfc->dev, ""); |     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) { | 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.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubmenuIndexNFCA7) { |         if(event.event == SubmenuIndexNFCA7) { | ||||||
|             nfc->dev->dev_data.nfc_data.uid_len = 7; |             nfc->dev->dev_data.nfc_data.uid_len = 7; | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; |             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexNFCA4) { |         } else if(event.event == SubmenuIndexNFCA4) { | ||||||
|             nfc->dev->dev_data.nfc_data.uid_len = 4; |             nfc->dev->dev_data.nfc_data.uid_len = 4; | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; |             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); |             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) { | void nfc_scene_set_type_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,13 +2,13 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_uid_byte_input_callback(void* context) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_set_uid_on_enter(void* context) { | void nfc_scene_set_uid_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     ByteInput* byte_input = nfc->byte_input; |     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) { | bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
|  |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventByteInputDone) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             DOLPHIN_DEED(DolphinDeedNfcAdd); |             DOLPHIN_DEED(DolphinDeedNfcAdd); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             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) { | void nfc_scene_set_uid_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); |     byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); | ||||||
|  | |||||||
| @ -9,13 +9,13 @@ enum SubmenuIndex { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_start_submenu_callback(void* context, uint32_t index) { | 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); |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_start_on_enter(void* context) { | void nfc_scene_start_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     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) { | bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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) { | void nfc_scene_start_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     submenu_reset(nfc->submenu); |     submenu_reset(nfc->submenu); | ||||||
| } | } | ||||||
|  | |||||||
| @ -59,6 +59,8 @@ typedef enum { | |||||||
|     NotificationMessageTypeForceSpeakerVolumeSetting, |     NotificationMessageTypeForceSpeakerVolumeSetting, | ||||||
|     NotificationMessageTypeForceVibroSetting, |     NotificationMessageTypeForceVibroSetting, | ||||||
|     NotificationMessageTypeForceDisplayBrightnessSetting, |     NotificationMessageTypeForceDisplayBrightnessSetting, | ||||||
|  | 
 | ||||||
|  |     NotificationMessageTypeLedBrightnessSettingApply, | ||||||
| } NotificationMessageType; | } NotificationMessageType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  | |||||||
| @ -212,18 +212,21 @@ void notification_process_notification_message( | |||||||
|             // store and send on delay or after seq
 |             // store and send on delay or after seq
 | ||||||
|             led_active = true; |             led_active = true; | ||||||
|             led_values[0] = notification_message->data.led.value; |             led_values[0] = notification_message->data.led.value; | ||||||
|  |             app->led[0].value_last[LayerNotification] = led_values[0]; | ||||||
|             reset_mask |= reset_red_mask; |             reset_mask |= reset_red_mask; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeLedGreen: |         case NotificationMessageTypeLedGreen: | ||||||
|             // store and send on delay or after seq
 |             // store and send on delay or after seq
 | ||||||
|             led_active = true; |             led_active = true; | ||||||
|             led_values[1] = notification_message->data.led.value; |             led_values[1] = notification_message->data.led.value; | ||||||
|  |             app->led[1].value_last[LayerNotification] = led_values[1]; | ||||||
|             reset_mask |= reset_green_mask; |             reset_mask |= reset_green_mask; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeLedBlue: |         case NotificationMessageTypeLedBlue: | ||||||
|             // store and send on delay or after seq
 |             // store and send on delay or after seq
 | ||||||
|             led_active = true; |             led_active = true; | ||||||
|             led_values[2] = notification_message->data.led.value; |             led_values[2] = notification_message->data.led.value; | ||||||
|  |             app->led[2].value_last[LayerNotification] = led_values[2]; | ||||||
|             reset_mask |= reset_blue_mask; |             reset_mask |= reset_blue_mask; | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeVibro: |         case NotificationMessageTypeVibro: | ||||||
| @ -273,6 +276,16 @@ void notification_process_notification_message( | |||||||
|         case NotificationMessageTypeForceDisplayBrightnessSetting: |         case NotificationMessageTypeForceDisplayBrightnessSetting: | ||||||
|             display_brightness_setting = |             display_brightness_setting = | ||||||
|                 notification_message->data.forced_settings.display_brightness; |                 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_index++; | ||||||
|         notification_message = (*message->sequence)[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)); |                     app, notification_message->data.led.value)); | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeLedRed: |         case NotificationMessageTypeLedRed: | ||||||
|  |             app->led[0].value_last[LayerInternal] = notification_message->data.led.value; | ||||||
|             notification_apply_internal_led_layer( |             notification_apply_internal_led_layer( | ||||||
|                 &app->led[0], |                 &app->led[0], | ||||||
|                 notification_settings_get_rgb_led_brightness( |                 notification_settings_get_rgb_led_brightness( | ||||||
|                     app, notification_message->data.led.value)); |                     app, notification_message->data.led.value)); | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeLedGreen: |         case NotificationMessageTypeLedGreen: | ||||||
|  |             app->led[1].value_last[LayerInternal] = notification_message->data.led.value; | ||||||
|             notification_apply_internal_led_layer( |             notification_apply_internal_led_layer( | ||||||
|                 &app->led[1], |                 &app->led[1], | ||||||
|                 notification_settings_get_rgb_led_brightness( |                 notification_settings_get_rgb_led_brightness( | ||||||
|                     app, notification_message->data.led.value)); |                     app, notification_message->data.led.value)); | ||||||
|             break; |             break; | ||||||
|         case NotificationMessageTypeLedBlue: |         case NotificationMessageTypeLedBlue: | ||||||
|  |             app->led[2].value_last[LayerInternal] = notification_message->data.led.value; | ||||||
|             notification_apply_internal_led_layer( |             notification_apply_internal_led_layer( | ||||||
|                 &app->led[2], |                 &app->led[2], | ||||||
|                 notification_settings_get_rgb_led_brightness( |                 notification_settings_get_rgb_led_brightness( | ||||||
|                     app, notification_message->data.led.value)); |                     app, notification_message->data.led.value)); | ||||||
|             break; |             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: |         default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ typedef enum { | |||||||
| } NotificationLedLayerIndex; | } NotificationLedLayerIndex; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     uint8_t value_last[LayerMAX]; | ||||||
|     uint8_t value[LayerMAX]; |     uint8_t value[LayerMAX]; | ||||||
|     NotificationLedLayerIndex index; |     NotificationLedLayerIndex index; | ||||||
|     Light light; |     Light light; | ||||||
|  | |||||||
| @ -82,12 +82,22 @@ static void screen_changed(VariableItem* item) { | |||||||
|     notification_message(app->notification, &sequence_display_on); |     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) { | static void led_changed(VariableItem* item) { | ||||||
|     NotificationAppSettings* app = variable_item_get_context(item); |     NotificationAppSettings* app = variable_item_get_context(item); | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
| 
 | 
 | ||||||
|     variable_item_set_current_value_text(item, backlight_text[index]); |     variable_item_set_current_value_text(item, backlight_text[index]); | ||||||
|     app->notification->settings.led_brightness = backlight_value[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); |     notification_message(app->notification, &sequence_blink_white_100); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								applications/power/power_service/power.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										26
									
								
								applications/power/power_service/power.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -12,14 +12,19 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Power* power = context; |     Power* power = context; | ||||||
|     canvas_draw_icon(canvas, 0, 1, &I_Battery_26x8); |     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) { |     if(power->info.gauge_is_ok) { | ||||||
|         canvas_set_bitmap_mode(canvas, 1); |         canvas_draw_box(canvas, 2, 3, (power->info.charge + 4) / 5, 4); | ||||||
|         canvas_set_color(canvas, ColorWhite); |         if(power->state == PowerStateCharging) { | ||||||
|         canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_mask_9x10); |             canvas_set_bitmap_mode(canvas, 1); | ||||||
|         canvas_set_color(canvas, ColorBlack); |             canvas_set_color(canvas, ColorWhite); | ||||||
|         canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_9x10); |             canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_mask_9x10); | ||||||
|         canvas_set_bitmap_mode(canvas, 0); |             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) { | static bool power_update_info(Power* power) { | ||||||
|     PowerInfo info; |     PowerInfo info; | ||||||
| 
 | 
 | ||||||
|  |     info.gauge_is_ok = furi_hal_power_gauge_is_ok(); | ||||||
|     info.charge = furi_hal_power_get_pct(); |     info.charge = furi_hal_power_get_pct(); | ||||||
|     info.health = furi_hal_power_get_bat_health_pct(); |     info.health = furi_hal_power_get_bat_health_pct(); | ||||||
|     info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); |     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) { | static void power_check_low_battery(Power* power) { | ||||||
|  |     if(!power->info.gauge_is_ok) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Check battery charge and vbus voltage
 |     // Check battery charge and vbus voltage
 | ||||||
|     if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) && |     if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) && | ||||||
|        power->show_low_bat_level_message) { |        power->show_low_bat_level_message) { | ||||||
|  | |||||||
| @ -29,6 +29,8 @@ typedef struct { | |||||||
| } PowerEvent; | } PowerEvent; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     bool gauge_is_ok; | ||||||
|  | 
 | ||||||
|     float current_charger; |     float current_charger; | ||||||
|     float current_gauge; |     float current_gauge; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubGhzCustomEventSceneDelete) { |         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)) { |             if(subghz_delete_file(subghz)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); | ||||||
|             } else { |             } else { | ||||||
|  | |||||||
| @ -21,10 +21,15 @@ void subghz_scene_delete_raw_on_enter(void* context) { | |||||||
|     string_init(frequency_str); |     string_init(frequency_str); | ||||||
|     string_init(modulation_str); |     string_init(modulation_str); | ||||||
| 
 | 
 | ||||||
|     char delete_str[64]; |     char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; | ||||||
|     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name); |     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( |     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( |     widget_add_string_element( | ||||||
|         subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); |         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; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubGhzCustomEventSceneDeleteRAW) { |         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)) { |             if(subghz_delete_file(subghz)) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); | ||||||
|             } else { |             } else { | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexEdit) { |         } 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( |             scene_manager_set_scene_state( | ||||||
|                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); |                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov