Merge branch 'dev' into release-candidate
This commit is contained in:
		
						commit
						dad1b0622b
					
				
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @ -49,14 +49,14 @@ firmware_clean: | |||||||
| 
 | 
 | ||||||
| .PHONY: bootloader_flash | .PHONY: bootloader_flash | ||||||
| bootloader_flash: | bootloader_flash: | ||||||
| ifeq ($(FORCE), '1') | ifeq ($(FORCE), 1) | ||||||
| 	rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true | 	rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true | ||||||
| endif | endif | ||||||
| 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash | 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash | ||||||
| 
 | 
 | ||||||
| .PHONY: firmware_flash | .PHONY: firmware_flash | ||||||
| firmware_flash: | firmware_flash: | ||||||
| ifeq ($(FORCE), '1') | ifeq ($(FORCE), 1) | ||||||
| 	rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true | 	rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true | ||||||
| endif | endif | ||||||
| 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash | 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash | ||||||
|  | |||||||
| @ -65,55 +65,55 @@ extern int32_t power_settings_app(void* p); | |||||||
| const FlipperApplication FLIPPER_SERVICES[] = { | const FlipperApplication FLIPPER_SERVICES[] = { | ||||||
| /* Services */ | /* Services */ | ||||||
| #ifdef SRV_RPC | #ifdef SRV_RPC | ||||||
|     {.app = rpc_srv, .name = "RPC", .stack_size = 1024 * 4, .icon = NULL}, |     {.app = rpc_srv, .name = "RpcSrv", .stack_size = 1024 * 4, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_BT | #ifdef SRV_BT | ||||||
|     {.app = bt_srv, .name = "BT", .stack_size = 1024, .icon = NULL}, |     {.app = bt_srv, .name = "BtSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_CLI | #ifdef SRV_CLI | ||||||
|     {.app = cli_srv, .name = "Cli", .stack_size = 4096, .icon = NULL}, |     {.app = cli_srv, .name = "CliSrv", .stack_size = 4096, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_DIALOGS | #ifdef SRV_DIALOGS | ||||||
|     {.app = dialogs_srv, .name = "Dialogs", .stack_size = 1024, .icon = NULL}, |     {.app = dialogs_srv, .name = "DialogsSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_DOLPHIN | #ifdef SRV_DOLPHIN | ||||||
|     {.app = dolphin_srv, .name = "Dolphin", .stack_size = 1024, .icon = NULL}, |     {.app = dolphin_srv, .name = "DolphinSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_DESKTOP | #ifdef SRV_DESKTOP | ||||||
|     {.app = desktop_srv, .name = "Desktop", .stack_size = 1024, .icon = NULL}, |     {.app = desktop_srv, .name = "DesktopSrv", .stack_size = 2048, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_GUI | #ifdef SRV_GUI | ||||||
|     {.app = gui_srv, .name = "Gui", .stack_size = 8192, .icon = NULL}, |     {.app = gui_srv, .name = "GuiSrv", .stack_size = 2048, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_INPUT | #ifdef SRV_INPUT | ||||||
|     {.app = input_srv, .name = "Input", .stack_size = 1024, .icon = NULL}, |     {.app = input_srv, .name = "InputSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_LOADER | #ifdef SRV_LOADER | ||||||
|     {.app = loader_srv, .name = "Loader", .stack_size = 1024, .icon = NULL}, |     {.app = loader_srv, .name = "LoaderSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_NOTIFICATION | #ifdef SRV_NOTIFICATION | ||||||
|     {.app = notification_srv, .name = "Notification", .stack_size = 1024, .icon = NULL}, |     {.app = notification_srv, .name = "NotificationSrv", .stack_size = 1536, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_POWER | #ifdef SRV_POWER | ||||||
|     {.app = power_srv, .name = "Power", .stack_size = 1024, .icon = NULL}, |     {.app = power_srv, .name = "PowerSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_POWER_OBSERVER | #ifdef SRV_POWER_OBSERVER | ||||||
|     {.app = power_observer_srv, .name = "PowerObserver", .stack_size = 1024, .icon = NULL}, |     {.app = power_observer_srv, .name = "PowerAuditSrv", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef SRV_STORAGE | #ifdef SRV_STORAGE | ||||||
|     {.app = storage_srv, .name = "Storage", .stack_size = 4096, .icon = NULL}, |     {.app = storage_srv, .name = "StorageSrv", .stack_size = 3072, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -231,6 +231,10 @@ endif | |||||||
| SRV_RPC ?= 0 | SRV_RPC ?= 0 | ||||||
| ifeq ($(SRV_RPC), 1) | ifeq ($(SRV_RPC), 1) | ||||||
| CFLAGS		+= -DSRV_RPC | CFLAGS		+= -DSRV_RPC | ||||||
|  | ifeq ($(SRV_RPC_DEBUG), 1) | ||||||
|  | CFLAGS		+= -DSRV_RPC_DEBUG | ||||||
|  | endif | ||||||
|  | SRV_CLI		= 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| SRV_LOADER ?= 0 | SRV_LOADER ?= 0 | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "archive_files.h" | #include "archive_files.h" | ||||||
| #include "archive_browser.h" | #include "archive_browser.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "Archive" | ||||||
|  | 
 | ||||||
| bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { | bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { | ||||||
|     furi_assert(file_info); |     furi_assert(file_info); | ||||||
|     furi_assert(tab_ext); |     furi_assert(tab_ext); | ||||||
| @ -147,11 +149,11 @@ void archive_file_append(const char* path, const char* format, ...) { | |||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     FileWorker* file_worker = file_worker_alloc(false); | ||||||
| 
 | 
 | ||||||
|     if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { |     if(!file_worker_open(file_worker, path, FSAM_WRITE, FSOM_OPEN_APPEND)) { | ||||||
|         FURI_LOG_E("Archive", "Append open error"); |         FURI_LOG_E(TAG, "Append open error"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { |     if(!file_worker_write(file_worker, string_get_cstr(string), string_size(string))) { | ||||||
|         FURI_LOG_E("Archive", "Append write error"); |         FURI_LOG_E(TAG, "Append write error"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     file_worker_close(file_worker); |     file_worker_close(file_worker); | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include "battery_service.h" | #include "battery_service.h" | ||||||
| #include "bt_keys_storage.h" | #include "bt_keys_storage.h" | ||||||
| 
 | 
 | ||||||
| #define BT_SERVICE_TAG "BT" | #define TAG "BtSrv" | ||||||
| 
 | 
 | ||||||
| static void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | static void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -81,14 +81,15 @@ Bt* bt_alloc() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Called from GAP thread from Serial service
 | // Called from GAP thread from Serial service
 | ||||||
| static void bt_on_data_received_callback(uint8_t* data, uint16_t size, void* context) { | static uint16_t bt_on_data_received_callback(uint8_t* data, uint16_t size, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Bt* bt = context; |     Bt* bt = context; | ||||||
| 
 | 
 | ||||||
|     size_t bytes_processed = rpc_session_feed(bt->rpc_session, data, size, 1000); |     size_t bytes_processed = rpc_session_feed(bt->rpc_session, data, size, 1000); | ||||||
|     if(bytes_processed != size) { |     if(bytes_processed != size) { | ||||||
|         FURI_LOG_E(BT_SERVICE_TAG, "Only %d of %d bytes processed by RPC", bytes_processed, size); |         FURI_LOG_E(TAG, "Only %d of %d bytes processed by RPC", bytes_processed, size); | ||||||
|     } |     } | ||||||
|  |     return rpc_session_get_available_size(bt->rpc_session); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Called from GAP thread from Serial service
 | // Called from GAP thread from Serial service
 | ||||||
| @ -118,6 +119,11 @@ static void bt_rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t byt | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void bt_rpc_buffer_is_empty_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     furi_hal_bt_notify_buffer_is_empty(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Called from GAP thread
 | // Called from GAP thread
 | ||||||
| static void bt_on_gap_event_callback(BleEvent event, void* context) { | static void bt_on_gap_event_callback(BleEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -129,12 +135,13 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { | |||||||
|         BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; |         BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; | ||||||
|         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); |         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|         // Open RPC session
 |         // Open RPC session
 | ||||||
|         FURI_LOG_I(BT_SERVICE_TAG, "Open RPC connection"); |         FURI_LOG_I(TAG, "Open RPC connection"); | ||||||
|         bt->rpc_session = rpc_session_open(bt->rpc); |         bt->rpc_session = rpc_session_open(bt->rpc); | ||||||
|         rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback); |         rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback); | ||||||
|  |         rpc_session_set_buffer_is_empty_callback(bt->rpc_session, bt_rpc_buffer_is_empty_callback); | ||||||
|         rpc_session_set_context(bt->rpc_session, bt); |         rpc_session_set_context(bt->rpc_session, bt); | ||||||
|         furi_hal_bt_set_data_event_callbacks( |         furi_hal_bt_set_data_event_callbacks( | ||||||
|             bt_on_data_received_callback, bt_on_data_sent_callback, bt); |             RPC_BUFFER_SIZE, bt_on_data_received_callback, bt_on_data_sent_callback, bt); | ||||||
|         // Update battery level
 |         // Update battery level
 | ||||||
|         PowerInfo info; |         PowerInfo info; | ||||||
|         power_get_info(bt->power, &info); |         power_get_info(bt->power, &info); | ||||||
| @ -142,7 +149,7 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { | |||||||
|         message.data.battery_level = info.charge; |         message.data.battery_level = info.charge; | ||||||
|         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); |         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
|     } else if(event.type == BleEventTypeDisconnected) { |     } else if(event.type == BleEventTypeDisconnected) { | ||||||
|         FURI_LOG_I(BT_SERVICE_TAG, "Close RPC connection"); |         FURI_LOG_I(TAG, "Close RPC connection"); | ||||||
|         if(bt->rpc_session) { |         if(bt->rpc_session) { | ||||||
|             rpc_session_close(bt->rpc_session); |             rpc_session_close(bt->rpc_session); | ||||||
|             bt->rpc_session = NULL; |             bt->rpc_session = NULL; | ||||||
| @ -165,7 +172,7 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { | |||||||
| static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) { | static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Bt* bt = context; |     Bt* bt = context; | ||||||
|     FURI_LOG_I(BT_SERVICE_TAG, "Changed addr start: %08lX, size changed: %d", addr, size); |     FURI_LOG_I(TAG, "Changed addr start: %08lX, size changed: %d", addr, size); | ||||||
|     BtMessage message = {.type = BtMessageTypeKeysStorageUpdated}; |     BtMessage message = {.type = BtMessageTypeKeysStorageUpdated}; | ||||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); |     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||||
| } | } | ||||||
| @ -188,20 +195,20 @@ int32_t bt_srv() { | |||||||
| 
 | 
 | ||||||
|     // Read keys
 |     // Read keys
 | ||||||
|     if(!bt_load_key_storage(bt)) { |     if(!bt_load_key_storage(bt)) { | ||||||
|         FURI_LOG_W(BT_SERVICE_TAG, "Failed to load saved bonding keys"); |         FURI_LOG_W(TAG, "Failed to load saved bonding keys"); | ||||||
|     } |     } | ||||||
|     // Start 2nd core
 |     // Start 2nd core
 | ||||||
|     if(!furi_hal_bt_start_core2()) { |     if(!furi_hal_bt_start_core2()) { | ||||||
|         FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); |         FURI_LOG_E(TAG, "Core2 startup failed"); | ||||||
|     } else { |     } else { | ||||||
|         view_port_enabled_set(bt->statusbar_view_port, true); |         view_port_enabled_set(bt->statusbar_view_port, true); | ||||||
|         if(furi_hal_bt_init_app(bt_on_gap_event_callback, bt)) { |         if(furi_hal_bt_init_app(bt_on_gap_event_callback, bt)) { | ||||||
|             FURI_LOG_I(BT_SERVICE_TAG, "BLE stack started"); |             FURI_LOG_I(TAG, "BLE stack started"); | ||||||
|             if(bt->bt_settings.enabled) { |             if(bt->bt_settings.enabled) { | ||||||
|                 furi_hal_bt_start_advertising(); |                 furi_hal_bt_start_advertising(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_E(BT_SERVICE_TAG, "BT App start failed"); |             FURI_LOG_E(TAG, "BT App start failed"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); |     furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt); | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <file-worker.h> | #include <file-worker.h> | ||||||
| 
 | 
 | ||||||
| #define BT_SETTINGS_TAG "bt settings" | #define TAG "BtSettings" | ||||||
| #define BT_SETTINGS_PATH "/int/bt.settings" | #define BT_SETTINGS_PATH "/int/bt.settings" | ||||||
| 
 | 
 | ||||||
| bool bt_settings_load(BtSettings* bt_settings) { | bool bt_settings_load(BtSettings* bt_settings) { | ||||||
| @ -10,7 +10,7 @@ bool bt_settings_load(BtSettings* bt_settings) { | |||||||
|     bool file_loaded = false; |     bool file_loaded = false; | ||||||
|     BtSettings settings = {}; |     BtSettings settings = {}; | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(BT_SETTINGS_TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); |     FURI_LOG_I(TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); | ||||||
|     FileWorker* file_worker = file_worker_alloc(true); |     FileWorker* file_worker = file_worker_alloc(true); | ||||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { |     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|         if(file_worker_read(file_worker, &settings, sizeof(settings))) { |         if(file_worker_read(file_worker, &settings, sizeof(settings))) { | ||||||
| @ -20,16 +20,16 @@ bool bt_settings_load(BtSettings* bt_settings) { | |||||||
|     file_worker_free(file_worker); |     file_worker_free(file_worker); | ||||||
| 
 | 
 | ||||||
|     if(file_loaded) { |     if(file_loaded) { | ||||||
|         FURI_LOG_I(BT_SETTINGS_TAG, "Settings load success"); |         FURI_LOG_I(TAG, "Settings load success"); | ||||||
|         if(settings.version != BT_SETTINGS_VERSION) { |         if(settings.version != BT_SETTINGS_VERSION) { | ||||||
|             FURI_LOG_E(BT_SETTINGS_TAG, "Settings version mismatch"); |             FURI_LOG_E(TAG, "Settings version mismatch"); | ||||||
|         } else { |         } else { | ||||||
|             osKernelLock(); |             osKernelLock(); | ||||||
|             *bt_settings = settings; |             *bt_settings = settings; | ||||||
|             osKernelUnlock(); |             osKernelUnlock(); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E(BT_SETTINGS_TAG, "Settings load failed"); |         FURI_LOG_E(TAG, "Settings load failed"); | ||||||
|     } |     } | ||||||
|     return file_loaded; |     return file_loaded; | ||||||
| } | } | ||||||
| @ -41,7 +41,7 @@ bool bt_settings_save(BtSettings* bt_settings) { | |||||||
|     FileWorker* file_worker = file_worker_alloc(true); |     FileWorker* file_worker = file_worker_alloc(true); | ||||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { |     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { | ||||||
|         if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) { |         if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) { | ||||||
|             FURI_LOG_I(BT_SETTINGS_TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); |             FURI_LOG_I(TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); | ||||||
|             result = true; |             result = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,6 +6,9 @@ | |||||||
| #include <furi-hal-usb-hid.h> | #include <furi-hal-usb-hid.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "BadUsb" | ||||||
|  | #define WORKER_TAG TAG "Worker" | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     EventTypeInput, |     EventTypeInput, | ||||||
|     EventTypeWorkerState, |     EventTypeWorkerState, | ||||||
| @ -191,7 +194,7 @@ static bool ducky_parse_line(string_t line, BadUsbParams* app) { | |||||||
| 
 | 
 | ||||||
| static void badusb_worker(void* context) { | static void badusb_worker(void* context) { | ||||||
|     BadUsbParams* app = context; |     BadUsbParams* app = context; | ||||||
|     FURI_LOG_I("BadUSB worker", "Init"); |     FURI_LOG_I(WORKER_TAG, "Init"); | ||||||
|     File* script_file = storage_file_alloc(furi_record_open("storage")); |     File* script_file = storage_file_alloc(furi_record_open("storage")); | ||||||
|     BadUsbEvent evt; |     BadUsbEvent evt; | ||||||
|     string_t line; |     string_t line; | ||||||
| @ -203,7 +206,7 @@ static void badusb_worker(void* context) { | |||||||
|         uint32_t flags = |         uint32_t flags = | ||||||
|             osThreadFlagsWait(WorkerCmdStart | WorkerCmdStop, osFlagsWaitAny, osWaitForever); |             osThreadFlagsWait(WorkerCmdStart | WorkerCmdStop, osFlagsWaitAny, osWaitForever); | ||||||
|         if(flags & WorkerCmdStart) { |         if(flags & WorkerCmdStart) { | ||||||
|             FURI_LOG_I("BadUSB worker", "Start"); |             FURI_LOG_I(WORKER_TAG, "Start"); | ||||||
|             do { |             do { | ||||||
|                 ret = storage_file_read(script_file, buffer, 16); |                 ret = storage_file_read(script_file, buffer, 16); | ||||||
|                 for(uint16_t i = 0; i < ret; i++) { |                 for(uint16_t i = 0; i < ret; i++) { | ||||||
| @ -211,7 +214,7 @@ static void badusb_worker(void* context) { | |||||||
|                         line_cnt++; |                         line_cnt++; | ||||||
|                         if(ducky_parse_line(line, app) == false) { |                         if(ducky_parse_line(line, app) == false) { | ||||||
|                             ret = 0; |                             ret = 0; | ||||||
|                             FURI_LOG_E("BadUSB worker", "Unknown command at line %lu", line_cnt); |                             FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", line_cnt); | ||||||
|                             evt.type = EventTypeWorkerState; |                             evt.type = EventTypeWorkerState; | ||||||
|                             evt.worker.state = WorkerStateScriptError; |                             evt.worker.state = WorkerStateScriptError; | ||||||
|                             evt.worker.line = line_cnt; |                             evt.worker.line = line_cnt; | ||||||
| @ -231,7 +234,7 @@ static void badusb_worker(void* context) { | |||||||
|             } while(ret > 0); |             } while(ret > 0); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E("BadUSB worker", "Script file open error"); |         FURI_LOG_E(WORKER_TAG, "Script file open error"); | ||||||
|         evt.type = EventTypeWorkerState; |         evt.type = EventTypeWorkerState; | ||||||
|         evt.worker.state = WorkerStateNoFile; |         evt.worker.state = WorkerStateNoFile; | ||||||
|         osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); |         osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); | ||||||
| @ -243,7 +246,7 @@ static void badusb_worker(void* context) { | |||||||
|     storage_file_close(script_file); |     storage_file_close(script_file); | ||||||
|     storage_file_free(script_file); |     storage_file_free(script_file); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("BadUSB worker", "End"); |     FURI_LOG_I(WORKER_TAG, "End"); | ||||||
|     evt.type = EventTypeWorkerState; |     evt.type = EventTypeWorkerState; | ||||||
|     evt.worker.state = WorkerStateDone; |     evt.worker.state = WorkerStateDone; | ||||||
|     osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); |     osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); | ||||||
| @ -324,7 +327,7 @@ int32_t bad_usb_app(void* p) { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } else if(event.type == EventTypeWorkerState) { |             } else if(event.type == EventTypeWorkerState) { | ||||||
|                 FURI_LOG_I("BadUSB app", "ev: %d", event.worker.state); |                 FURI_LOG_I(TAG, "ev: %d", event.worker.state); | ||||||
|                 if(event.worker.state == WorkerStateDone) { |                 if(event.worker.state == WorkerStateDone) { | ||||||
|                     worker_running = false; |                     worker_running = false; | ||||||
|                     if(app_state == AppStateExit) |                     if(app_state == AppStateExit) | ||||||
|  | |||||||
| @ -14,6 +14,8 @@ | |||||||
| 
 | 
 | ||||||
| #include "view_display_test.h" | #include "view_display_test.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "DisplayTest" | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
| @ -77,7 +79,7 @@ static uint32_t display_test_exit_callback(void* context) { | |||||||
| 
 | 
 | ||||||
| static void display_test_reload_config(DisplayTest* instance) { | static void display_test_reload_config(DisplayTest* instance) { | ||||||
|     FURI_LOG_I( |     FURI_LOG_I( | ||||||
|         "DisplayTest", |         TAG, | ||||||
|         "contrast: %d, regulation_ratio: %d, bias: %d", |         "contrast: %d, regulation_ratio: %d, bias: %d", | ||||||
|         instance->config_contrast, |         instance->config_contrast, | ||||||
|         instance->config_regulation_ratio, |         instance->config_regulation_ratio, | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ | |||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "KeypadTest" | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     bool press[5]; |     bool press[5]; | ||||||
|     uint16_t up; |     uint16_t up; | ||||||
| @ -80,7 +82,7 @@ int32_t keypad_test_app(void* p) { | |||||||
| 
 | 
 | ||||||
|     ValueMutex state_mutex; |     ValueMutex state_mutex; | ||||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) { |     if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) { | ||||||
|         FURI_LOG_E("KeypadTest", "cannot create mutex"); |         FURI_LOG_E(TAG, "cannot create mutex"); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -101,7 +103,7 @@ int32_t keypad_test_app(void* p) { | |||||||
|         if(event_status == osOK) { |         if(event_status == osOK) { | ||||||
|             if(event.type == EventTypeInput) { |             if(event.type == EventTypeInput) { | ||||||
|                 FURI_LOG_I( |                 FURI_LOG_I( | ||||||
|                     "KeypadTest", |                     TAG, | ||||||
|                     "key: %s type: %s", |                     "key: %s type: %s", | ||||||
|                     input_get_key_name(event.input.key), |                     input_get_key_name(event.input.key), | ||||||
|                     input_get_type_name(event.input.type)); |                     input_get_type_name(event.input.type)); | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "desktop_animation.h" | #include "desktop_animation.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "DesktopAnimation" | ||||||
|  | 
 | ||||||
| static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | ||||||
| 
 | 
 | ||||||
| const Icon* desktop_get_icon() { | const Icon* desktop_get_icon() { | ||||||
| @ -12,10 +14,10 @@ const Icon* desktop_get_icon() { | |||||||
|     DolphinStats stats = dolphin_stats(dolphin); |     DolphinStats stats = dolphin_stats(dolphin); | ||||||
|     float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp())); |     float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp())); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("desktop-animation", "background change"); |     FURI_LOG_I(TAG, "background change"); | ||||||
|     FURI_LOG_I("desktop-animation", "icounter: %d", stats.icounter); |     FURI_LOG_I(TAG, "icounter: %d", stats.icounter); | ||||||
|     FURI_LOG_I("desktop-animation", "butthurt: %d", stats.butthurt); |     FURI_LOG_I(TAG, "butthurt: %d", stats.butthurt); | ||||||
|     FURI_LOG_I("desktop-animation", "time since deeed: %.0f", timediff); |     FURI_LOG_I(TAG, "time since deeed: %.0f", timediff); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     if((random() % 100) > 50) { // temp rnd selection
 |     if((random() % 100) > 50) { // temp rnd selection
 | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "view-holder.h" | #include "view-holder.h" | ||||||
| #include <gui/view_i.h> | #include <gui/view_i.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "ViewHolder" | ||||||
|  | 
 | ||||||
| struct ViewHolder { | struct ViewHolder { | ||||||
|     View* view; |     View* view; | ||||||
|     ViewPort* view_port; |     ViewPort* view_port; | ||||||
| @ -125,7 +127,7 @@ static void view_holder_input_callback(InputEvent* event, void* context) { | |||||||
|         view_holder->ongoing_input &= ~key_bit; |         view_holder->ongoing_input &= ~key_bit; | ||||||
|     } else if(!(view_holder->ongoing_input & key_bit)) { |     } else if(!(view_holder->ongoing_input & key_bit)) { | ||||||
|         FURI_LOG_W( |         FURI_LOG_W( | ||||||
|             "ViewHolder", |             TAG, | ||||||
|             "non-complementary input, discarding key: %s, type: %s", |             "non-complementary input, discarding key: %s, type: %s", | ||||||
|             input_get_key_name(event->key), |             input_get_key_name(event->key), | ||||||
|             input_get_type_name(event->type)); |             input_get_type_name(event->type)); | ||||||
|  | |||||||
| @ -82,7 +82,7 @@ static void dolphin_check_butthurt(DolphinState* state) { | |||||||
|     float diff_time = difftime(dolphin_state_get_timestamp(state), dolphin_state_timestamp()); |     float diff_time = difftime(dolphin_state_get_timestamp(state), dolphin_state_timestamp()); | ||||||
| 
 | 
 | ||||||
|     if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { |     if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { | ||||||
|         FURI_LOG_I("dolphin-state", "Increasing butthurt"); |         FURI_LOG_I("DolphinState", "Increasing butthurt"); | ||||||
|         dolphin_state_butthurted(state); |         dolphin_state_butthurted(state); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <toolbox/saved_struct.h> | #include <toolbox/saved_struct.h> | ||||||
| 
 | 
 | ||||||
| #define DOLPHIN_STATE_TAG "DolphinState" | #define TAG "DolphinState" | ||||||
| #define DOLPHIN_STATE_PATH "/int/dolphin.state" | #define DOLPHIN_STATE_PATH "/int/dolphin.state" | ||||||
| #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 | #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 | ||||||
| #define DOLPHIN_STATE_HEADER_VERSION 0x01 | #define DOLPHIN_STATE_HEADER_VERSION 0x01 | ||||||
| @ -48,10 +48,10 @@ bool dolphin_state_save(DolphinState* dolphin_state) { | |||||||
|         DOLPHIN_STATE_HEADER_VERSION); |         DOLPHIN_STATE_HEADER_VERSION); | ||||||
| 
 | 
 | ||||||
|     if(result) { |     if(result) { | ||||||
|         FURI_LOG_I(DOLPHIN_STATE_TAG, "State saved"); |         FURI_LOG_I(TAG, "State saved"); | ||||||
|         dolphin_state->dirty = false; |         dolphin_state->dirty = false; | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E(DOLPHIN_STATE_TAG, "Failed to save state"); |         FURI_LOG_E(TAG, "Failed to save state"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return result; |     return result; | ||||||
| @ -66,7 +66,7 @@ bool dolphin_state_load(DolphinState* dolphin_state) { | |||||||
|         DOLPHIN_STATE_HEADER_VERSION); |         DOLPHIN_STATE_HEADER_VERSION); | ||||||
| 
 | 
 | ||||||
|     if(!loaded) { |     if(!loaded) { | ||||||
|         FURI_LOG_W(DOLPHIN_STATE_TAG, "Reset dolphin-state"); |         FURI_LOG_W(TAG, "Reset dolphin-state"); | ||||||
|         memset(dolphin_state, 0, sizeof(*dolphin_state)); |         memset(dolphin_state, 0, sizeof(*dolphin_state)); | ||||||
|         dolphin_state->dirty = true; |         dolphin_state->dirty = true; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,11 +8,12 @@ | |||||||
| #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) | #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     WorkerEvtStop = (1 << 0), |     WorkerEvtReserved = (1 << 0), // Reserved for StreamBuffer internal event
 | ||||||
|     WorkerEvtRxDone = (1 << 1), |     WorkerEvtStop = (1 << 1), | ||||||
|  |     WorkerEvtRxDone = (1 << 2), | ||||||
| 
 | 
 | ||||||
|     WorkerEvtTxStop = (1 << 2), |     WorkerEvtTxStop = (1 << 3), | ||||||
|     WorkerEvtCdcRx = (1 << 3), |     WorkerEvtCdcRx = (1 << 4), | ||||||
| } WorkerEvtFlags; | } WorkerEvtFlags; | ||||||
| 
 | 
 | ||||||
| #define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone) | #define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone) | ||||||
| @ -75,7 +76,7 @@ static int32_t usb_uart_worker(void* context) { | |||||||
|     usb_uart->usb_mutex = osMutexNew(NULL); |     usb_uart->usb_mutex = osMutexNew(NULL); | ||||||
| 
 | 
 | ||||||
|     usb_uart->tx_thread = furi_thread_alloc(); |     usb_uart->tx_thread = furi_thread_alloc(); | ||||||
|     furi_thread_set_name(usb_uart->tx_thread, "usb_uart_tx"); |     furi_thread_set_name(usb_uart->tx_thread, "UsbUartTxWorker"); | ||||||
|     furi_thread_set_stack_size(usb_uart->tx_thread, 512); |     furi_thread_set_stack_size(usb_uart->tx_thread, 512); | ||||||
|     furi_thread_set_context(usb_uart->tx_thread, NULL); |     furi_thread_set_context(usb_uart->tx_thread, NULL); | ||||||
|     furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); |     furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); | ||||||
| @ -191,7 +192,7 @@ void usb_uart_enable(UsbUartConfig* cfg) { | |||||||
|         usb_uart = furi_alloc(sizeof(UsbUartParams)); |         usb_uart = furi_alloc(sizeof(UsbUartParams)); | ||||||
| 
 | 
 | ||||||
|         usb_uart->thread = furi_thread_alloc(); |         usb_uart->thread = furi_thread_alloc(); | ||||||
|         furi_thread_set_name(usb_uart->thread, "usb_uart"); |         furi_thread_set_name(usb_uart->thread, "UsbUartWorker"); | ||||||
|         furi_thread_set_stack_size(usb_uart->thread, 1024); |         furi_thread_set_stack_size(usb_uart->thread, 1024); | ||||||
|         furi_thread_set_context(usb_uart->thread, cfg); |         furi_thread_set_context(usb_uart->thread, cfg); | ||||||
|         furi_thread_set_callback(usb_uart->thread, usb_uart_worker); |         furi_thread_set_callback(usb_uart->thread, usb_uart_worker); | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "gui_i.h" | #include "gui_i.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "GuiSrv" | ||||||
|  | 
 | ||||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ||||||
|     // Iterating backward
 |     // Iterating backward
 | ||||||
|     ViewPortArray_it_t it; |     ViewPortArray_it_t it; | ||||||
| @ -190,7 +192,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|         gui->ongoing_input |= key_bit; |         gui->ongoing_input |= key_bit; | ||||||
|     } else if(!(gui->ongoing_input & key_bit)) { |     } else if(!(gui->ongoing_input & key_bit)) { | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             "Gui", |             TAG, | ||||||
|             "non-complementary input, discarding key: %s type: %s, sequence: %p", |             "non-complementary input, discarding key: %s type: %s, sequence: %p", | ||||||
|             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), | ||||||
| @ -212,7 +214,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|         view_port_input(view_port, input_event); |         view_port_input(view_port, input_event); | ||||||
|     } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { |     } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             "Gui", |             TAG, | ||||||
|             "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", |             "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|             gui->ongoing_input_view_port, |             gui->ongoing_input_view_port, | ||||||
|             view_port, |             view_port, | ||||||
| @ -222,7 +224,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { | |||||||
|         view_port_input(gui->ongoing_input_view_port, input_event); |         view_port_input(gui->ongoing_input_view_port, input_event); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             "Gui", |             TAG, | ||||||
|             "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", |             "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", | ||||||
|             gui->ongoing_input_view_port, |             gui->ongoing_input_view_port, | ||||||
|             view_port, |             view_port, | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| #include "view_dispatcher_i.h" | #include "view_dispatcher_i.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "ViewDispatcher" | ||||||
|  | 
 | ||||||
| ViewDispatcher* view_dispatcher_alloc() { | ViewDispatcher* view_dispatcher_alloc() { | ||||||
|     ViewDispatcher* view_dispatcher = furi_alloc(sizeof(ViewDispatcher)); |     ViewDispatcher* view_dispatcher = furi_alloc(sizeof(ViewDispatcher)); | ||||||
| 
 | 
 | ||||||
| @ -237,7 +239,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e | |||||||
|         view_dispatcher->ongoing_input &= ~key_bit; |         view_dispatcher->ongoing_input &= ~key_bit; | ||||||
|     } else if(!(view_dispatcher->ongoing_input & key_bit)) { |     } else if(!(view_dispatcher->ongoing_input & key_bit)) { | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             "ViewDispatcher", |             TAG, | ||||||
|             "non-complementary input, discarding key: %s, type: %s, sequence: %p", |             "non-complementary input, discarding key: %s, type: %s, sequence: %p", | ||||||
|             input_get_key_name(event->key), |             input_get_key_name(event->key), | ||||||
|             input_get_type_name(event->type), |             input_get_type_name(event->type), | ||||||
| @ -276,7 +278,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e | |||||||
|         } |         } | ||||||
|     } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { |     } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) { | ||||||
|         FURI_LOG_D( |         FURI_LOG_D( | ||||||
|             "ViewDispatcher", |             TAG, | ||||||
|             "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", |             "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||||
|             view_dispatcher->ongoing_input_view, |             view_dispatcher->ongoing_input_view, | ||||||
|             view_dispatcher->current_view, |             view_dispatcher->current_view, | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ | |||||||
| #include <furi-hal-irda.h> | #include <furi-hal-irda.h> | ||||||
| #include <file-worker-cpp.h> | #include <file-worker-cpp.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "IrdaFileParser" | ||||||
|  | 
 | ||||||
| bool IrdaAppFileParser::open_irda_file_read(const char* name) { | bool IrdaAppFileParser::open_irda_file_read(const char* name) { | ||||||
|     std::string full_filename; |     std::string full_filename; | ||||||
|     if(name[0] != '/') |     if(name[0] != '/') | ||||||
| @ -154,11 +156,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if(!irda_is_protocol_valid((IrdaProtocol)protocol)) { |     if(!irda_is_protocol_valid((IrdaProtocol)protocol)) { | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             "IrdaFileParser", |             TAG, "Unknown protocol(\'%.*s...\'): \'%s\'", end_of_str, str.c_str(), protocol_name); | ||||||
|             "Unknown protocol(\'%.*s...\'): \'%s\'", |  | ||||||
|             end_of_str, |  | ||||||
|             str.c_str(), |  | ||||||
|             protocol_name); |  | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -167,7 +165,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if(address != (address & address_mask)) { |     if(address != (address & address_mask)) { | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             "IrdaFileParser", |             TAG, | ||||||
|             "Signal(\'%.*s...\'): address is too long (mask for this protocol is 0x%08X): 0x%X", |             "Signal(\'%.*s...\'): address is too long (mask for this protocol is 0x%08X): 0x%X", | ||||||
|             end_of_str, |             end_of_str, | ||||||
|             str.c_str(), |             str.c_str(), | ||||||
| @ -181,7 +179,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if(command != (command & command_mask)) { |     if(command != (command & command_mask)) { | ||||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); |         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             "IrdaFileParser", |             TAG, | ||||||
|             "Signal(\'%.*s...\'): command is too long (mask for this protocol is 0x%08X): 0x%X", |             "Signal(\'%.*s...\'): command is too long (mask for this protocol is 0x%08X): 0x%X", | ||||||
|             end_of_str, |             end_of_str, | ||||||
|             str.c_str(), |             str.c_str(), | ||||||
| @ -256,7 +254,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if((frequency < IRDA_MIN_FREQUENCY) || (frequency > IRDA_MAX_FREQUENCY)) { |     if((frequency < IRDA_MIN_FREQUENCY) || (frequency > IRDA_MAX_FREQUENCY)) { | ||||||
|         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); |         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             "IrdaFileParser", |             TAG, | ||||||
|             "RAW signal(\'%.*s...\'): frequency is out of bounds (%ld-%ld): %ld", |             "RAW signal(\'%.*s...\'): frequency is out of bounds (%ld-%ld): %ld", | ||||||
|             end_of_str, |             end_of_str, | ||||||
|             string.c_str(), |             string.c_str(), | ||||||
| @ -269,7 +267,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if((duty_cycle == 0) || (duty_cycle > 100)) { |     if((duty_cycle == 0) || (duty_cycle > 100)) { | ||||||
|         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); |         size_t end_of_str = MIN(string.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||||
|         FURI_LOG_E( |         FURI_LOG_E( | ||||||
|             "IrdaFileParser", |             TAG, | ||||||
|             "RAW signal(\'%.*s...\'): duty cycle is out of bounds (0-100): %ld", |             "RAW signal(\'%.*s...\'): duty cycle is out of bounds (0-100): %ld", | ||||||
|             end_of_str, |             end_of_str, | ||||||
|             string.c_str(), |             string.c_str(), | ||||||
| @ -283,8 +281,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|     if(last_valid_ch != std::string_view::npos) { |     if(last_valid_ch != std::string_view::npos) { | ||||||
|         str.remove_suffix(str.size() - last_valid_ch - 1); |         str.remove_suffix(str.size() - last_valid_ch - 1); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E( |         FURI_LOG_E(TAG, "RAW signal(\'%.*s\'): no timings", header_len, string.c_str()); | ||||||
|             "IrdaFileParser", "RAW signal(\'%.*s\'): no timings", header_len, string.c_str()); |  | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -303,7 +300,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|         parsed = std::sscanf(str.data(), "%9s", buf); |         parsed = std::sscanf(str.data(), "%9s", buf); | ||||||
|         if(parsed != 1) { |         if(parsed != 1) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 "IrdaFileParser", |                 TAG, | ||||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%*s\'", |                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%*s\'", | ||||||
|                 header_len, |                 header_len, | ||||||
|                 string.c_str(), |                 string.c_str(), | ||||||
| @ -318,7 +315,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
|         int value = atoi(buf); |         int value = atoi(buf); | ||||||
|         if(value <= 0) { |         if(value <= 0) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 "IrdaFileParser", |                 TAG, | ||||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%s\'", |                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%s\'", | ||||||
|                 header_len, |                 header_len, | ||||||
|                 string.c_str(), |                 string.c_str(), | ||||||
| @ -330,7 +327,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | |||||||
| 
 | 
 | ||||||
|         if(raw_signal.timings_cnt >= max_raw_timings_in_signal) { |         if(raw_signal.timings_cnt >= max_raw_timings_in_signal) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 "IrdaFileParser", |                 TAG, | ||||||
|                 "RAW signal(\'%.*s...\'): too much timings (max %ld)", |                 "RAW signal(\'%.*s...\'): too much timings (max %ld)", | ||||||
|                 header_len, |                 header_len, | ||||||
|                 string.c_str(), |                 string.c_str(), | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "loader/loader.h" | #include "loader/loader.h" | ||||||
| #include "loader_i.h" | #include "loader_i.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "LoaderSrv" | ||||||
|  | 
 | ||||||
| #define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) | #define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) | ||||||
| #define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) | #define LOADER_THREAD_FLAG_ALL (LOADER_THREAD_FLAG_SHOW_MENU) | ||||||
| 
 | 
 | ||||||
| @ -15,15 +17,13 @@ static void loader_menu_callback(void* _ctx, uint32_t index) { | |||||||
|     if(!loader_lock(loader_instance)) return; |     if(!loader_lock(loader_instance)) return; | ||||||
| 
 | 
 | ||||||
|     if(furi_thread_get_state(loader_instance->thread) != FuriThreadStateStopped) { |     if(furi_thread_get_state(loader_instance->thread) != FuriThreadStateStopped) { | ||||||
|         FURI_LOG_E( |         FURI_LOG_E(TAG, "Can't start app. %s is running", loader_instance->current_app->name); | ||||||
|             LOADER_LOG_TAG, "Can't start app. %s is running", loader_instance->current_app->name); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     furi_hal_power_insomnia_enter(); |     furi_hal_power_insomnia_enter(); | ||||||
|     loader_instance->current_app = flipper_app; |     loader_instance->current_app = flipper_app; | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I( |     FURI_LOG_I(TAG, "Starting furi application: %s", loader_instance->current_app->name); | ||||||
|         LOADER_LOG_TAG, "Starting furi application: %s", loader_instance->current_app->name); |  | ||||||
|     furi_thread_set_name(loader_instance->thread, flipper_app->name); |     furi_thread_set_name(loader_instance->thread, flipper_app->name); | ||||||
|     furi_thread_set_stack_size(loader_instance->thread, flipper_app->stack_size); |     furi_thread_set_stack_size(loader_instance->thread, flipper_app->stack_size); | ||||||
|     furi_thread_set_context(loader_instance->thread, NULL); |     furi_thread_set_context(loader_instance->thread, NULL); | ||||||
| @ -79,14 +79,14 @@ LoaderStatus loader_start(Loader* instance, const char* name, const char* args) | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(!flipper_app) { |     if(!flipper_app) { | ||||||
|         FURI_LOG_E(LOADER_LOG_TAG, "Can't find application with name %s", name); |         FURI_LOG_E(TAG, "Can't find application with name %s", name); | ||||||
|         return LoaderStatusErrorUnknownApp; |         return LoaderStatusErrorUnknownApp; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool locked = loader_lock(instance); |     bool locked = loader_lock(instance); | ||||||
| 
 | 
 | ||||||
|     if(!locked || (furi_thread_get_state(instance->thread) != FuriThreadStateStopped)) { |     if(!locked || (furi_thread_get_state(instance->thread) != FuriThreadStateStopped)) { | ||||||
|         FURI_LOG_E(LOADER_LOG_TAG, "Can't start app. %s is running", instance->current_app->name); |         FURI_LOG_E(TAG, "Can't start app. %s is running", instance->current_app->name); | ||||||
|         /* no need to call loader_unlock() - it is called as soon as application stops */ |         /* no need to call loader_unlock() - it is called as soon as application stops */ | ||||||
|         return LoaderStatusErrorAppStarted; |         return LoaderStatusErrorAppStarted; | ||||||
|     } |     } | ||||||
| @ -97,10 +97,10 @@ LoaderStatus loader_start(Loader* instance, const char* name, const char* args) | |||||||
|         string_set_str(instance->args, args); |         string_set_str(instance->args, args); | ||||||
|         string_strim(instance->args); |         string_strim(instance->args); | ||||||
|         thread_args = (void*)string_get_cstr(instance->args); |         thread_args = (void*)string_get_cstr(instance->args); | ||||||
|         FURI_LOG_I(LOADER_LOG_TAG, "Start %s app with args: %s", name, args); |         FURI_LOG_I(TAG, "Start %s app with args: %s", name, args); | ||||||
|     } else { |     } else { | ||||||
|         string_clean(instance->args); |         string_clean(instance->args); | ||||||
|         FURI_LOG_I(LOADER_LOG_TAG, "Start %s app with no args", name); |         FURI_LOG_I(TAG, "Start %s app with no args", name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     furi_thread_set_name(instance->thread, flipper_app->name); |     furi_thread_set_name(instance->thread, flipper_app->name); | ||||||
| @ -155,7 +155,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con | |||||||
|         delay(20); |         delay(20); | ||||||
|         int heap_diff = instance->free_heap_size - memmgr_get_free_heap(); |         int heap_diff = instance->free_heap_size - memmgr_get_free_heap(); | ||||||
|         FURI_LOG_I( |         FURI_LOG_I( | ||||||
|             LOADER_LOG_TAG, |             TAG, | ||||||
|             "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", |             "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", | ||||||
|             heap_diff, |             heap_diff, | ||||||
|             furi_thread_get_heap_size(instance->thread)); |             furi_thread_get_heap_size(instance->thread)); | ||||||
| @ -266,7 +266,7 @@ static void loader_add_cli_command(FlipperApplication* app) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void loader_build_menu() { | static void loader_build_menu() { | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Building main menu"); |     FURI_LOG_I(TAG, "Building main menu"); | ||||||
|     size_t i; |     size_t i; | ||||||
|     for(i = 0; i < FLIPPER_APPS_COUNT; i++) { |     for(i = 0; i < FLIPPER_APPS_COUNT; i++) { | ||||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_APPS[i]); |         loader_add_cli_command((FlipperApplication*)&FLIPPER_APPS[i]); | ||||||
| @ -300,7 +300,7 @@ static void loader_build_menu() { | |||||||
|         loader_submenu_callback, |         loader_submenu_callback, | ||||||
|         (void*)LoaderMenuViewSettings); |         (void*)LoaderMenuViewSettings); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Building plugins menu"); |     FURI_LOG_I(TAG, "Building plugins menu"); | ||||||
|     for(i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { |     for(i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { | ||||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_PLUGINS[i]); |         loader_add_cli_command((FlipperApplication*)&FLIPPER_PLUGINS[i]); | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
| @ -311,7 +311,7 @@ static void loader_build_menu() { | |||||||
|             (void*)&FLIPPER_PLUGINS[i]); |             (void*)&FLIPPER_PLUGINS[i]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Building debug menu"); |     FURI_LOG_I(TAG, "Building debug menu"); | ||||||
|     for(i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { |     for(i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { | ||||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_DEBUG_APPS[i]); |         loader_add_cli_command((FlipperApplication*)&FLIPPER_DEBUG_APPS[i]); | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
| @ -322,7 +322,7 @@ static void loader_build_menu() { | |||||||
|             (void*)&FLIPPER_DEBUG_APPS[i]); |             (void*)&FLIPPER_DEBUG_APPS[i]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Building settings menu"); |     FURI_LOG_I(TAG, "Building settings menu"); | ||||||
|     for(i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { |     for(i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             loader_instance->settings_menu, |             loader_instance->settings_menu, | ||||||
| @ -339,7 +339,7 @@ void loader_show_menu() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t loader_srv(void* p) { | int32_t loader_srv(void* p) { | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Starting"); |     FURI_LOG_I(TAG, "Starting"); | ||||||
| 
 | 
 | ||||||
|     loader_instance = loader_alloc(); |     loader_instance = loader_alloc(); | ||||||
| 
 | 
 | ||||||
| @ -350,7 +350,7 @@ int32_t loader_srv(void* p) { | |||||||
|         FLIPPER_ON_SYSTEM_START[i](); |         FLIPPER_ON_SYSTEM_START[i](); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Started"); |     FURI_LOG_I(TAG, "Started"); | ||||||
| 
 | 
 | ||||||
|     furi_record_create("loader", loader_instance); |     furi_record_create("loader", loader_instance); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,8 +12,6 @@ | |||||||
| #include <applications.h> | #include <applications.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| 
 | 
 | ||||||
| #define LOADER_LOG_TAG "loader" |  | ||||||
| 
 |  | ||||||
| struct Loader { | struct Loader { | ||||||
|     osThreadId_t loader_thread; |     osThreadId_t loader_thread; | ||||||
|     FuriThread* thread; |     FuriThread* thread; | ||||||
|  | |||||||
| @ -1,49 +1,80 @@ | |||||||
| #include "nfc_emv_parser.h" | #include "nfc_emv_parser.h" | ||||||
|  | #include <lib/flipper_file/flipper_file.h> | ||||||
| 
 | 
 | ||||||
| #include <file-worker.h> | static const char* nfc_resources_header = "Flipper EMV resources"; | ||||||
|  | static const uint32_t nfc_resources_file_version = 1; | ||||||
| 
 | 
 | ||||||
| static bool | static bool nfc_emv_parser_search_data( | ||||||
|     nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) { |     Storage* storage, | ||||||
|     bool found = false; |     const char* file_name, | ||||||
|     FileWorker* file_worker = file_worker_alloc(true); |     string_t key, | ||||||
|  |     string_t data) { | ||||||
|  |     bool parsed = false; | ||||||
|  |     FlipperFile* file = flipper_file_alloc(storage); | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
| 
 | 
 | ||||||
|     if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { |     do { | ||||||
|         if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) { |         // Open file
 | ||||||
|             found = true; |         if(!flipper_file_open_existing(file, file_name)) break; | ||||||
|         } |         // Read file header and version
 | ||||||
|     } |         uint32_t version = 0; | ||||||
|  |         if(!flipper_file_read_header(file, temp_str, &version)) break; | ||||||
|  |         if(string_cmp_str(temp_str, nfc_resources_header) || | ||||||
|  |            (version != nfc_resources_file_version)) | ||||||
|  |             break; | ||||||
|  |         if(!flipper_file_read_string(file, string_get_cstr(key), data)) break; | ||||||
|  |         parsed = true; | ||||||
|  |     } while(false); | ||||||
| 
 | 
 | ||||||
|     file_worker_close(file_worker); |     string_clear(temp_str); | ||||||
|     file_worker_free(file_worker); |     flipper_file_free(file); | ||||||
|     return found; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) { | bool nfc_emv_parser_get_aid_name( | ||||||
|     bool result = false; |     Storage* storage, | ||||||
|  |     uint8_t* aid, | ||||||
|  |     uint8_t aid_len, | ||||||
|  |     string_t aid_name) { | ||||||
|  |     furi_assert(storage); | ||||||
|  |     bool parsed = false; | ||||||
|     string_t key; |     string_t key; | ||||||
|     string_init(key); |     string_init(key); | ||||||
|     for(uint8_t i = 0; i < aid_len; i++) { |     for(uint8_t i = 0; i < aid_len; i++) { | ||||||
|         string_cat_printf(key, "%02X", aid[i]); |         string_cat_printf(key, "%02X", aid[i]); | ||||||
|     } |     } | ||||||
|     result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name); |     if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/aid.nfc", key, aid_name)) { | ||||||
|  |         parsed = true; | ||||||
|  |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
|     return result; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) { | bool nfc_emv_parser_get_country_name( | ||||||
|     bool result = false; |     Storage* storage, | ||||||
|  |     uint16_t country_code, | ||||||
|  |     string_t country_name) { | ||||||
|  |     bool parsed = false; | ||||||
|     string_t key; |     string_t key; | ||||||
|     string_init_printf(key, "%04X", country_code); |     string_init_printf(key, "%04X", country_code); | ||||||
|     result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name); |     if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/country_code.nfc", key, country_name)) { | ||||||
|  |         parsed = true; | ||||||
|  |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
|     return result; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) { | bool nfc_emv_parser_get_currency_name( | ||||||
|     bool result = false; |     Storage* storage, | ||||||
|  |     uint16_t currency_code, | ||||||
|  |     string_t currency_name) { | ||||||
|  |     bool parsed = false; | ||||||
|     string_t key; |     string_t key; | ||||||
|     string_init_printf(key, "%04X", currency_code); |     string_init_printf(key, "%04X", currency_code); | ||||||
|     result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name); |     if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/currency_code.nfc", key, currency_name)) { | ||||||
|  |         parsed = true; | ||||||
|  |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
|     return result; |     return parsed; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,25 +3,39 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
|  | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
| /** Get EMV application name by number
 | /** Get EMV application name by number
 | ||||||
|  |  * @param storage Storage instance | ||||||
|  * @param aid - AID number array |  * @param aid - AID number array | ||||||
|  * @param aid_len - AID length |  * @param aid_len - AID length | ||||||
|  * @param aid_name - string to keep AID name |  * @param aid_name - string to keep AID name | ||||||
|  * @return - true if AID found, false otherwies |  * @return - true if AID found, false otherwies | ||||||
|  */ |  */ | ||||||
| bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name); | bool nfc_emv_parser_get_aid_name( | ||||||
|  |     Storage* storage, | ||||||
|  |     uint8_t* aid, | ||||||
|  |     uint8_t aid_len, | ||||||
|  |     string_t aid_name); | ||||||
| 
 | 
 | ||||||
| /** Get country name by country code
 | /** Get country name by country code
 | ||||||
|  |  * @param storage Storage instance | ||||||
|  * @param country_code - ISO 3166 country code |  * @param country_code - ISO 3166 country code | ||||||
|  * @param country_name - string to keep country name |  * @param country_name - string to keep country name | ||||||
|  * @return - true if country found, false otherwies |  * @return - true if country found, false otherwies | ||||||
|  */ |  */ | ||||||
| bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name); | bool nfc_emv_parser_get_country_name( | ||||||
|  |     Storage* storage, | ||||||
|  |     uint16_t country_code, | ||||||
|  |     string_t country_name); | ||||||
| 
 | 
 | ||||||
| /** Get currency name by currency code
 | /** Get currency name by currency code
 | ||||||
|  |  * @param storage Storage instance | ||||||
|  * @param currency_code - ISO 3166 currency code |  * @param currency_code - ISO 3166 currency code | ||||||
|  * @param currency_name - string to keep currency name |  * @param currency_name - string to keep currency name | ||||||
|  * @return - true if currency found, false otherwies |  * @return - true if currency found, false otherwies | ||||||
|  */ |  */ | ||||||
| bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name); | bool nfc_emv_parser_get_currency_name( | ||||||
|  |     Storage* storage, | ||||||
|  |     uint16_t currency_code, | ||||||
|  |     string_t currency_name); | ||||||
|  | |||||||
| @ -31,6 +31,9 @@ Nfc* nfc_alloc() { | |||||||
|     view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); |     view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); | ||||||
|     view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100); |     view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100); | ||||||
| 
 | 
 | ||||||
|  |     // Nfc device
 | ||||||
|  |     nfc->dev = nfc_device_alloc(); | ||||||
|  | 
 | ||||||
|     // Open GUI record
 |     // Open GUI record
 | ||||||
|     nfc->gui = furi_record_open("gui"); |     nfc->gui = furi_record_open("gui"); | ||||||
|     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); |     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); | ||||||
| @ -82,6 +85,9 @@ Nfc* nfc_alloc() { | |||||||
| void nfc_free(Nfc* nfc) { | void nfc_free(Nfc* nfc) { | ||||||
|     furi_assert(nfc); |     furi_assert(nfc); | ||||||
| 
 | 
 | ||||||
|  |     // Nfc device
 | ||||||
|  |     nfc_device_free(nfc->dev); | ||||||
|  | 
 | ||||||
|     // Submenu
 |     // Submenu
 | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); |     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|     submenu_free(nfc->submenu); |     submenu_free(nfc->submenu); | ||||||
| @ -154,8 +160,12 @@ 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') && nfc_device_load(nfc->dev, p)) { | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |         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, NfcSceneStart); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,45 +1,38 @@ | |||||||
| #include "nfc_device_i.h" | #include "nfc_device.h" | ||||||
| 
 | 
 | ||||||
| #include <file-worker.h> |  | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| #include <lib/toolbox/hex.h> | #include <lib/flipper_file/flipper_file.h> | ||||||
| 
 |  | ||||||
| #define NFC_DEVICE_MAX_DATA_LEN 14 |  | ||||||
| 
 | 
 | ||||||
| static const char* nfc_app_folder = "/any/nfc"; | static const char* nfc_app_folder = "/any/nfc"; | ||||||
| static const char* nfc_app_extension = ".nfc"; | static const char* nfc_app_extension = ".nfc"; | ||||||
| static const char* nfc_app_shadow_extension = ".shd"; | static const char* nfc_app_shadow_extension = ".shd"; | ||||||
|  | static const char* nfc_file_header = "Flipper NFC device"; | ||||||
|  | static const uint32_t nfc_file_version = 2; | ||||||
| 
 | 
 | ||||||
| static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len, uint8_t delim_len) { | NfcDevice* nfc_device_alloc() { | ||||||
|     string_strim(str); |     NfcDevice* nfc_dev = furi_alloc(sizeof(NfcDevice)); | ||||||
|     uint8_t nibble_high = 0; |     nfc_dev->storage = furi_record_open("storage"); | ||||||
|     uint8_t nibble_low = 0; |     nfc_dev->dialogs = furi_record_open("dialogs"); | ||||||
|     bool parsed = true; |     return nfc_dev; | ||||||
| 
 |  | ||||||
|     for(uint16_t i = 0; i < len; i++) { |  | ||||||
|         if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) && |  | ||||||
|            hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) { |  | ||||||
|             buff[i] = (nibble_high << 4) | nibble_low; |  | ||||||
|             string_right(str, delim_len + 2); |  | ||||||
|         } else { |  | ||||||
|             parsed = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return parsed; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { | void nfc_device_free(NfcDevice* nfc_dev) { | ||||||
|  |     furi_assert(nfc_dev); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     furi_record_close("dialogs"); | ||||||
|  |     free(nfc_dev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { | ||||||
|     if(dev->format == NfcDeviceSaveFormatUid) { |     if(dev->format == NfcDeviceSaveFormatUid) { | ||||||
|         string_set_str(format_string, "UID\n"); |         string_set_str(format_string, "UID"); | ||||||
|     } else if(dev->format == NfcDeviceSaveFormatBankCard) { |     } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|         string_set_str(format_string, "Bank card\n"); |         string_set_str(format_string, "Bank card"); | ||||||
|     } else if(dev->format == NfcDeviceSaveFormatMifareUl) { |     } else if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|         string_set_str(format_string, "Mifare Ultralight\n"); |         string_set_str(format_string, "Mifare Ultralight"); | ||||||
|     } else { |     } else { | ||||||
|         string_set_str(format_string, "Unknown\n"); |         string_set_str(format_string, "Unknown"); | ||||||
|     } |     } | ||||||
|     return string_size(format_string); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||||
| @ -59,228 +52,166 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | |||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { | static bool nfc_device_save_mifare_ul_data(FlipperFile* file, NfcDevice* dev) { | ||||||
|     NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data; |     bool saved = false; | ||||||
|     string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len); |  | ||||||
|     for(uint8_t i = 0; i < uid_data->uid_len; i++) { |  | ||||||
|         string_cat_printf(uid_string, "%02X ", uid_data->uid[i]); |  | ||||||
|     } |  | ||||||
|     string_cat_printf( |  | ||||||
|         uid_string, |  | ||||||
|         "ATQA: %02X %02X SAK: %02X\n", |  | ||||||
|         uid_data->atqa[0], |  | ||||||
|         uid_data->atqa[1], |  | ||||||
|         uid_data->sak); |  | ||||||
|     return string_size(uid_string); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) { |  | ||||||
|     NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data; |  | ||||||
|     bool parsed = false; |  | ||||||
| 
 |  | ||||||
|     do { |  | ||||||
|         // strlen("UID len: ") = 9
 |  | ||||||
|         string_right(uid_string, 9); |  | ||||||
|         if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // strlen("UID: ") = 5
 |  | ||||||
|         string_right(uid_string, 5); |  | ||||||
|         if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // strlen("ATQA: ") = 6
 |  | ||||||
|         string_right(uid_string, 6); |  | ||||||
|         if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // strlen("SAK: ") = 5
 |  | ||||||
|         string_right(uid_string, 5); |  | ||||||
|         if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         parsed = true; |  | ||||||
|     } while(0); |  | ||||||
| 
 |  | ||||||
|     return parsed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) { |  | ||||||
|     MifareUlData* data = &dev->dev_data.mf_ul_data; |     MifareUlData* data = &dev->dev_data.mf_ul_data; | ||||||
|     string_printf(mifare_ul_string, "Signature:"); |     string_t temp_str; | ||||||
|     for(uint8_t i = 0; i < sizeof(data->signature); i++) { |     string_init(temp_str); | ||||||
|         string_cat_printf(mifare_ul_string, " %02X", data->signature[i]); |  | ||||||
|     } |  | ||||||
|     string_cat_printf(mifare_ul_string, "\nVersion:"); |  | ||||||
|     uint8_t* version = (uint8_t*)&data->version; |  | ||||||
|     for(uint8_t i = 0; i < sizeof(data->version); i++) { |  | ||||||
|         string_cat_printf(mifare_ul_string, " %02X", version[i]); |  | ||||||
|     } |  | ||||||
|     for(uint8_t i = 0; i < 3; i++) { |  | ||||||
|         string_cat_printf( |  | ||||||
|             mifare_ul_string, |  | ||||||
|             "\nCounter %d: %lu Tearing flag %d: %02X", |  | ||||||
|             i, |  | ||||||
|             data->counter[i], |  | ||||||
|             i, |  | ||||||
|             data->tearing[i]); |  | ||||||
|     } |  | ||||||
|     string_cat_printf(mifare_ul_string, "\nData size: %d\n", data->data_size); |  | ||||||
|     for(uint16_t i = 0; i < data->data_size; i += 4) { |  | ||||||
|         string_cat_printf( |  | ||||||
|             mifare_ul_string, |  | ||||||
|             "%02X %02X %02X %02X\n", |  | ||||||
|             data->data[i], |  | ||||||
|             data->data[i + 1], |  | ||||||
|             data->data[i + 2], |  | ||||||
|             data->data[i + 3]); |  | ||||||
|     } |  | ||||||
|     return string_size(mifare_ul_string); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) { |  | ||||||
|     MifareUlData* data = &dev->dev_data.mf_ul_data; |  | ||||||
|     uint16_t tearing_tmp = 0; |  | ||||||
|     uint16_t cnt_num = 0; |  | ||||||
|     size_t ws = 0; |  | ||||||
|     int res = 0; |  | ||||||
|     bool parsed = false; |  | ||||||
| 
 | 
 | ||||||
|  |     // Save Mifare Ultralight specific data
 | ||||||
|     do { |     do { | ||||||
|         // strlen("Signature: ") = 11
 |         if(!flipper_file_write_comment_cstr(file, "Mifare Ultralight specific data")) break; | ||||||
|         string_right(mifare_ul_string, 11); |         if(!flipper_file_write_hex(file, "Signature", data->signature, sizeof(data->signature))) | ||||||
|         if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) { |  | ||||||
|             break; |             break; | ||||||
|         } |         if(!flipper_file_write_hex( | ||||||
|         // strlen("Version: ") = 9
 |                file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version))) | ||||||
|         string_right(mifare_ul_string, 9); |  | ||||||
|         if(!nfc_device_read_hex( |  | ||||||
|                mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) { |  | ||||||
|             break; |             break; | ||||||
|         } |         // Write conters and tearing flags data
 | ||||||
|         string_strim(mifare_ul_string); |         bool counters_saved = true; | ||||||
|         // Read counters and tearing flags
 |  | ||||||
|         for(uint8_t i = 0; i < 3; i++) { |         for(uint8_t i = 0; i < 3; i++) { | ||||||
|             res = sscanf( |             string_printf(temp_str, "Counter %d", i); | ||||||
|                 string_get_cstr(mifare_ul_string), |             if(!flipper_file_write_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) { | ||||||
|                 "Counter %hX: %lu Tearing flag %hX: %02hX", |                 counters_saved = false; | ||||||
|                 &cnt_num, |                 break; | ||||||
|                 &data->counter[i], |             } | ||||||
|                 &cnt_num, |             string_printf(temp_str, "Tearing %d", i); | ||||||
|                 &tearing_tmp); |             if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) { | ||||||
|             if(res != 4) { |                 counters_saved = false; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             data->tearing[i] = tearing_tmp; |  | ||||||
|             ws = string_search_char(mifare_ul_string, '\n'); |  | ||||||
|             string_right(mifare_ul_string, ws + 1); |  | ||||||
|         } |         } | ||||||
|         // Read data size
 |         if(!counters_saved) break; | ||||||
|         res = sscanf(string_get_cstr(mifare_ul_string), "Data size: %hu", &data->data_size); |         // Write pages data
 | ||||||
|         if(res != 1) { |         uint32_t pages_total = data->data_size / 4; | ||||||
|             break; |         if(!flipper_file_write_uint32(file, "Pages total", &pages_total, 1)) break; | ||||||
|         } |         bool pages_saved = true; | ||||||
|         ws = string_search_char(mifare_ul_string, '\n'); |  | ||||||
|         string_right(mifare_ul_string, ws + 1); |  | ||||||
|         // Read data
 |  | ||||||
|         for(uint16_t i = 0; i < data->data_size; i += 4) { |         for(uint16_t i = 0; i < data->data_size; i += 4) { | ||||||
|             if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4, 1)) { |             string_printf(temp_str, "Page %d", i / 4); | ||||||
|  |             if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->data[i], 4)) { | ||||||
|  |                 pages_saved = false; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         parsed = true; |         if(!pages_saved) break; | ||||||
|     } while(0); |         saved = true; | ||||||
|  |     } while(false); | ||||||
| 
 | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|  |     return saved; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_device_load_mifare_ul_data(FlipperFile* file, NfcDevice* dev) { | ||||||
|  |     bool parsed = false; | ||||||
|  |     MifareUlData* data = &dev->dev_data.mf_ul_data; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // Read signature
 | ||||||
|  |         if(!flipper_file_read_hex(file, "Signature", data->signature, sizeof(data->signature))) | ||||||
|  |             break; | ||||||
|  |         // Read Mifare version
 | ||||||
|  |         if(!flipper_file_read_hex( | ||||||
|  |                file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version))) | ||||||
|  |             break; | ||||||
|  |         // Read counters and tearing flags
 | ||||||
|  |         bool counters_parsed = true; | ||||||
|  |         for(uint8_t i = 0; i < 3; i++) { | ||||||
|  |             string_printf(temp_str, "Counter %d", i); | ||||||
|  |             if(!flipper_file_read_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) { | ||||||
|  |                 counters_parsed = false; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             string_printf(temp_str, "Tearing %d", i); | ||||||
|  |             if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) { | ||||||
|  |                 counters_parsed = false; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(!counters_parsed) break; | ||||||
|  |         // Read pages
 | ||||||
|  |         uint32_t pages = 0; | ||||||
|  |         if(!flipper_file_read_uint32(file, "Pages total", &pages, 1)) break; | ||||||
|  |         data->data_size = pages * 4; | ||||||
|  |         bool pages_parsed = true; | ||||||
|  |         for(uint16_t i = 0; i < pages; i++) { | ||||||
|  |             string_printf(temp_str, "Page %d", i); | ||||||
|  |             if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) { | ||||||
|  |                 pages_parsed = false; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(!pages_parsed) break; | ||||||
|  |         parsed = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|     return parsed; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string) { | static bool nfc_device_save_bank_card_data(FlipperFile* file, NfcDevice* dev) { | ||||||
|  |     bool saved = false; | ||||||
|     NfcEmvData* data = &dev->dev_data.emv_data; |     NfcEmvData* data = &dev->dev_data.emv_data; | ||||||
|     string_printf(bank_card_string, "AID len: %d, AID:", data->aid_len); |     uint32_t data_temp = 0; | ||||||
|     for(uint8_t i = 0; i < data->aid_len; i++) { |  | ||||||
|         string_cat_printf(bank_card_string, " %02X", data->aid[i]); |  | ||||||
|     } |  | ||||||
|     string_cat_printf( |  | ||||||
|         bank_card_string, "\nName: %s\nNumber len: %d\nNumber:", data->name, data->number_len); |  | ||||||
|     for(uint8_t i = 0; i < data->number_len; i++) { |  | ||||||
|         string_cat_printf(bank_card_string, " %02X", data->number[i]); |  | ||||||
|     } |  | ||||||
|     if(data->exp_mon) { |  | ||||||
|         string_cat_printf( |  | ||||||
|             bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year); |  | ||||||
|     } |  | ||||||
|     if(data->country_code) { |  | ||||||
|         string_cat_printf(bank_card_string, "\nCountry code: %04X", data->country_code); |  | ||||||
|     } |  | ||||||
|     if(data->currency_code) { |  | ||||||
|         string_cat_printf(bank_card_string, "\nCurrency code: %04X", data->currency_code); |  | ||||||
|     } |  | ||||||
|     return string_size(bank_card_string); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string) { |  | ||||||
|     NfcEmvData* data = &dev->dev_data.emv_data; |  | ||||||
|     bool parsed = false; |  | ||||||
|     int res = 0; |  | ||||||
|     uint8_t code[2] = {}; |  | ||||||
|     memset(data, 0, sizeof(NfcEmvData)); |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         res = sscanf(string_get_cstr(bank_card_string), "AID len: %hu", &data->aid_len); |         // Write Bank card specific data
 | ||||||
|         if(res != 1) { |         if(!flipper_file_write_comment_cstr(file, "Bank card specific data")) break; | ||||||
|             break; |         if(!flipper_file_write_hex(file, "AID", data->aid, data->aid_len)) break; | ||||||
|  |         if(!flipper_file_write_string_cstr(file, "Name", data->name)) break; | ||||||
|  |         if(!flipper_file_write_hex(file, "Number", data->number, data->number_len)) break; | ||||||
|  |         if(data->exp_mon) { | ||||||
|  |             uint8_t exp_data[2] = {data->exp_mon, data->exp_year}; | ||||||
|  |             if(!flipper_file_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break; | ||||||
|         } |         } | ||||||
|         // strlen("AID len: ") = 9
 |         if(data->country_code) { | ||||||
|         string_right(bank_card_string, 9); |             data_temp = data->country_code; | ||||||
|         size_t ws = string_search_char(bank_card_string, ':'); |             if(!flipper_file_write_uint32(file, "Country code", &data_temp, 1)) break; | ||||||
|         string_right(bank_card_string, ws + 1); |  | ||||||
|         if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |         } | ||||||
|         res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name); |         if(data->currency_code) { | ||||||
|         if(res != 1) { |             data_temp = data->currency_code; | ||||||
|             break; |             if(!flipper_file_write_uint32(file, "Currency code", &data_temp, 1)) break; | ||||||
|         } |         } | ||||||
|         ws = string_search_char(bank_card_string, '\n'); |         saved = true; | ||||||
|         string_right(bank_card_string, ws + 1); |     } while(false); | ||||||
|         res = sscanf(string_get_cstr(bank_card_string), "Number len: %hhu", &data->number_len); |  | ||||||
|         if(res != 1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         ws = string_search_char(bank_card_string, '\n'); |  | ||||||
|         string_right(bank_card_string, ws + 1); |  | ||||||
|         // strlen("Number: ") = 8
 |  | ||||||
|         string_right(bank_card_string, 8); |  | ||||||
|         if(!nfc_device_read_hex(bank_card_string, data->number, data->number_len, 1)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         parsed = true; |  | ||||||
|         // Check expiration date presence
 |  | ||||||
|         ws = string_search_str(bank_card_string, "Exp date: "); |  | ||||||
|         if(ws != STRING_FAILURE) { |  | ||||||
|             // strlen("Exp date: ") = 10
 |  | ||||||
|             string_right(bank_card_string, 10); |  | ||||||
|             nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 1); |  | ||||||
|             nfc_device_read_hex(bank_card_string, &data->exp_year, 1, 1); |  | ||||||
|         } |  | ||||||
|         // Check country code presence
 |  | ||||||
|         ws = string_search_str(bank_card_string, "Country code: "); |  | ||||||
|         if(ws != STRING_FAILURE) { |  | ||||||
|             // strlen("Country code: ") = 14
 |  | ||||||
|             string_right(bank_card_string, 14); |  | ||||||
|             nfc_device_read_hex(bank_card_string, code, 2, 0); |  | ||||||
|             data->country_code = code[0] << 8 | code[1]; |  | ||||||
|         } |  | ||||||
|         // Check currency code presence
 |  | ||||||
|         ws = string_search_str(bank_card_string, "Currency code: "); |  | ||||||
|         if(ws != STRING_FAILURE) { |  | ||||||
|             // strlen("Currency code: ") = 15
 |  | ||||||
|             string_right(bank_card_string, 15); |  | ||||||
|             nfc_device_read_hex(bank_card_string, code, 2, 0); |  | ||||||
|             data->currency_code = code[0] << 8 | code[1]; |  | ||||||
|         } |  | ||||||
|     } while(0); |  | ||||||
| 
 | 
 | ||||||
|  |     return saved; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_device_load_bank_card_data(FlipperFile* file, NfcDevice* dev) { | ||||||
|  |     bool parsed = false; | ||||||
|  |     NfcEmvData* data = &dev->dev_data.emv_data; | ||||||
|  |     memset(data, 0, sizeof(NfcEmvData)); | ||||||
|  |     uint32_t data_cnt = 0; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // Load essential data
 | ||||||
|  |         if(!flipper_file_get_value_count(file, "AID", &data_cnt)) break; | ||||||
|  |         data->aid_len = data_cnt; | ||||||
|  |         if(!flipper_file_read_hex(file, "AID", data->aid, data->aid_len)) break; | ||||||
|  |         if(!flipper_file_read_string(file, "Name", temp_str)) break; | ||||||
|  |         strlcpy(data->name, string_get_cstr(temp_str), sizeof(data->name)); | ||||||
|  |         if(!flipper_file_get_value_count(file, "Number", &data_cnt)) break; | ||||||
|  |         data->number_len = data_cnt; | ||||||
|  |         if(!flipper_file_read_hex(file, "Number", data->number, data->number_len)) break; | ||||||
|  |         parsed = true; | ||||||
|  |         // Load optional data
 | ||||||
|  |         uint8_t exp_data[2] = {}; | ||||||
|  |         if(flipper_file_read_hex(file, "Exp data", exp_data, 2)) { | ||||||
|  |             data->exp_mon = exp_data[0]; | ||||||
|  |             data->exp_year = exp_data[1]; | ||||||
|  |         } | ||||||
|  |         if(flipper_file_read_uint32(file, "Country code", &data_cnt, 1)) { | ||||||
|  |             data->country_code = data_cnt; | ||||||
|  |         } | ||||||
|  |         if(flipper_file_read_uint32(file, "Currency code", &data_cnt, 1)) { | ||||||
|  |             data->currency_code = data_cnt; | ||||||
|  |         } | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|     return parsed; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -297,58 +228,49 @@ static bool nfc_device_save_file( | |||||||
|     const char* extension) { |     const char* extension) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     bool saved = false; | ||||||
|     string_t dev_file_name; |     FlipperFile* file = flipper_file_alloc(dev->storage); | ||||||
|     string_init(dev_file_name); |     NfcDeviceCommonData* data = &dev->dev_data.nfc_data; | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|     uint16_t string_len = 0; |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Create nfc directory if necessary
 |         // Create nfc directory if necessary
 | ||||||
|         if(!file_worker_mkdir(file_worker, nfc_app_folder)) { |         if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break; | ||||||
|             break; |  | ||||||
|         }; |  | ||||||
|         // First remove nfc device file if it was saved
 |         // First remove nfc device file if it was saved
 | ||||||
|         string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension); |         string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); | ||||||
|         if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { |  | ||||||
|             break; |  | ||||||
|         }; |  | ||||||
|         // Open file
 |         // Open file
 | ||||||
|         if(!file_worker_open( |         if(!flipper_file_open_always(file, string_get_cstr(temp_str))) break; | ||||||
|                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { |         // Write header
 | ||||||
|  |         if(!flipper_file_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; | ||||||
|  |         // Write nfc device type
 | ||||||
|  |         if(!flipper_file_write_comment_cstr( | ||||||
|  |                file, "Nfc device type can be UID, Mifare Ultralight, Bank card")) | ||||||
|             break; |             break; | ||||||
|         } |         nfc_device_prepare_format_string(dev, temp_str); | ||||||
|         // Prepare and write format name on 1st line
 |         if(!flipper_file_write_string(file, "Device type", temp_str)) break; | ||||||
|         string_len = nfc_device_prepare_format_string(dev, temp_str); |         // Write UID, ATQA, SAK
 | ||||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { |         if(!flipper_file_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) | ||||||
|             break; |             break; | ||||||
|         } |         if(!flipper_file_write_hex(file, "UID", data->uid, data->uid_len)) break; | ||||||
|         // Prepare and write UID data on 2nd line
 |         if(!flipper_file_write_hex(file, "ATQA", data->atqa, 2)) break; | ||||||
|         string_len = nfc_device_prepare_uid_string(dev, temp_str); |         if(!flipper_file_write_hex(file, "SAK", &data->sak, 1)) break; | ||||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // Save more data if necessary
 |         // Save more data if necessary
 | ||||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { |         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|             string_len = nfc_device_prepare_mifare_ul_string(dev, temp_str); |             if(!nfc_device_save_mifare_ul_data(file, dev)) break; | ||||||
|             if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { |         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|             string_len = nfc_device_prepare_bank_card_string(dev, temp_str); |             if(!nfc_device_save_bank_card_data(file, dev)) break; | ||||||
|             if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         saved = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|  |     if(!saved) { | ||||||
|  |         dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file"); | ||||||
|  |     } | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(dev_file_name); |     flipper_file_close(file); | ||||||
|     file_worker_close(file_worker); |     flipper_file_free(file); | ||||||
|     file_worker_free(file_worker); |     return saved; | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_device_save(NfcDevice* dev, const char* dev_name) { | bool nfc_device_save(NfcDevice* dev, const char* dev_name) { | ||||||
| @ -360,73 +282,64 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { | |||||||
|     return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension); |     return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) { | static bool nfc_device_load_data(NfcDevice* dev, string_t path) { | ||||||
|     string_t temp_string; |  | ||||||
|     string_init(temp_string); |  | ||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|  |     FlipperFile* file = flipper_file_alloc(dev->storage); | ||||||
|  |     NfcDeviceCommonData* data = &dev->dev_data.nfc_data; | ||||||
|  |     uint32_t data_cnt = 0; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  |     bool depricated_version = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Check existance of shadow file
 |         // Check existance of shadow file
 | ||||||
|         size_t ext_start = string_search_str(path, nfc_app_extension); |         size_t ext_start = string_search_str(path, nfc_app_extension); | ||||||
|         string_set_n(temp_string, path, 0, ext_start); |         string_set_n(temp_str, path, 0, ext_start); | ||||||
|         string_cat_printf(temp_string, "%s", nfc_app_shadow_extension); |         string_cat_printf(temp_str, "%s", nfc_app_shadow_extension); | ||||||
|         if(!file_worker_is_file_exist( |         dev->shadow_file_exist = | ||||||
|                file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) { |             storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK; | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // Open shadow file if it exists. If not - open original
 |         // Open shadow file if it exists. If not - open original
 | ||||||
|         if(dev->shadow_file_exist) { |         if(dev->shadow_file_exist) { | ||||||
|             if(!file_worker_open( |             if(!flipper_file_open_existing(file, string_get_cstr(temp_str))) break; | ||||||
|                    file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             if(!file_worker_open( |             if(!flipper_file_open_existing(file, string_get_cstr(path))) break; | ||||||
|                    file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
| 
 |         // Read and verify file header
 | ||||||
|         // Read and parse format from 1st line
 |         uint32_t version = 0; | ||||||
|         if(!file_worker_read_until(file_worker, temp_string, '\n')) { |         if(!flipper_file_read_header(file, temp_str, &version)) break; | ||||||
|             break; |         if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) { | ||||||
|         } |             depricated_version = true; | ||||||
|         if(!nfc_device_parse_format_string(dev, temp_string)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // Read and parse UID data from 2nd line
 |  | ||||||
|         if(!file_worker_read_until(file_worker, temp_string, '\n')) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         if(!nfc_device_parse_uid_string(dev, temp_string)) { |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |         // Read Nfc device type
 | ||||||
|  |         if(!flipper_file_read_string(file, "Device type", temp_str)) break; | ||||||
|  |         if(!nfc_device_parse_format_string(dev, temp_str)) break; | ||||||
|  |         // Read and parse UID, ATQA and SAK
 | ||||||
|  |         if(!flipper_file_get_value_count(file, "UID", &data_cnt)) break; | ||||||
|  |         data->uid_len = data_cnt; | ||||||
|  |         if(!flipper_file_read_hex(file, "UID", data->uid, data->uid_len)) break; | ||||||
|  |         if(!flipper_file_read_hex(file, "ATQA", data->atqa, 2)) break; | ||||||
|  |         if(!flipper_file_read_hex(file, "SAK", &data->sak, 1)) break; | ||||||
|         // Parse other data
 |         // Parse other data
 | ||||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { |         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|             // Read until EOF
 |             if(!nfc_device_load_mifare_ul_data(file, dev)) break; | ||||||
|             if(!file_worker_read_until(file_worker, temp_string, 0x05)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             if(!nfc_device_parse_mifare_ul_string(dev, temp_string)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { |         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|             // Read until EOF
 |             if(!nfc_device_load_bank_card_data(file, dev)) break; | ||||||
|             if(!file_worker_read_until(file_worker, temp_string, 0x05)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             if(!nfc_device_parse_bank_card_string(dev, temp_string)) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         parsed = true; |         parsed = true; | ||||||
|     } while(0); |     } while(false); | ||||||
| 
 | 
 | ||||||
|     if(!parsed) { |     if(!parsed) { | ||||||
|         file_worker_show_error(file_worker, "Can not parse\nfile"); |         if(depricated_version) { | ||||||
|  |             dialog_message_show_storage_error(dev->dialogs, "File format depricated"); | ||||||
|  |         } else { | ||||||
|  |             dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile"); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(temp_string); |     string_clear(temp_str); | ||||||
|  |     flipper_file_close(file); | ||||||
|  |     flipper_file_free(file); | ||||||
|     return parsed; |     return parsed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -434,19 +347,16 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) { | |||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
|     furi_assert(file_path); |     furi_assert(file_path); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |  | ||||||
|     // Load device data
 |     // Load device data
 | ||||||
|     string_t path; |     string_t path; | ||||||
|     string_init_set_str(path, file_path); |     string_init_set_str(path, file_path); | ||||||
|     bool dev_load = nfc_device_load_data(file_worker, path, dev); |     bool dev_load = nfc_device_load_data(dev, path); | ||||||
|     if(dev_load) { |     if(dev_load) { | ||||||
|         // Set device name
 |         // Set device name
 | ||||||
|         path_extract_filename_no_ext(file_path, path); |         path_extract_filename_no_ext(file_path, path); | ||||||
|         nfc_device_set_name(dev, string_get_cstr(path)); |         nfc_device_set_name(dev, string_get_cstr(path)); | ||||||
|     } |     } | ||||||
|     string_clear(path); |     string_clear(path); | ||||||
|     file_worker_close(file_worker); |  | ||||||
|     file_worker_free(file_worker); |  | ||||||
| 
 | 
 | ||||||
|     return dev_load; |     return dev_load; | ||||||
| } | } | ||||||
| @ -454,10 +364,9 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) { | |||||||
| bool nfc_file_select(NfcDevice* dev) { | bool nfc_file_select(NfcDevice* dev) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |  | ||||||
|     // Input events and views are managed by file_select
 |     // Input events and views are managed by file_select
 | ||||||
|     bool res = file_worker_file_select( |     bool res = dialog_file_select_show( | ||||||
|         file_worker, |         dev->dialogs, | ||||||
|         nfc_app_folder, |         nfc_app_folder, | ||||||
|         nfc_app_extension, |         nfc_app_extension, | ||||||
|         dev->file_name, |         dev->file_name, | ||||||
| @ -465,18 +374,14 @@ bool nfc_file_select(NfcDevice* dev) { | |||||||
|         dev->dev_name); |         dev->dev_name); | ||||||
|     if(res) { |     if(res) { | ||||||
|         string_t dev_str; |         string_t dev_str; | ||||||
| 
 |  | ||||||
|         // Get key file path
 |         // Get key file path
 | ||||||
|         string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension); |         string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension); | ||||||
| 
 |         res = nfc_device_load_data(dev, dev_str); | ||||||
|         res = nfc_device_load_data(file_worker, dev_str, dev); |  | ||||||
|         if(res) { |         if(res) { | ||||||
|             nfc_device_set_name(dev, dev->file_name); |             nfc_device_set_name(dev, dev->file_name); | ||||||
|         } |         } | ||||||
|         string_clear(dev_str); |         string_clear(dev_str); | ||||||
|     } |     } | ||||||
|     file_worker_close(file_worker); |  | ||||||
|     file_worker_free(file_worker); |  | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| @ -491,61 +396,48 @@ void nfc_device_clear(NfcDevice* dev) { | |||||||
| bool nfc_device_delete(NfcDevice* dev) { | bool nfc_device_delete(NfcDevice* dev) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
|     bool result = true; |     bool deleted = false; | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |  | ||||||
|     string_t file_path; |     string_t file_path; | ||||||
|  |     string_init(file_path); | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         // Delete original file
 |         // Delete original file
 | ||||||
|         string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); |         string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); | ||||||
|         if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { |         if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // Delete shadow file if it exists
 |         // Delete shadow file if it exists
 | ||||||
|         if(dev->shadow_file_exist) { |         if(dev->shadow_file_exist) { | ||||||
|             string_clean(file_path); |  | ||||||
|             string_printf( |             string_printf( | ||||||
|                 file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); |                 file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); | ||||||
|             if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { |             if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; | ||||||
|                 result = false; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         deleted = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|  |     if(!deleted) { | ||||||
|  |         dialog_message_show_storage_error(dev->dialogs, "Can not remove file"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     string_clear(file_path); |     string_clear(file_path); | ||||||
|     file_worker_close(file_worker); |     return deleted; | ||||||
|     file_worker_free(file_worker); |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_device_restore(NfcDevice* dev) { | bool nfc_device_restore(NfcDevice* dev) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
|     furi_assert(dev->shadow_file_exist); |     furi_assert(dev->shadow_file_exist); | ||||||
| 
 | 
 | ||||||
|     bool result = true; |     bool restored = false; | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |  | ||||||
|     string_t path; |     string_t path; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         string_init_printf( |         string_init_printf( | ||||||
|             path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); |             path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); | ||||||
|         if(!file_worker_remove(file_worker, string_get_cstr(path))) { |         if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break; | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         dev->shadow_file_exist = false; |         dev->shadow_file_exist = false; | ||||||
|         string_clean(path); |  | ||||||
|         string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); |         string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); | ||||||
|         if(!nfc_device_load_data(file_worker, path, dev)) { |         if(!nfc_device_load_data(dev, path)) break; | ||||||
|             result = false; |         restored = true; | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     string_clear(path); |     string_clear(path); | ||||||
|     file_worker_close(file_worker); |     return restored; | ||||||
|     file_worker_free(file_worker); |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <storage/storage.h> | ||||||
|  | #include <dialogs/dialogs.h> | ||||||
| 
 | 
 | ||||||
| #include "mifare_ultralight.h" | #include "mifare_ultralight.h" | ||||||
| 
 | 
 | ||||||
| @ -57,6 +59,8 @@ typedef struct { | |||||||
| } NfcDeviceData; | } NfcDeviceData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     Storage* storage; | ||||||
|  |     DialogsApp* dialogs; | ||||||
|     NfcDeviceData dev_data; |     NfcDeviceData dev_data; | ||||||
|     char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; |     char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; | ||||||
|     char file_name[NFC_FILE_NAME_MAX_LEN]; |     char file_name[NFC_FILE_NAME_MAX_LEN]; | ||||||
| @ -64,6 +68,10 @@ typedef struct { | |||||||
|     bool shadow_file_exist; |     bool shadow_file_exist; | ||||||
| } NfcDevice; | } NfcDevice; | ||||||
| 
 | 
 | ||||||
|  | NfcDevice* nfc_device_alloc(); | ||||||
|  | 
 | ||||||
|  | void nfc_device_free(NfcDevice* nfc_dev); | ||||||
|  | 
 | ||||||
| void nfc_device_set_name(NfcDevice* dev, const char* name); | void nfc_device_set_name(NfcDevice* dev, const char* name); | ||||||
| 
 | 
 | ||||||
| bool nfc_device_save(NfcDevice* dev, const char* dev_name); | bool nfc_device_save(NfcDevice* dev, const char* dev_name); | ||||||
|  | |||||||
| @ -1,16 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "nfc_device.h" |  | ||||||
| #include <m-string.h> |  | ||||||
| 
 |  | ||||||
| uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string); |  | ||||||
| bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string); |  | ||||||
| 
 |  | ||||||
| uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string); |  | ||||||
| bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string); |  | ||||||
| 
 |  | ||||||
| uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string); |  | ||||||
| bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string); |  | ||||||
| 
 |  | ||||||
| uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string); |  | ||||||
| bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string); |  | ||||||
| @ -36,7 +36,7 @@ struct Nfc { | |||||||
|     Gui* gui; |     Gui* gui; | ||||||
|     NotificationApp* notifications; |     NotificationApp* notifications; | ||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     NfcDevice dev; |     NfcDevice* dev; | ||||||
|     NfcDeviceCommonData dev_edit_data; |     NfcDeviceCommonData dev_edit_data; | ||||||
| 
 | 
 | ||||||
|     char text_store[NFC_TEXT_STORE_SIZE + 1]; |     char text_store[NFC_TEXT_STORE_SIZE + 1]; | ||||||
|  | |||||||
							
								
								
									
										145
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										145
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -3,14 +3,14 @@ | |||||||
| #include "nfc_protocols/emv_decoder.h" | #include "nfc_protocols/emv_decoder.h" | ||||||
| #include "nfc_protocols/mifare_ultralight.h" | #include "nfc_protocols/mifare_ultralight.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_WORKER_TAG "nfc worker" | #define TAG "NfcWorker" | ||||||
| 
 | 
 | ||||||
| /***************************** NFC Worker API *******************************/ | /***************************** NFC Worker API *******************************/ | ||||||
| 
 | 
 | ||||||
| NfcWorker* nfc_worker_alloc() { | NfcWorker* nfc_worker_alloc() { | ||||||
|     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); |     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); | ||||||
|     // Worker thread attributes
 |     // Worker thread attributes
 | ||||||
|     nfc_worker->thread_attr.name = "nfc_worker"; |     nfc_worker->thread_attr.name = "NfcWorker"; | ||||||
|     nfc_worker->thread_attr.stack_size = 8192; |     nfc_worker->thread_attr.stack_size = 8192; | ||||||
|     nfc_worker->callback = NULL; |     nfc_worker->callback = NULL; | ||||||
|     nfc_worker->context = NULL; |     nfc_worker->context = NULL; | ||||||
| @ -144,7 +144,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) { | |||||||
|     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; |     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { |     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { |         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Reader detected"); |             FURI_LOG_I(TAG, "Reader detected"); | ||||||
|         } |         } | ||||||
|         osDelay(10); |         osDelay(10); | ||||||
|     } |     } | ||||||
| @ -174,18 +174,17 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | |||||||
|                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); |                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); | ||||||
|                 result->nfc_data.protocol = NfcDeviceProtocolEMV; |                 result->nfc_data.protocol = NfcDeviceProtocolEMV; | ||||||
| 
 | 
 | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Send select PPSE command"); |                 FURI_LOG_I(TAG, "Send select PPSE command"); | ||||||
|                 tx_len = emv_prepare_select_ppse(tx_buff); |                 tx_len = emv_prepare_select_ppse(tx_buff); | ||||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); |                     FURI_LOG_E(TAG, "Error during selection PPSE request: %d", err); | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_I( |                 FURI_LOG_I(TAG, "Select PPSE response received. Start parsing response"); | ||||||
|                     NFC_WORKER_TAG, "Select PPSE response received. Start parsing response"); |  | ||||||
|                 if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); |                     FURI_LOG_I(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); | ||||||
| @ -194,18 +193,18 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | |||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); |                     FURI_LOG_E(TAG, "Can't find pay application"); | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // Can't find EMV card
 |                 // Can't find EMV card
 | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); |                 FURI_LOG_W(TAG, "Card doesn't support EMV"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             // Can't find EMV card
 |             // Can't find EMV card
 | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); |             FURI_LOG_W(TAG, "Can't find any cards"); | ||||||
|             furi_hal_nfc_deactivate(); |             furi_hal_nfc_deactivate(); | ||||||
|         } |         } | ||||||
|         osDelay(20); |         osDelay(20); | ||||||
| @ -236,56 +235,53 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); |                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); | ||||||
|                 result->nfc_data.protocol = NfcDeviceProtocolEMV; |                 result->nfc_data.protocol = NfcDeviceProtocolEMV; | ||||||
| 
 | 
 | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Send select PPSE command"); |                 FURI_LOG_I(TAG, "Send select PPSE command"); | ||||||
|                 tx_len = emv_prepare_select_ppse(tx_buff); |                 tx_len = emv_prepare_select_ppse(tx_buff); | ||||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Error during selection PPSE request: %d", err); |                     FURI_LOG_E(TAG, "Error during selection PPSE request: %d", err); | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_I( |                 FURI_LOG_I(TAG, "Select PPSE response received. Start parsing response"); | ||||||
|                     NFC_WORKER_TAG, "Select PPSE response received. Start parsing response"); |  | ||||||
|                 if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced"); |                     FURI_LOG_I(TAG, "Select PPSE responce parced"); | ||||||
|  |                     result->emv_data.aid_len = emv_app.aid_len; | ||||||
|  |                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); |                     FURI_LOG_E(TAG, "Can't find pay application"); | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Starting application ..."); |                 FURI_LOG_I(TAG, "Starting application ..."); | ||||||
|                 tx_len = emv_prepare_select_app(tx_buff, &emv_app); |                 tx_len = emv_prepare_select_app(tx_buff, &emv_app); | ||||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E( |                     FURI_LOG_E(TAG, "Error during application selection request: %d", err); | ||||||
|                         NFC_WORKER_TAG, "Error during application selection request: %d", err); |  | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_I( |                 FURI_LOG_I(TAG, "Select application response received. Start parsing response"); | ||||||
|                     NFC_WORKER_TAG, |  | ||||||
|                     "Select application response received. Start parsing response"); |  | ||||||
|                 if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card name: %s", emv_app.name); |                     FURI_LOG_I(TAG, "Card name: %s", emv_app.name); | ||||||
|                     memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); |                     memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); | ||||||
|                 } else if(emv_app.pdol.size > 0) { |                 } else if(emv_app.pdol.size > 0) { | ||||||
|                     FURI_LOG_W(NFC_WORKER_TAG, "Can't find card name, but PDOL is present."); |                     FURI_LOG_W(TAG, "Can't find card name, but PDOL is present."); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find card name or PDOL"); |                     FURI_LOG_E(TAG, "Can't find card name or PDOL"); | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Starting Get Processing Options command ..."); |                 FURI_LOG_I(TAG, "Starting Get Processing Options command ..."); | ||||||
|                 tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app); |                 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); |                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E( |                     FURI_LOG_E(TAG, "Error during Get Processing Options command: %d", err); | ||||||
|                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err); |  | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { |                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); |                     FURI_LOG_I(TAG, "Card number parsed"); | ||||||
|                     result->emv_data.number_len = emv_app.card_number_len; |                     result->emv_data.number_len = emv_app.card_number_len; | ||||||
|                     memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); |                     memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); | ||||||
|                     // Notify caller and exit
 |                     // Notify caller and exit
 | ||||||
| @ -309,7 +305,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                                 tx_buff, tx_len, &rx_buff, &rx_len, false); |                                 tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                             if(err != ERR_NONE) { |                             if(err != ERR_NONE) { | ||||||
|                                 FURI_LOG_E( |                                 FURI_LOG_E( | ||||||
|                                     NFC_WORKER_TAG, |                                     TAG, | ||||||
|                                     "Error reading application sfi %d, record %d", |                                     "Error reading application sfi %d, record %d", | ||||||
|                                     sfi, |                                     sfi, | ||||||
|                                     record); |                                     record); | ||||||
| @ -321,7 +317,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     if(pan_found) { |                     if(pan_found) { | ||||||
|                         FURI_LOG_I(NFC_WORKER_TAG, "Card PAN found"); |                         FURI_LOG_I(TAG, "Card PAN found"); | ||||||
|                         result->emv_data.number_len = emv_app.card_number_len; |                         result->emv_data.number_len = emv_app.card_number_len; | ||||||
|                         memcpy( |                         memcpy( | ||||||
|                             result->emv_data.number, |                             result->emv_data.number, | ||||||
| @ -343,18 +339,18 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | |||||||
|                         } |                         } | ||||||
|                         break; |                         break; | ||||||
|                     } else { |                     } else { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Can't read card number"); |                         FURI_LOG_E(TAG, "Can't read card number"); | ||||||
|                     } |                     } | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // Can't find EMV card
 |                 // Can't find EMV card
 | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Card doesn't support EMV"); |                 FURI_LOG_W(TAG, "Card doesn't support EMV"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             // Can't find EMV card
 |             // Can't find EMV card
 | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any cards"); |             FURI_LOG_W(TAG, "Can't find any cards"); | ||||||
|             furi_hal_nfc_deactivate(); |             furi_hal_nfc_deactivate(); | ||||||
|         } |         } | ||||||
|         osDelay(20); |         osDelay(20); | ||||||
| @ -416,63 +412,63 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | |||||||
| 
 | 
 | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulateApdu) { |     while(nfc_worker->state == NfcWorkerStateEmulateApdu) { | ||||||
|         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { |         if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected"); |             FURI_LOG_I(TAG, "POS terminal detected"); | ||||||
|             // Read data from POS terminal
 |             // Read data from POS terminal
 | ||||||
|             err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); |             err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); | ||||||
|             if(err == ERR_NONE) { |             if(err == ERR_NONE) { | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received Select PPSE"); |                 FURI_LOG_I(TAG, "Received Select PPSE"); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_E(NFC_WORKER_TAG, "Error in 1st data exchange: select PPSE"); |                 FURI_LOG_E(TAG, "Error in 1st data exchange: select PPSE"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Transive SELECT PPSE ANS"); |             FURI_LOG_I(TAG, "Transive SELECT PPSE ANS"); | ||||||
|             tx_len = emv_select_ppse_ans(tx_buff); |             tx_len = emv_select_ppse_ans(tx_buff); | ||||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|             if(err == ERR_NONE) { |             if(err == ERR_NONE) { | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received Select APP"); |                 FURI_LOG_I(TAG, "Received Select APP"); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_E(NFC_WORKER_TAG, "Error in 2nd data exchange: select APP"); |                 FURI_LOG_E(TAG, "Error in 2nd data exchange: select APP"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Transive SELECT APP ANS"); |             FURI_LOG_I(TAG, "Transive SELECT APP ANS"); | ||||||
|             tx_len = emv_select_app_ans(tx_buff); |             tx_len = emv_select_app_ans(tx_buff); | ||||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|             if(err == ERR_NONE) { |             if(err == ERR_NONE) { | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received PDOL"); |                 FURI_LOG_I(TAG, "Received PDOL"); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_E(NFC_WORKER_TAG, "Error in 3rd data exchange: receive PDOL"); |                 FURI_LOG_E(TAG, "Error in 3rd data exchange: receive PDOL"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             FURI_LOG_I(NFC_WORKER_TAG, "Transive PDOL ANS"); |             FURI_LOG_I(TAG, "Transive PDOL ANS"); | ||||||
|             tx_len = emv_get_proc_opt_ans(tx_buff); |             tx_len = emv_get_proc_opt_ans(tx_buff); | ||||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|             if(err == ERR_NONE) { |             if(err == ERR_NONE) { | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Transive PDOL ANS"); |                 FURI_LOG_I(TAG, "Transive PDOL ANS"); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_E(NFC_WORKER_TAG, "Error in 4rd data exchange: Transive PDOL ANS"); |                 FURI_LOG_E(TAG, "Error in 4rd data exchange: Transive PDOL ANS"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) { |             if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) { | ||||||
|                 FURI_LOG_E(NFC_WORKER_TAG, "Failed long message test"); |                 FURI_LOG_E(TAG, "Failed long message test"); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Correct debug message received"); |                 FURI_LOG_I(TAG, "Correct debug message received"); | ||||||
|                 tx_len = sizeof(debug_tx); |                 tx_len = sizeof(debug_tx); | ||||||
|                 err = furi_hal_nfc_data_exchange( |                 err = furi_hal_nfc_data_exchange( | ||||||
|                     (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false); |                     (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err == ERR_NONE) { |                 if(err == ERR_NONE) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Transive Debug message"); |                     FURI_LOG_I(TAG, "Transive Debug message"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             furi_hal_nfc_deactivate(); |             furi_hal_nfc_deactivate(); | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader"); |             FURI_LOG_W(TAG, "Can't find reader"); | ||||||
|         } |         } | ||||||
|         osDelay(20); |         osDelay(20); | ||||||
|     } |     } | ||||||
| @ -499,71 +495,69 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                    dev_list[0].dev.nfca.sensRes.platformInfo, |                    dev_list[0].dev.nfca.sensRes.platformInfo, | ||||||
|                    dev_list[0].dev.nfca.selRes.sak)) { |                    dev_list[0].dev.nfca.selRes.sak)) { | ||||||
|                 // Get Mifare Ultralight version
 |                 // Get Mifare Ultralight version
 | ||||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Found Mifare Ultralight tag. Reading tag version"); |                 FURI_LOG_I(TAG, "Found Mifare Ultralight tag. Reading tag version"); | ||||||
|                 tx_len = mf_ul_prepare_get_version(tx_buff); |                 tx_len = mf_ul_prepare_get_version(tx_buff); | ||||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|                 if(err == ERR_NONE) { |                 if(err == ERR_NONE) { | ||||||
|                     mf_ul_parse_get_version_response(rx_buff, &mf_ul_read); |                     mf_ul_parse_get_version_response(rx_buff, &mf_ul_read); | ||||||
|                     FURI_LOG_I( |                     FURI_LOG_I( | ||||||
|                         NFC_WORKER_TAG, |                         TAG, | ||||||
|                         "Mifare Ultralight Type: %d, Pages: %d", |                         "Mifare Ultralight Type: %d, Pages: %d", | ||||||
|                         mf_ul_read.type, |                         mf_ul_read.type, | ||||||
|                         mf_ul_read.pages_to_read); |                         mf_ul_read.pages_to_read); | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Reading signature ..."); |                     FURI_LOG_I(TAG, "Reading signature ..."); | ||||||
|                     tx_len = mf_ul_prepare_read_signature(tx_buff); |                     tx_len = mf_ul_prepare_read_signature(tx_buff); | ||||||
|                     if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { |                     if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||||
|                         FURI_LOG_W(NFC_WORKER_TAG, "Failed reading signature"); |                         FURI_LOG_W(TAG, "Failed reading signature"); | ||||||
|                         memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature)); |                         memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature)); | ||||||
|                     } else { |                     } else { | ||||||
|                         mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read); |                         mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read); | ||||||
|                     } |                     } | ||||||
|                 } else if(err == ERR_TIMEOUT) { |                 } else if(err == ERR_TIMEOUT) { | ||||||
|                     FURI_LOG_W( |                     FURI_LOG_W( | ||||||
|                         NFC_WORKER_TAG, |                         TAG, | ||||||
|                         "Card doesn't respond to GET VERSION command. Setting default read parameters"); |                         "Card doesn't respond to GET VERSION command. Setting default read parameters"); | ||||||
|                     err = ERR_NONE; |                     err = ERR_NONE; | ||||||
|                     mf_ul_set_default_version(&mf_ul_read); |                     mf_ul_set_default_version(&mf_ul_read); | ||||||
|                     // Reinit device
 |                     // Reinit device
 | ||||||
|                     furi_hal_nfc_deactivate(); |                     furi_hal_nfc_deactivate(); | ||||||
|                     if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { |                     if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); |                         FURI_LOG_E(TAG, "Lost connection. Restarting search"); | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_E( |                     FURI_LOG_E( | ||||||
|                         NFC_WORKER_TAG, |                         TAG, "Error getting Mifare Ultralight version. Error code: %d", err); | ||||||
|                         "Error getting Mifare Ultralight version. Error code: %d", |  | ||||||
|                         err); |  | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if(mf_ul_read.support_fast_read) { |                 if(mf_ul_read.support_fast_read) { | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Reading pages ..."); |                     FURI_LOG_I(TAG, "Reading pages ..."); | ||||||
|                     tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1); |                     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)) { |                     if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Failed reading pages"); |                         FURI_LOG_E(TAG, "Failed reading pages"); | ||||||
|                         continue; |                         continue; | ||||||
|                     } else { |                     } else { | ||||||
|                         mf_ul_parse_fast_read_response( |                         mf_ul_parse_fast_read_response( | ||||||
|                             rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read); |                             rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Reading 3 counters ..."); |                     FURI_LOG_I(TAG, "Reading 3 counters ..."); | ||||||
|                     for(uint8_t i = 0; i < 3; i++) { |                     for(uint8_t i = 0; i < 3; i++) { | ||||||
|                         tx_len = mf_ul_prepare_read_cnt(tx_buff, 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)) { |                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||||
|                             FURI_LOG_W(NFC_WORKER_TAG, "Failed reading Counter %d", i); |                             FURI_LOG_W(TAG, "Failed reading Counter %d", i); | ||||||
|                             mf_ul_read.data.counter[i] = 0; |                             mf_ul_read.data.counter[i] = 0; | ||||||
|                         } else { |                         } else { | ||||||
|                             mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read); |                             mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Checking tearing flags ..."); |                     FURI_LOG_I(TAG, "Checking tearing flags ..."); | ||||||
|                     for(uint8_t i = 0; i < 3; i++) { |                     for(uint8_t i = 0; i < 3; i++) { | ||||||
|                         tx_len = mf_ul_prepare_check_tearing(tx_buff, 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)) { |                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||||
|                             FURI_LOG_E(NFC_WORKER_TAG, "Error checking tearing flag %d", i); |                             FURI_LOG_E(TAG, "Error checking tearing flag %d", i); | ||||||
|                             mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT; |                             mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT; | ||||||
|                         } else { |                         } else { | ||||||
|                             mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read); |                             mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read); | ||||||
| @ -572,11 +566,10 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                 } else { |                 } else { | ||||||
|                     // READ card with READ command (4 pages at a time)
 |                     // READ card with READ command (4 pages at a time)
 | ||||||
|                     for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { |                     for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { | ||||||
|                         FURI_LOG_I(NFC_WORKER_TAG, "Reading pages %d - %d ...", page, page + 3); |                         FURI_LOG_I(TAG, "Reading pages %d - %d ...", page, page + 3); | ||||||
|                         tx_len = mf_ul_prepare_read(tx_buff, page); |                         tx_len = mf_ul_prepare_read(tx_buff, page); | ||||||
|                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { |                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||||
|                             FURI_LOG_E( |                             FURI_LOG_E(TAG, "Read pages %d - %d failed", page, page + 3); | ||||||
|                                 NFC_WORKER_TAG, "Read pages %d - %d failed", page, page + 3); |  | ||||||
|                             continue; |                             continue; | ||||||
|                         } else { |                         } else { | ||||||
|                             mf_ul_parse_read_response(rx_buff, page, &mf_ul_read); |                             mf_ul_parse_read_response(rx_buff, page, &mf_ul_read); | ||||||
| @ -600,10 +593,10 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); |                 FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight"); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); |             FURI_LOG_W(TAG, "Can't find any tags"); | ||||||
|         } |         } | ||||||
|         osDelay(100); |         osDelay(100); | ||||||
|     } |     } | ||||||
| @ -627,7 +620,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                data->nfc_data.sak, |                data->nfc_data.sak, | ||||||
|                true, |                true, | ||||||
|                200)) { |                200)) { | ||||||
|             FURI_LOG_D(NFC_WORKER_TAG, "Anticollision passed"); |             FURI_LOG_D(TAG, "Anticollision passed"); | ||||||
|             if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) { |             if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) { | ||||||
|                 // Data exchange loop
 |                 // Data exchange loop
 | ||||||
|                 while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { |                 while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { | ||||||
| @ -639,17 +632,17 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                         if(err == ERR_NONE) { |                         if(err == ERR_NONE) { | ||||||
|                             continue; |                             continue; | ||||||
|                         } else { |                         } else { | ||||||
|                             FURI_LOG_E(NFC_WORKER_TAG, "Communication error: %d", err); |                             FURI_LOG_E(TAG, "Communication error: %d", err); | ||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         FURI_LOG_W(NFC_WORKER_TAG, "Not valid command: %02X", rx_buff[0]); |                         FURI_LOG_W(TAG, "Not valid command: %02X", rx_buff[0]); | ||||||
|                         furi_hal_nfc_deactivate(); |                         furi_hal_nfc_deactivate(); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Error in 1st data exchange"); |                 FURI_LOG_W(TAG, "Error in 1st data exchange"); | ||||||
|                 furi_hal_nfc_deactivate(); |                 furi_hal_nfc_deactivate(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -660,7 +653,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                 nfc_worker->callback(nfc_worker->context); |                 nfc_worker->callback(nfc_worker->context); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader"); |         FURI_LOG_W(TAG, "Can't find reader"); | ||||||
|         osThreadYield(); |         osThreadYield(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) { | |||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* 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.nfc_data.protocol > NfcDeviceProtocolUnknown) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Run compatible app", |             "Run compatible app", | ||||||
| @ -48,9 +48,9 @@ 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.nfc_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 == NfcDeviceProtocolEMV) { |             } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
| @ -66,7 +66,7 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexSave) { |         } else if(event.event == SubmenuIndexSave) { | ||||||
|             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave); |             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave); | ||||||
|             nfc->dev.format = NfcDeviceSaveFormatUid; |             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -12,14 +12,14 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     char delete_str[64]; |     char delete_str[64]; | ||||||
|     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev.dev_name); |     snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev->dev_name); | ||||||
|     widget_add_text_box_element(nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, delete_str); |     widget_add_text_box_element(nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, delete_str); | ||||||
|     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]; |     char uid_str[32]; | ||||||
|     NfcDeviceCommonData* 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, |             uid_str, | ||||||
| @ -73,7 +73,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             return scene_manager_previous_scene(nfc->scene_manager); |             return scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             if(nfc_device_delete(&nfc->dev)) { |             if(nfc_device_delete(nfc->dev)) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_search_and_switch_to_previous_scene( |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
|  | #include "../helpers/nfc_emv_parser.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL) | #define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL) | ||||||
| 
 | 
 | ||||||
| @ -36,13 +37,13 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     widget_add_text_box_element( |     widget_add_text_box_element( | ||||||
|         nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev.dev_name); |         nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev->dev_name); | ||||||
|     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); | ||||||
|     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 uid_str[32]; | ||||||
|     NfcDeviceCommonData* 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, |             uid_str, | ||||||
| @ -87,14 +88,14 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|     widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str); |     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) { | ||||||
|         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"); | ||||||
|         dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); |         dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); | ||||||
|         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 = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data; |         MifareUlData* 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_context(text_box, nfc); |         text_box_set_context(text_box, nfc); | ||||||
|         text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback); |         text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback); | ||||||
| @ -107,8 +108,8 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|                 nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); |                 nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); | ||||||
|         } |         } | ||||||
|         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)); | ||||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|         NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; |         NfcEmvData* 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); | ||||||
| @ -116,12 +117,29 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|         if(emv_data->exp_mon) { |         if(emv_data->exp_mon) { | ||||||
|             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); |             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); | ||||||
|         } |         } | ||||||
|  |         string_t display_str; | ||||||
|  |         string_init(display_str); | ||||||
|         if(emv_data->country_code) { |         if(emv_data->country_code) { | ||||||
|             bank_card_set_country_name(bank_card, emv_data->country_code); |             string_t country_name; | ||||||
|  |             string_init(country_name); | ||||||
|  |             if(nfc_emv_parser_get_country_name( | ||||||
|  |                    nfc->dev->storage, emv_data->country_code, country_name)) { | ||||||
|  |                 string_printf(display_str, "Reg:%s", string_get_cstr(country_name)); | ||||||
|  |                 bank_card_set_country_name(bank_card, string_get_cstr(display_str)); | ||||||
|  |             } | ||||||
|  |             string_clear(country_name); | ||||||
|         } |         } | ||||||
|         if(emv_data->currency_code) { |         if(emv_data->currency_code) { | ||||||
|             bank_card_set_currency_name(bank_card, emv_data->currency_code); |             string_t currency_name; | ||||||
|  |             string_init(currency_name); | ||||||
|  |             if(nfc_emv_parser_get_currency_name( | ||||||
|  |                    nfc->dev->storage, emv_data->country_code, currency_name)) { | ||||||
|  |                 string_printf(display_str, "Cur:%s", string_get_cstr(currency_name)); | ||||||
|  |                 bank_card_set_currency_name(bank_card, string_get_cstr(display_str)); | ||||||
|  |             } | ||||||
|  |             string_clear(currency_name); | ||||||
|         } |         } | ||||||
|  |         string_clear(display_str); | ||||||
|     } |     } | ||||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| @ -136,17 +154,17 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { |         if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { | ||||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); |             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { |         } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { | ||||||
|             if(nfc->dev.format == NfcDeviceSaveFormatUid) { |             if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { |             } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|                 consumed = true; |                 consumed = true; | ||||||
|             } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { |             } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|                 scene_manager_set_scene_state( |                 scene_manager_set_scene_state( | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); |                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); | ||||||
| @ -168,7 +186,7 @@ void nfc_scene_device_info_on_exit(void* context) { | |||||||
|     // Clear Custom Widget
 |     // Clear Custom Widget
 | ||||||
|     widget_clear(nfc->widget); |     widget_clear(nfc->widget); | ||||||
| 
 | 
 | ||||||
|     if(nfc->dev.format == NfcDeviceSaveFormatUid) { |     if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||||
|         // Clear Dialog
 |         // Clear Dialog
 | ||||||
|         DialogEx* dialog_ex = nfc->dialog_ex; |         DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|         dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); |         dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); | ||||||
| @ -179,11 +197,11 @@ void nfc_scene_device_info_on_exit(void* context) { | |||||||
|         dialog_ex_set_center_button_text(dialog_ex, NULL); |         dialog_ex_set_center_button_text(dialog_ex, NULL); | ||||||
|         dialog_ex_set_result_callback(dialog_ex, NULL); |         dialog_ex_set_result_callback(dialog_ex, NULL); | ||||||
|         dialog_ex_set_context(dialog_ex, NULL); |         dialog_ex_set_context(dialog_ex, NULL); | ||||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|         // Clear TextBox
 |         // Clear TextBox
 | ||||||
|         text_box_clean(nfc->text_box); |         text_box_clean(nfc->text_box); | ||||||
|         string_clean(nfc->text_box_store); |         string_clean(nfc->text_box_store); | ||||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|         // Clear Bank Card
 |         // Clear Bank Card
 | ||||||
|         bank_card_clear(nfc->bank_card); |         bank_card_clear(nfc->bank_card); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { | |||||||
|     // 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) { | ||||||
|  | |||||||
| @ -14,8 +14,8 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|     if(strcmp(nfc->dev.dev_name, "")) { |     if(strcmp(nfc->dev->dev_name, "")) { | ||||||
|         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); |         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); | ||||||
|     } |     } | ||||||
|     popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); |     popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); | ||||||
|     popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop); |     popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop); | ||||||
| @ -25,7 +25,7 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) { | |||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateEmulateMifareUl, |         NfcWorkerStateEmulateMifareUl, | ||||||
|         &nfc->dev.dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_emulate_mifare_ul_worker_callback, |         nfc_emulate_mifare_ul_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
| @ -45,7 +45,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event | |||||||
|            NFC_MF_UL_DATA_CHANGED) { |            NFC_MF_UL_DATA_CHANGED) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED); |                 nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED); | ||||||
|             nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name); |             nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); | ||||||
|         } |         } | ||||||
|         consumed = false; |         consumed = false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -5,10 +5,10 @@ void nfc_scene_emulate_uid_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
|     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; | ||||||
| 
 | 
 | ||||||
|     if(strcmp(nfc->dev.dev_name, "")) { |     if(strcmp(nfc->dev->dev_name, "")) { | ||||||
|         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); |         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); | ||||||
|     } else if(data->uid_len == 4) { |     } else if(data->uid_len == 4) { | ||||||
|         nfc_text_store_set( |         nfc_text_store_set( | ||||||
|             nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]); |             nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]); | ||||||
| @ -32,7 +32,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { | |||||||
|     // 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, NfcWorkerStateEmulate, &nfc->dev.dev_data, NULL, nfc); |     nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| void nfc_scene_file_select_on_enter(void* context) { | void nfc_scene_file_select_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* 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); | ||||||
|     } else { |     } else { | ||||||
|         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); |         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); | ||||||
|  | |||||||
| @ -32,9 +32,9 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|         if(event.event == SubmenuIndexSave) { |         if(event.event == SubmenuIndexSave) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); |                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); | ||||||
|             nfc->dev.format = NfcDeviceSaveFormatMifareUl; |             nfc->dev->format = NfcDeviceSaveFormatMifareUl; | ||||||
|             // 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; |             return true; | ||||||
|         } else if(event.event == SubmenuIndexEmulate) { |         } else if(event.event == SubmenuIndexEmulate) { | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void nfc_scene_read_card_on_enter(void* context) { | |||||||
|     // Start worker
 |     // 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_start( | ||||||
|         nfc->worker, NfcWorkerStateDetect, &nfc->dev.dev_data, nfc_read_card_worker_callback, nfc); |         nfc->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ 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 = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_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"); | ||||||
| @ -68,7 +68,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event | |||||||
|             return scene_manager_previous_scene(nfc->scene_manager); |             return scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if(event.event == DialogExResultRight) { |         } else if(event.event == DialogExResultRight) { | ||||||
|             // 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); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ void nfc_scene_read_emv_app_on_enter(void* context) { | |||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateReadEMVApp, |         NfcWorkerStateReadEMVApp, | ||||||
|         &nfc->dev.dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_read_emv_app_worker_callback, |         nfc_read_emv_app_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,8 +13,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | |||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; |     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_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, "Run app"); |     dialog_ex_set_right_button_text(dialog_ex, "Run app"); | ||||||
| @ -23,7 +23,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | |||||||
|     // Display UID and AID
 |     // Display UID and AID
 | ||||||
|     string_t aid; |     string_t aid; | ||||||
|     string_init(aid); |     string_init(aid); | ||||||
|     bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, aid); |     bool aid_found = | ||||||
|  |         nfc_emv_parser_get_aid_name(nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid); | ||||||
|     if(!aid_found) { |     if(!aid_found) { | ||||||
|         for(uint8_t i = 0; i < emv_data->aid_len; i++) { |         for(uint8_t i = 0; i < emv_data->aid_len; i++) { | ||||||
|             string_cat_printf(aid, "%02X", emv_data->aid[i]); |             string_cat_printf(aid, "%02X", emv_data->aid[i]); | ||||||
|  | |||||||
| @ -17,12 +17,12 @@ void nfc_scene_read_emv_data_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||||
|     // Clear emv data
 |     // Clear emv data
 | ||||||
|     memset(&nfc->dev.dev_data.emv_data, 0, sizeof(nfc->dev.dev_data.emv_data)); |     memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data)); | ||||||
|     // Start worker
 |     // Start worker
 | ||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateReadEMV, |         NfcWorkerStateReadEMV, | ||||||
|         &nfc->dev.dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_read_emv_data_worker_callback, |         nfc_read_emv_data_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,8 +13,8 @@ void nfc_scene_read_emv_data_success_widget_callback( | |||||||
| 
 | 
 | ||||||
| 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 = (Nfc*)context; | ||||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; |     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     // Add frame
 |     // Add frame
 | ||||||
| @ -34,7 +34,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|         nfc); |         nfc); | ||||||
|     // Add card name
 |     // Add card name
 | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name); |         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); | ||||||
|     // Add cad number
 |     // Add cad number
 | ||||||
|     string_t pan_str; |     string_t pan_str; | ||||||
|     string_init(pan_str); |     string_init(pan_str); | ||||||
| @ -49,7 +49,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|     string_t country_name; |     string_t country_name; | ||||||
|     string_init(country_name); |     string_init(country_name); | ||||||
|     if((emv_data->country_code) && |     if((emv_data->country_code) && | ||||||
|        nfc_emv_parser_get_country_name(emv_data->country_code, country_name)) { |        nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) { | ||||||
|         string_t disp_country; |         string_t disp_country; | ||||||
|         string_init_printf(disp_country, "Reg:%s", country_name); |         string_init_printf(disp_country, "Reg:%s", country_name); | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
| @ -61,7 +61,8 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | |||||||
|     string_t currency_name; |     string_t currency_name; | ||||||
|     string_init(currency_name); |     string_init(currency_name); | ||||||
|     if((emv_data->currency_code) && |     if((emv_data->currency_code) && | ||||||
|        nfc_emv_parser_get_currency_name(emv_data->currency_code, currency_name)) { |        nfc_emv_parser_get_currency_name( | ||||||
|  |            nfc->dev->storage, emv_data->currency_code, currency_name)) { | ||||||
|         string_t disp_currency; |         string_t disp_currency; | ||||||
|         string_init_printf(disp_currency, "Cur:%s", currency_name); |         string_init_printf(disp_currency, "Cur:%s", currency_name); | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
| @ -122,8 +123,8 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e | |||||||
|                 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; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) { | |||||||
|     nfc_worker_start( |     nfc_worker_start( | ||||||
|         nfc->worker, |         nfc->worker, | ||||||
|         NfcWorkerStateReadMifareUl, |         NfcWorkerStateReadMifareUl, | ||||||
|         &nfc->dev.dev_data, |         &nfc->dev->dev_data, | ||||||
|         nfc_read_mifare_ul_worker_callback, |         nfc_read_mifare_ul_worker_callback, | ||||||
|         nfc); |         nfc); | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
|     notification_message(nfc->notifications, &sequence_success); |     notification_message(nfc->notifications, &sequence_success); | ||||||
| 
 | 
 | ||||||
|     // Setup dialog view
 |     // Setup dialog view
 | ||||||
|     NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_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"); | ||||||
| @ -54,7 +54,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); | ||||||
| 
 | 
 | ||||||
|     // Setup TextBox view
 |     // Setup TextBox view
 | ||||||
|     MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data; |     MifareUlData* 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_context(text_box, nfc); |     text_box_set_context(text_box, nfc); | ||||||
|     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); |     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); | ||||||
|  | |||||||
| @ -15,11 +15,11 @@ void nfc_scene_save_name_on_enter(void* context) { | |||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     TextInput* text_input = nfc->text_input; |     TextInput* text_input = nfc->text_input; | ||||||
|     bool dev_name_empty = false; |     bool dev_name_empty = false; | ||||||
|     if(!strcmp(nfc->dev.dev_name, "")) { |     if(!strcmp(nfc->dev->dev_name, "")) { | ||||||
|         set_random_name(nfc->text_store, sizeof(nfc->text_store)); |         set_random_name(nfc->text_store, sizeof(nfc->text_store)); | ||||||
|         dev_name_empty = true; |         dev_name_empty = true; | ||||||
|     } else { |     } else { | ||||||
|         nfc_text_store_set(nfc, nfc->dev.dev_name); |         nfc_text_store_set(nfc, nfc->dev->dev_name); | ||||||
|     } |     } | ||||||
|     text_input_set_header_text(text_input, "Name the card"); |     text_input_set_header_text(text_input, "Name the card"); | ||||||
|     text_input_set_result_callback( |     text_input_set_result_callback( | ||||||
| @ -37,14 +37,14 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { |         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { | ||||||
|             if(strcmp(nfc->dev.dev_name, "")) { |             if(strcmp(nfc->dev->dev_name, "")) { | ||||||
|                 nfc_device_delete(&nfc->dev); |                 nfc_device_delete(nfc->dev); | ||||||
|             } |             } | ||||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { |             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { | ||||||
|                 nfc->dev.dev_data.nfc_data = nfc->dev_edit_data; |                 nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; | ||||||
|             } |             } | ||||||
|             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; |                 return true; | ||||||
|             } else { |             } else { | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
|     Submenu* submenu = nfc->submenu; |     Submenu* submenu = nfc->submenu; | ||||||
| 
 | 
 | ||||||
|     if(nfc->dev.format != NfcDeviceSaveFormatBankCard) { |     if(nfc->dev->format != NfcDeviceSaveFormatBankCard) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); |             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     } |     } | ||||||
| @ -30,7 +30,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); | ||||||
|     if(nfc->dev.shadow_file_exist) { |     if(nfc->dev->shadow_file_exist) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Restore original", |             "Restore original", | ||||||
| @ -49,7 +49,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); | ||||||
|         if(event.event == SubmenuIndexEmulate) { |         if(event.event == SubmenuIndexEmulate) { | ||||||
|             if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { |             if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||||
| @ -65,7 +65,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexRestoreOriginal) { |         } else if(event.event == SubmenuIndexRestoreOriginal) { | ||||||
|             if(!nfc_device_restore(&nfc->dev)) { |             if(!nfc_device_restore(nfc->dev)) { | ||||||
|                 scene_manager_search_and_switch_to_previous_scene( |                 scene_manager_search_and_switch_to_previous_scene( | ||||||
|                     nfc->scene_manager, NfcSceneStart); |                     nfc->scene_manager, NfcSceneStart); | ||||||
|             } else { |             } else { | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ void nfc_scene_set_atqa_on_enter(void* context) { | |||||||
|         nfc_scene_set_atqa_byte_input_callback, |         nfc_scene_set_atqa_byte_input_callback, | ||||||
|         NULL, |         NULL, | ||||||
|         nfc, |         nfc, | ||||||
|         nfc->dev.dev_data.nfc_data.atqa, |         nfc->dev->dev_data.nfc_data.atqa, | ||||||
|         2); |         2); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ void nfc_scene_set_sak_on_enter(void* context) { | |||||||
|         nfc_scene_set_sak_byte_input_callback, |         nfc_scene_set_sak_byte_input_callback, | ||||||
|         NULL, |         NULL, | ||||||
|         nfc, |         nfc, | ||||||
|         &nfc->dev.dev_data.nfc_data.sak, |         &nfc->dev->dev_data.nfc_data.sak, | ||||||
|         1); |         1); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ void nfc_scene_set_type_on_enter(void* context) { | |||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* 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, ""); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); |         submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
| @ -28,13 +28,13 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|     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; |             return 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; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ void nfc_scene_set_uid_on_enter(void* context) { | |||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     ByteInput* byte_input = nfc->byte_input; |     ByteInput* byte_input = nfc->byte_input; | ||||||
|     byte_input_set_header_text(byte_input, "Enter uid in hex"); |     byte_input_set_header_text(byte_input, "Enter uid in hex"); | ||||||
|     nfc->dev_edit_data = nfc->dev.dev_data.nfc_data; |     nfc->dev_edit_data = nfc->dev->dev_data.nfc_data; | ||||||
|     byte_input_set_result_callback( |     byte_input_set_result_callback( | ||||||
|         byte_input, |         byte_input, | ||||||
|         nfc_scene_set_uid_byte_input_callback, |         nfc_scene_set_uid_byte_input_callback, | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ void nfc_scene_start_on_enter(void* context) { | |||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart)); |         submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart)); | ||||||
| 
 | 
 | ||||||
|     nfc_device_clear(&nfc->dev); |     nfc_device_clear(nfc->dev); | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -67,42 +67,14 @@ void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { | |||||||
|         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); |         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code) { | void bank_card_set_country_name(BankCard* bank_card, const char* country_name) { | ||||||
|     furi_assert(bank_card); |     furi_assert(bank_card); | ||||||
|     string_t country_name; |     widget_add_string_element( | ||||||
|     string_init(country_name); |         bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name); | ||||||
|     if(nfc_emv_parser_get_country_name(country_code, country_name)) { |  | ||||||
|         string_t disp_country; |  | ||||||
|         string_init_printf(disp_country, "Reg:%s", country_name); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             bank_card->widget, |  | ||||||
|             120, |  | ||||||
|             18, |  | ||||||
|             AlignRight, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             string_get_cstr(disp_country)); |  | ||||||
|         string_clear(disp_country); |  | ||||||
|     } |  | ||||||
|     string_clear(country_name); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code) { | void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) { | ||||||
|     furi_assert(bank_card); |     furi_assert(bank_card); | ||||||
|     string_t currency_name; |     widget_add_string_element( | ||||||
|     string_init(currency_name); |         bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name); | ||||||
|     if(nfc_emv_parser_get_currency_name(currency_code, currency_name)) { |  | ||||||
|         string_t disp_currency; |  | ||||||
|         string_init_printf(disp_currency, "Cur:%s", currency_name); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             bank_card->widget, |  | ||||||
|             31, |  | ||||||
|             18, |  | ||||||
|             AlignLeft, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             string_get_cstr(disp_currency)); |  | ||||||
|         string_clear(disp_currency); |  | ||||||
|     } |  | ||||||
|     string_clear(currency_name); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,6 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len); | |||||||
| 
 | 
 | ||||||
| void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); | void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); | ||||||
| 
 | 
 | ||||||
| void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code); | void bank_card_set_country_name(BankCard* bank_card, const char* country_name); | ||||||
| 
 | 
 | ||||||
| void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code); | void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name); | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ | |||||||
| #include "notification-messages.h" | #include "notification-messages.h" | ||||||
| #include "notification-app.h" | #include "notification-app.h" | ||||||
| 
 | 
 | ||||||
|  | #define TAG "NotificationSrv" | ||||||
|  | 
 | ||||||
| static const uint8_t minimal_delay = 100; | static const uint8_t minimal_delay = 100; | ||||||
| static const uint8_t led_off_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; | static const uint8_t led_off_values[NOTIFICATION_LED_COUNT] = {0x00, 0x00, 0x00}; | ||||||
| 
 | 
 | ||||||
| @ -314,7 +316,7 @@ static bool notification_load_settings(NotificationApp* app) { | |||||||
|     File* file = storage_file_alloc(furi_record_open("storage")); |     File* file = storage_file_alloc(furi_record_open("storage")); | ||||||
|     const size_t settings_size = sizeof(NotificationSettings); |     const size_t settings_size = sizeof(NotificationSettings); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("notification", "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH); |     FURI_LOG_I(TAG, "loading settings from \"%s\"", NOTIFICATION_SETTINGS_PATH); | ||||||
|     bool fs_result = |     bool fs_result = | ||||||
|         storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); |         storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||||
| 
 | 
 | ||||||
| @ -327,21 +329,18 @@ static bool notification_load_settings(NotificationApp* app) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(fs_result) { |     if(fs_result) { | ||||||
|         FURI_LOG_I("notification", "load success"); |         FURI_LOG_I(TAG, "load success"); | ||||||
| 
 | 
 | ||||||
|         if(settings.version != NOTIFICATION_SETTINGS_VERSION) { |         if(settings.version != NOTIFICATION_SETTINGS_VERSION) { | ||||||
|             FURI_LOG_E( |             FURI_LOG_E( | ||||||
|                 "notification", |                 TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); | ||||||
|                 "version(%d != %d) mismatch", |  | ||||||
|                 settings.version, |  | ||||||
|                 NOTIFICATION_SETTINGS_VERSION); |  | ||||||
|         } else { |         } else { | ||||||
|             osKernelLock(); |             osKernelLock(); | ||||||
|             memcpy(&app->settings, &settings, settings_size); |             memcpy(&app->settings, &settings, settings_size); | ||||||
|             osKernelUnlock(); |             osKernelUnlock(); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E("notification", "load failed, %s", storage_file_get_error_desc(file)); |         FURI_LOG_E(TAG, "load failed, %s", storage_file_get_error_desc(file)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
| @ -356,7 +355,7 @@ static bool notification_save_settings(NotificationApp* app) { | |||||||
|     File* file = storage_file_alloc(furi_record_open("storage")); |     File* file = storage_file_alloc(furi_record_open("storage")); | ||||||
|     const size_t settings_size = sizeof(NotificationSettings); |     const size_t settings_size = sizeof(NotificationSettings); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("notification", "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH); |     FURI_LOG_I(TAG, "saving settings to \"%s\"", NOTIFICATION_SETTINGS_PATH); | ||||||
| 
 | 
 | ||||||
|     osKernelLock(); |     osKernelLock(); | ||||||
|     memcpy(&settings, &app->settings, settings_size); |     memcpy(&settings, &app->settings, settings_size); | ||||||
| @ -374,9 +373,9 @@ static bool notification_save_settings(NotificationApp* app) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(fs_result) { |     if(fs_result) { | ||||||
|         FURI_LOG_I("notification", "save success"); |         FURI_LOG_I(TAG, "save success"); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_E("notification", "save failed, %s", storage_file_get_error_desc(file)); |         FURI_LOG_E(TAG, "save failed, %s", storage_file_get_error_desc(file)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include <cmsis_os2.h> | #include <cmsis_os2.h> | ||||||
| #include <portmacro.h> | #include <portmacro.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  | 
 | ||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| @ -16,14 +17,12 @@ | |||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include <m-dict.h> | #include <m-dict.h> | ||||||
| 
 | 
 | ||||||
| #define RPC_TAG "RPC" | #define TAG "RpcSrv" | ||||||
| 
 | 
 | ||||||
| #define RPC_EVENT_NEW_DATA (1 << 0) | #define RPC_EVENT_NEW_DATA (1 << 0) | ||||||
| #define RPC_EVENT_DISCONNECT (1 << 1) | #define RPC_EVENT_DISCONNECT (1 << 1) | ||||||
| #define RPC_EVENTS_ALL (RPC_EVENT_DISCONNECT | RPC_EVENT_NEW_DATA) | #define RPC_EVENTS_ALL (RPC_EVENT_DISCONNECT | RPC_EVENT_NEW_DATA) | ||||||
| 
 | 
 | ||||||
| #define DEBUG_PRINT 0 |  | ||||||
| 
 |  | ||||||
| DICT_DEF2(RpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, RpcHandler, M_POD_OPLIST) | DICT_DEF2(RpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, RpcHandler, M_POD_OPLIST) | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -53,6 +52,7 @@ static RpcSystemCallbacks rpc_systems[] = { | |||||||
| 
 | 
 | ||||||
| struct RpcSession { | struct RpcSession { | ||||||
|     RpcSendBytesCallback send_bytes_callback; |     RpcSendBytesCallback send_bytes_callback; | ||||||
|  |     RpcBufferIsEmptyCallback buffer_is_empty_callback; | ||||||
|     RpcSessionClosedCallback closed_callback; |     RpcSessionClosedCallback closed_callback; | ||||||
|     void* context; |     void* context; | ||||||
|     osMutexId_t callbacks_mutex; |     osMutexId_t callbacks_mutex; | ||||||
| @ -263,6 +263,7 @@ void rpc_print_message(const PB_Main* message) { | |||||||
|         size_t msg_file_count = message->content.storage_list_response.file_count; |         size_t msg_file_count = message->content.storage_list_response.file_count; | ||||||
|         string_cat_printf(str, "\tlist_response {\r\n"); |         string_cat_printf(str, "\tlist_response {\r\n"); | ||||||
|         rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count); |         rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|     case PB_Main_gui_start_screen_stream_request_tag: |     case PB_Main_gui_start_screen_stream_request_tag: | ||||||
|         string_cat_printf(str, "\tstart_screen_stream {\r\n"); |         string_cat_printf(str, "\tstart_screen_stream {\r\n"); | ||||||
| @ -270,8 +271,8 @@ void rpc_print_message(const PB_Main* message) { | |||||||
|     case PB_Main_gui_stop_screen_stream_request_tag: |     case PB_Main_gui_stop_screen_stream_request_tag: | ||||||
|         string_cat_printf(str, "\tstop_screen_stream {\r\n"); |         string_cat_printf(str, "\tstop_screen_stream {\r\n"); | ||||||
|         break; |         break; | ||||||
|     case PB_Main_gui_screen_stream_frame_tag: |     case PB_Main_gui_screen_frame_tag: | ||||||
|         string_cat_printf(str, "\tscreen_stream_frame {\r\n"); |         string_cat_printf(str, "\tscreen_frame {\r\n"); | ||||||
|         break; |         break; | ||||||
|     case PB_Main_gui_send_input_event_request_tag: |     case PB_Main_gui_send_input_event_request_tag: | ||||||
|         string_cat_printf(str, "\tsend_input_event {\r\n"); |         string_cat_printf(str, "\tsend_input_event {\r\n"); | ||||||
| @ -280,6 +281,12 @@ void rpc_print_message(const PB_Main* message) { | |||||||
|         string_cat_printf( |         string_cat_printf( | ||||||
|             str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); |             str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); | ||||||
|         break; |         break; | ||||||
|  |     case PB_Main_gui_start_virtual_display_request_tag: | ||||||
|  |         string_cat_printf(str, "\tstart_virtual_display {\r\n"); | ||||||
|  |         break; | ||||||
|  |     case PB_Main_gui_stop_virtual_display_request_tag: | ||||||
|  |         string_cat_printf(str, "\tstop_virtual_display {\r\n"); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|     string_cat_printf(str, "\t}\r\n}\r\n"); |     string_cat_printf(str, "\t}\r\n}\r\n"); | ||||||
|     printf("%s", string_get_cstr(str)); |     printf("%s", string_get_cstr(str)); | ||||||
| @ -292,7 +299,7 @@ static Rpc* rpc_alloc(void) { | |||||||
|     rpc->busy_mutex = osMutexNew(NULL); |     rpc->busy_mutex = osMutexNew(NULL); | ||||||
|     rpc->busy = false; |     rpc->busy = false; | ||||||
|     rpc->events = osEventFlagsNew(NULL); |     rpc->events = osEventFlagsNew(NULL); | ||||||
|     rpc->stream = xStreamBufferCreate(256, 1); |     rpc->stream = xStreamBufferCreate(RPC_BUFFER_SIZE, 1); | ||||||
| 
 | 
 | ||||||
|     rpc->decoded_message = furi_alloc(sizeof(PB_Main)); |     rpc->decoded_message = furi_alloc(sizeof(PB_Main)); | ||||||
|     rpc->decoded_message->cb_content.funcs.decode = content_callback; |     rpc->decoded_message->cb_content.funcs.decode = content_callback; | ||||||
| @ -334,7 +341,7 @@ RpcSession* rpc_session_open(Rpc* rpc) { | |||||||
|         }; |         }; | ||||||
|         rpc_add_handler(rpc, PB_Main_stop_session_tag, &rpc_handler); |         rpc_add_handler(rpc, PB_Main_stop_session_tag, &rpc_handler); | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_D(RPC_TAG, "Session started\r\n"); |         FURI_LOG_D(TAG, "Session started\r\n"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return result ? &rpc->session : NULL; /* support 1 open session for now */ |     return result ? &rpc->session : NULL; /* support 1 open session for now */ | ||||||
| @ -365,6 +372,7 @@ static void rpc_free_session(RpcSession* session) { | |||||||
|     session->context = NULL; |     session->context = NULL; | ||||||
|     session->closed_callback = NULL; |     session->closed_callback = NULL; | ||||||
|     session->send_bytes_callback = NULL; |     session->send_bytes_callback = NULL; | ||||||
|  |     session->buffer_is_empty_callback = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rpc_session_set_context(RpcSession* session, void* context) { | void rpc_session_set_context(RpcSession* session, void* context) { | ||||||
| @ -397,6 +405,18 @@ void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallba | |||||||
|     osMutexRelease(session->callbacks_mutex); |     osMutexRelease(session->callbacks_mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void rpc_session_set_buffer_is_empty_callback( | ||||||
|  |     RpcSession* session, | ||||||
|  |     RpcBufferIsEmptyCallback callback) { | ||||||
|  |     furi_assert(session); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     furi_assert(session->rpc->busy); | ||||||
|  | 
 | ||||||
|  |     osMutexAcquire(session->callbacks_mutex, osWaitForever); | ||||||
|  |     session->buffer_is_empty_callback = callback; | ||||||
|  |     osMutexRelease(session->callbacks_mutex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Doesn't forbid using rpc_feed_bytes() after session close - it's safe.
 | /* Doesn't forbid using rpc_feed_bytes() after session close - it's safe.
 | ||||||
|  * Because any bytes received in buffer will be flushed before next session. |  * Because any bytes received in buffer will be flushed before next session. | ||||||
|  * If bytes get into stream buffer before it's get epmtified and this |  * If bytes get into stream buffer before it's get epmtified and this | ||||||
| @ -415,6 +435,12 @@ size_t | |||||||
|     return bytes_sent; |     return bytes_sent; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | size_t rpc_session_get_available_size(RpcSession* session) { | ||||||
|  |     furi_assert(session); | ||||||
|  |     Rpc* rpc = session->rpc; | ||||||
|  |     return xStreamBufferSpacesAvailable(rpc->stream); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { | bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { | ||||||
|     Rpc* rpc = istream->state; |     Rpc* rpc = istream->state; | ||||||
|     uint32_t flags = 0; |     uint32_t flags = 0; | ||||||
| @ -425,6 +451,11 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { | |||||||
|     while(1) { |     while(1) { | ||||||
|         bytes_received += |         bytes_received += | ||||||
|             xStreamBufferReceive(rpc->stream, buf + bytes_received, count - bytes_received, 0); |             xStreamBufferReceive(rpc->stream, buf + bytes_received, count - bytes_received, 0); | ||||||
|  |         if(xStreamBufferIsEmpty(rpc->stream)) { | ||||||
|  |             if(rpc->session.buffer_is_empty_callback) { | ||||||
|  |                 rpc->session.buffer_is_empty_callback(rpc->session.context); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         if(count == bytes_received) { |         if(count == bytes_received) { | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
| @ -443,7 +474,7 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #if DEBUG_PRINT | #if SRV_RPC_DEBUG | ||||||
|     rpc_print_data("INPUT", buf, bytes_received); |     rpc_print_data("INPUT", buf, bytes_received); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -456,8 +487,8 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) { | |||||||
|     RpcSession* session = &rpc->session; |     RpcSession* session = &rpc->session; | ||||||
|     pb_ostream_t ostream = PB_OSTREAM_SIZING; |     pb_ostream_t ostream = PB_OSTREAM_SIZING; | ||||||
| 
 | 
 | ||||||
| #if DEBUG_PRINT | #if SRV_RPC_DEBUG | ||||||
|     FURI_LOG_I(RPC_TAG, "OUTPUT:"); |     FURI_LOG_I(TAG, "OUTPUT:"); | ||||||
|     rpc_print_message(message); |     rpc_print_message(message); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -469,7 +500,7 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) { | |||||||
| 
 | 
 | ||||||
|     pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED); |     pb_encode_ex(&ostream, &PB_Main_msg, message, PB_ENCODE_DELIMITED); | ||||||
| 
 | 
 | ||||||
| #if DEBUG_PRINT | #if SRV_RPC_DEBUG | ||||||
|     rpc_print_data("OUTPUT", buffer, ostream.bytes_written); |     rpc_print_data("OUTPUT", buffer, ostream.bytes_written); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -510,12 +541,12 @@ int32_t rpc_srv(void* p) { | |||||||
|             .callback = rpc_pb_stream_read, |             .callback = rpc_pb_stream_read, | ||||||
|             .state = rpc, |             .state = rpc, | ||||||
|             .errmsg = NULL, |             .errmsg = NULL, | ||||||
|             .bytes_left = 1024, /* max incoming message size */ |             .bytes_left = RPC_MAX_MESSAGE_SIZE, /* max incoming message size */ | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         if(pb_decode_ex(&istream, &PB_Main_msg, rpc->decoded_message, PB_DECODE_DELIMITED)) { |         if(pb_decode_ex(&istream, &PB_Main_msg, rpc->decoded_message, PB_DECODE_DELIMITED)) { | ||||||
| #if DEBUG_PRINT | #if SRV_RPC_DEBUG | ||||||
|             FURI_LOG_I(RPC_TAG, "INPUT:"); |             FURI_LOG_I(TAG, "INPUT:"); | ||||||
|             rpc_print_message(rpc->decoded_message); |             rpc_print_message(rpc->decoded_message); | ||||||
| #endif | #endif | ||||||
|             RpcHandler* handler = |             RpcHandler* handler = | ||||||
| @ -524,20 +555,19 @@ int32_t rpc_srv(void* p) { | |||||||
|             if(handler && handler->message_handler) { |             if(handler && handler->message_handler) { | ||||||
|                 handler->message_handler(rpc->decoded_message, handler->context); |                 handler->message_handler(rpc->decoded_message, handler->context); | ||||||
|             } else if(!handler && !rpc->session.terminate) { |             } else if(!handler && !rpc->session.terminate) { | ||||||
|                 FURI_LOG_E( |                 FURI_LOG_E(TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content); | ||||||
|                     RPC_TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content); |  | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             xStreamBufferReset(rpc->stream); |             xStreamBufferReset(rpc->stream); | ||||||
|             if(!rpc->session.terminate) { |             if(!rpc->session.terminate) { | ||||||
|                 FURI_LOG_E(RPC_TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream)); |                 FURI_LOG_E(TAG, "Decode failed, error: \'%.128s\'", PB_GET_ERROR(&istream)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         pb_release(&PB_Main_msg, rpc->decoded_message); |         pb_release(&PB_Main_msg, rpc->decoded_message); | ||||||
| 
 | 
 | ||||||
|         if(rpc->session.terminate) { |         if(rpc->session.terminate) { | ||||||
|             FURI_LOG_D(RPC_TAG, "Session terminated"); |             FURI_LOG_D(TAG, "Session terminated"); | ||||||
|             osEventFlagsClear(rpc->events, RPC_EVENTS_ALL); |             osEventFlagsClear(rpc->events, RPC_EVENTS_ALL); | ||||||
|             rpc_free_session(&rpc->session); |             rpc_free_session(&rpc->session); | ||||||
|             rpc->busy = false; |             rpc->busy = false; | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								applications/rpc/rpc.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										22
									
								
								applications/rpc/rpc.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -4,6 +4,9 @@ | |||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include "cmsis_os.h" | #include "cmsis_os.h" | ||||||
| 
 | 
 | ||||||
|  | #define RPC_BUFFER_SIZE (1024) | ||||||
|  | #define RPC_MAX_MESSAGE_SIZE (1536) | ||||||
|  | 
 | ||||||
| /** Rpc interface. Used for opening session only. */ | /** Rpc interface. Used for opening session only. */ | ||||||
| typedef struct Rpc Rpc; | typedef struct Rpc Rpc; | ||||||
| /** Rpc session interface */ | /** Rpc session interface */ | ||||||
| @ -11,6 +14,8 @@ typedef struct RpcSession RpcSession; | |||||||
| 
 | 
 | ||||||
| /** Callback to send to client any data (e.g. response to command) */ | /** Callback to send to client any data (e.g. response to command) */ | ||||||
| typedef void (*RpcSendBytesCallback)(void* context, uint8_t* bytes, size_t bytes_len); | typedef void (*RpcSendBytesCallback)(void* context, uint8_t* bytes, size_t bytes_len); | ||||||
|  | /** Callback to notify client that buffer is empty */ | ||||||
|  | typedef void (*RpcBufferIsEmptyCallback)(void* context); | ||||||
| /** Callback to notify transport layer that close_session command
 | /** Callback to notify transport layer that close_session command
 | ||||||
|  * is received. Any other actions lays on transport layer. |  * is received. Any other actions lays on transport layer. | ||||||
|  * No destruction or session close preformed. */ |  * No destruction or session close preformed. */ | ||||||
| @ -59,6 +64,15 @@ void rpc_session_set_context(RpcSession* session, void* context); | |||||||
|  */ |  */ | ||||||
| void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallback callback); | void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallback callback); | ||||||
| 
 | 
 | ||||||
|  | /** Set callback to notify that buffer is empty
 | ||||||
|  |  * | ||||||
|  |  * @param   session     pointer to RpcSession descriptor | ||||||
|  |  * @param   callback    callback to notify client that buffer is empty (can be NULL) | ||||||
|  |  */ | ||||||
|  | void rpc_session_set_buffer_is_empty_callback( | ||||||
|  |     RpcSession* session, | ||||||
|  |     RpcBufferIsEmptyCallback callback); | ||||||
|  | 
 | ||||||
| /** Set callback to be called when RPC command to close session is received
 | /** Set callback to be called when RPC command to close session is received
 | ||||||
|  *  WARN: It's forbidden to call RPC API within RpcSessionClosedCallback |  *  WARN: It's forbidden to call RPC API within RpcSessionClosedCallback | ||||||
|  * |  * | ||||||
| @ -77,3 +91,11 @@ void rpc_session_set_close_callback(RpcSession* session, RpcSessionClosedCallbac | |||||||
|  * @return              actually consumed bytes |  * @return              actually consumed bytes | ||||||
|  */ |  */ | ||||||
| size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, TickType_t timeout); | size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, TickType_t timeout); | ||||||
|  | 
 | ||||||
|  | /** Get available size of RPC buffer
 | ||||||
|  |  * | ||||||
|  |  * @param   session     pointer to RpcSession descriptor | ||||||
|  |  * | ||||||
|  |  * @return              bytes available in buffer | ||||||
|  |  */ | ||||||
|  | size_t rpc_session_get_available_size(RpcSession* session); | ||||||
|  | |||||||
| @ -1,14 +1,14 @@ | |||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <rpc/rpc.h> | #include <rpc/rpc.h> | ||||||
| #include <furi-hal-vcp.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     Cli* cli; |     Cli* cli; | ||||||
|     bool session_close_request; |     bool session_close_request; | ||||||
| } CliRpc; | } CliRpc; | ||||||
| 
 | 
 | ||||||
| #define CLI_READ_BUFFER_SIZE 100 | #define CLI_READ_BUFFER_SIZE 64 | ||||||
| 
 | 
 | ||||||
| static void rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) { | static void rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t bytes_len) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -50,7 +50,8 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(size_received) { |         if(size_received) { | ||||||
|             rpc_session_feed(rpc_session, buffer, size_received, 3000); |             furi_assert( | ||||||
|  |                 rpc_session_feed(rpc_session, buffer, size_received, 3000) == size_received); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,12 +3,17 @@ | |||||||
| #include "gui.pb.h" | #include "gui.pb.h" | ||||||
| #include <gui/gui_i.h> | #include <gui/gui_i.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "RpcGui" | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     Rpc* rpc; |     Rpc* rpc; | ||||||
|     Gui* gui; |     Gui* gui; | ||||||
|  |     ViewPort* virtual_display_view_port; | ||||||
|  |     uint8_t* virtual_display_buffer; | ||||||
|  |     bool virtual_display_not_empty; | ||||||
| } RpcGuiSystem; | } RpcGuiSystem; | ||||||
| 
 | 
 | ||||||
| void rpc_system_gui_screen_frame_callback(uint8_t* data, size_t size, void* context) { | void rpc_system_gui_screen_stream_frame_callback(uint8_t* data, size_t size, void* context) { | ||||||
|     furi_assert(data); |     furi_assert(data); | ||||||
|     furi_assert(size == 1024); |     furi_assert(size == 1024); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -17,11 +22,11 @@ void rpc_system_gui_screen_frame_callback(uint8_t* data, size_t size, void* cont | |||||||
| 
 | 
 | ||||||
|     PB_Main* frame = furi_alloc(sizeof(PB_Main)); |     PB_Main* frame = furi_alloc(sizeof(PB_Main)); | ||||||
| 
 | 
 | ||||||
|     frame->which_content = PB_Main_gui_screen_stream_frame_tag; |     frame->which_content = PB_Main_gui_screen_frame_tag; | ||||||
|     frame->command_status = PB_CommandStatus_OK; |     frame->command_status = PB_CommandStatus_OK; | ||||||
|     frame->content.gui_screen_stream_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size)); |     frame->content.gui_screen_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size)); | ||||||
|     uint8_t* buffer = frame->content.gui_screen_stream_frame.data->bytes; |     uint8_t* buffer = frame->content.gui_screen_frame.data->bytes; | ||||||
|     uint16_t* frame_size_msg = &frame->content.gui_screen_stream_frame.data->size; |     uint16_t* frame_size_msg = &frame->content.gui_screen_frame.data->size; | ||||||
|     *frame_size_msg = size; |     *frame_size_msg = size; | ||||||
|     memcpy(buffer, data, size); |     memcpy(buffer, data, size); | ||||||
| 
 | 
 | ||||||
| @ -37,7 +42,8 @@ void rpc_system_gui_start_screen_stream_process(const PB_Main* request, void* co | |||||||
| 
 | 
 | ||||||
|     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); |     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); | ||||||
| 
 | 
 | ||||||
|     gui_set_framebuffer_callback(rpc_gui->gui, rpc_system_gui_screen_frame_callback, context); |     gui_set_framebuffer_callback( | ||||||
|  |         rpc_gui->gui, rpc_system_gui_screen_stream_frame_callback, context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) { | void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* context) { | ||||||
| @ -45,9 +51,9 @@ void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* con | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     RpcGuiSystem* rpc_gui = context; |     RpcGuiSystem* rpc_gui = context; | ||||||
| 
 | 
 | ||||||
|     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); |  | ||||||
| 
 |  | ||||||
|     gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); |     gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); | ||||||
|  | 
 | ||||||
|  |     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void rpc_system_gui_send_input_event_request_process(const PB_Main* request, void* context) { | void rpc_system_gui_send_input_event_request_process(const PB_Main* request, void* context) { | ||||||
| @ -120,6 +126,88 @@ void rpc_system_gui_send_input_event_request_process(const PB_Main* request, voi | |||||||
|     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); |     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void rpc_system_gui_virtual_display_render_callback(Canvas* canvas, void* context) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     furi_assert(context); | ||||||
|  |     RpcGuiSystem* rpc_gui = context; | ||||||
|  | 
 | ||||||
|  |     if(!rpc_gui->virtual_display_not_empty) { | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignCenter, "Virtual Display"); | ||||||
|  |         canvas_draw_str_aligned(canvas, 64, 36, AlignCenter, AlignCenter, "Waiting for frames..."); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     canvas_draw_xbm(canvas, 0, 0, canvas->width, canvas->height, rpc_gui->virtual_display_buffer); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void rpc_system_gui_start_virtual_display_process(const PB_Main* request, void* context) { | ||||||
|  |     furi_assert(request); | ||||||
|  |     furi_assert(context); | ||||||
|  |     RpcGuiSystem* rpc_gui = context; | ||||||
|  | 
 | ||||||
|  |     if(rpc_gui->virtual_display_view_port) { | ||||||
|  |         rpc_send_and_release_empty( | ||||||
|  |             rpc_gui->rpc, | ||||||
|  |             request->command_id, | ||||||
|  |             PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO: consider refactoring
 | ||||||
|  |     // Using display framebuffer size as an XBM buffer size is like comparing apples and oranges
 | ||||||
|  |     // Glad they both are 1024 for now
 | ||||||
|  |     size_t buffer_size = canvas_get_buffer_size(rpc_gui->gui->canvas); | ||||||
|  |     rpc_gui->virtual_display_buffer = furi_alloc(buffer_size); | ||||||
|  |     rpc_gui->virtual_display_view_port = view_port_alloc(); | ||||||
|  |     view_port_draw_callback_set( | ||||||
|  |         rpc_gui->virtual_display_view_port, | ||||||
|  |         rpc_system_gui_virtual_display_render_callback, | ||||||
|  |         rpc_gui); | ||||||
|  |     gui_add_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port, GuiLayerFullscreen); | ||||||
|  | 
 | ||||||
|  |     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void rpc_system_gui_stop_virtual_display_process(const PB_Main* request, void* context) { | ||||||
|  |     furi_assert(request); | ||||||
|  |     furi_assert(context); | ||||||
|  |     RpcGuiSystem* rpc_gui = context; | ||||||
|  | 
 | ||||||
|  |     if(!rpc_gui->virtual_display_view_port) { | ||||||
|  |         rpc_send_and_release_empty( | ||||||
|  |             rpc_gui->rpc, request->command_id, PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     gui_remove_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port); | ||||||
|  |     view_port_free(rpc_gui->virtual_display_view_port); | ||||||
|  |     free(rpc_gui->virtual_display_buffer); | ||||||
|  |     rpc_gui->virtual_display_view_port = NULL; | ||||||
|  |     rpc_gui->virtual_display_not_empty = false; | ||||||
|  | 
 | ||||||
|  |     rpc_send_and_release_empty(rpc_gui->rpc, request->command_id, PB_CommandStatus_OK); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void rpc_system_gui_virtual_display_frame_process(const PB_Main* request, void* context) { | ||||||
|  |     furi_assert(request); | ||||||
|  |     furi_assert(context); | ||||||
|  |     RpcGuiSystem* rpc_gui = context; | ||||||
|  | 
 | ||||||
|  |     if(!rpc_gui->virtual_display_view_port) { | ||||||
|  |         FURI_LOG_W(TAG, "Virtual display is not started, ignoring incoming frame packet"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t buffer_size = canvas_get_buffer_size(rpc_gui->gui->canvas); | ||||||
|  |     memcpy( | ||||||
|  |         rpc_gui->virtual_display_buffer, | ||||||
|  |         request->content.gui_screen_frame.data->bytes, | ||||||
|  |         buffer_size); | ||||||
|  |     rpc_gui->virtual_display_not_empty = true; | ||||||
|  |     view_port_update(rpc_gui->virtual_display_view_port); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void* rpc_system_gui_alloc(Rpc* rpc) { | void* rpc_system_gui_alloc(Rpc* rpc) { | ||||||
|     furi_assert(rpc); |     furi_assert(rpc); | ||||||
| 
 | 
 | ||||||
| @ -142,6 +230,15 @@ void* rpc_system_gui_alloc(Rpc* rpc) { | |||||||
|     rpc_handler.message_handler = rpc_system_gui_send_input_event_request_process; |     rpc_handler.message_handler = rpc_system_gui_send_input_event_request_process; | ||||||
|     rpc_add_handler(rpc, PB_Main_gui_send_input_event_request_tag, &rpc_handler); |     rpc_add_handler(rpc, PB_Main_gui_send_input_event_request_tag, &rpc_handler); | ||||||
| 
 | 
 | ||||||
|  |     rpc_handler.message_handler = rpc_system_gui_start_virtual_display_process; | ||||||
|  |     rpc_add_handler(rpc, PB_Main_gui_start_virtual_display_request_tag, &rpc_handler); | ||||||
|  | 
 | ||||||
|  |     rpc_handler.message_handler = rpc_system_gui_stop_virtual_display_process; | ||||||
|  |     rpc_add_handler(rpc, PB_Main_gui_stop_virtual_display_request_tag, &rpc_handler); | ||||||
|  | 
 | ||||||
|  |     rpc_handler.message_handler = rpc_system_gui_virtual_display_frame_process; | ||||||
|  |     rpc_add_handler(rpc, PB_Main_gui_screen_frame_tag, &rpc_handler); | ||||||
|  | 
 | ||||||
|     return rpc_gui; |     return rpc_gui; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -149,6 +246,15 @@ void rpc_system_gui_free(void* ctx) { | |||||||
|     furi_assert(ctx); |     furi_assert(ctx); | ||||||
|     RpcGuiSystem* rpc_gui = ctx; |     RpcGuiSystem* rpc_gui = ctx; | ||||||
|     furi_assert(rpc_gui->gui); |     furi_assert(rpc_gui->gui); | ||||||
|  | 
 | ||||||
|  |     if(rpc_gui->virtual_display_view_port) { | ||||||
|  |         gui_remove_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port); | ||||||
|  |         view_port_free(rpc_gui->virtual_display_view_port); | ||||||
|  |         free(rpc_gui->virtual_display_buffer); | ||||||
|  |         rpc_gui->virtual_display_view_port = NULL; | ||||||
|  |         rpc_gui->virtual_display_not_empty = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); |     gui_set_framebuffer_callback(rpc_gui->gui, NULL, NULL); | ||||||
|     furi_record_close("gui"); |     furi_record_close("gui"); | ||||||
|     free(rpc_gui); |     free(rpc_gui); | ||||||
|  | |||||||
| @ -463,3 +463,28 @@ bool storage_simply_mkdir(Storage* storage, const char* path) { | |||||||
|     result = storage_common_mkdir(storage, path); |     result = storage_common_mkdir(storage, path); | ||||||
|     return result == FSE_OK || result == FSE_EXIST; |     return result == FSE_OK || result == FSE_EXIST; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void storage_get_next_filename( | ||||||
|  |     Storage* storage, | ||||||
|  |     const char* dirname, | ||||||
|  |     const char* filename, | ||||||
|  |     const char* fileextension, | ||||||
|  |     string_t nextfilename) { | ||||||
|  |     string_t temp_str; | ||||||
|  |     uint16_t num = 0; | ||||||
|  | 
 | ||||||
|  |     string_init_printf(temp_str, "%s/%s%s", dirname, filename, fileextension); | ||||||
|  | 
 | ||||||
|  |     while(storage_common_stat(storage, string_get_cstr(temp_str), NULL) == FSE_OK) { | ||||||
|  |         num++; | ||||||
|  |         string_printf(temp_str, "%s/%s%d%s", dirname, filename, num, fileextension); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(num) { | ||||||
|  |         string_printf(nextfilename, "%s%d", filename, num); | ||||||
|  |     } else { | ||||||
|  |         string_printf(nextfilename, "%s", filename); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(temp_str); | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "storage-test" | #define TAG "StorageTest" | ||||||
| #define BYTES_COUNT 16 | #define BYTES_COUNT 16 | ||||||
| #define TEST_STRING "TestDataStringProvidedByDiceRoll" | #define TEST_STRING "TestDataStringProvidedByDiceRoll" | ||||||
| #define SEEK_OFFSET_FROM_START 10 | #define SEEK_OFFSET_FROM_START 10 | ||||||
|  | |||||||
| @ -262,6 +262,22 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path); | |||||||
|  */ |  */ | ||||||
| bool storage_simply_mkdir(Storage* storage, const char* path); | bool storage_simply_mkdir(Storage* storage, const char* path); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Get next free filename. | ||||||
|  |  *  | ||||||
|  |  * @param storage | ||||||
|  |  * @param dirname  | ||||||
|  |  * @param filename  | ||||||
|  |  * @param fileextension  | ||||||
|  |  * @param nextfilename return name | ||||||
|  |  */ | ||||||
|  | void storage_get_next_filename( | ||||||
|  |     Storage* storage, | ||||||
|  |     const char* dirname, | ||||||
|  |     const char* filename, | ||||||
|  |     const char* fileextension, | ||||||
|  |     string_t nextfilename); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ typedef DIR SDDir; | |||||||
| typedef FILINFO SDFileInfo; | typedef FILINFO SDFileInfo; | ||||||
| typedef FRESULT SDError; | typedef FRESULT SDError; | ||||||
| 
 | 
 | ||||||
| #define TAG "storage-ext" | #define TAG "StorageExt" | ||||||
| #define STORAGE_PATH "/ext" | #define STORAGE_PATH "/ext" | ||||||
| /********************* Definitions ********************/ | /********************* Definitions ********************/ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <lfs.h> | #include <lfs.h> | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "storage-int" | #define TAG "StorageInt" | ||||||
| #define STORAGE_PATH "/int" | #define STORAGE_PATH "/int" | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -121,7 +121,7 @@ static int storage_int_device_erase(const struct lfs_config* c, lfs_block_t bloc | |||||||
| 
 | 
 | ||||||
|     FURI_LOG_D(TAG, "Device erase: page %d, translated page: %x", block, page); |     FURI_LOG_D(TAG, "Device erase: page %d, translated page: %x", block, page); | ||||||
| 
 | 
 | ||||||
|     if(furi_hal_flash_erase(page, 1)) { |     if(furi_hal_flash_erase(page)) { | ||||||
|         return 0; |         return 0; | ||||||
|     } else { |     } else { | ||||||
|         return -1; |         return -1; | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() { | |||||||
|     SubGhzFrequencyAnalyzerWorker* instance = furi_alloc(sizeof(SubGhzFrequencyAnalyzerWorker)); |     SubGhzFrequencyAnalyzerWorker* instance = furi_alloc(sizeof(SubGhzFrequencyAnalyzerWorker)); | ||||||
| 
 | 
 | ||||||
|     instance->thread = furi_thread_alloc(); |     instance->thread = furi_thread_alloc(); | ||||||
|     furi_thread_set_name(instance->thread, "subghz_frequency_analyzer_worker"); |     furi_thread_set_name(instance->thread, "SubghzFAWorker"); | ||||||
|     furi_thread_set_stack_size(instance->thread, 2048); |     furi_thread_set_stack_size(instance->thread, 2048); | ||||||
|     furi_thread_set_context(instance->thread, instance); |     furi_thread_set_context(instance->thread, instance); | ||||||
|     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); |     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread); | ||||||
|  | |||||||
| @ -11,33 +11,33 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co | |||||||
| 
 | 
 | ||||||
| void subghz_scene_delete_on_enter(void* context) { | void subghz_scene_delete_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 |     string_t frequency_str; | ||||||
|     char buffer_str[16]; |     string_t modulation_str; | ||||||
|     snprintf( |  | ||||||
|         buffer_str, |  | ||||||
|         sizeof(buffer_str), |  | ||||||
|         "%03ld.%02ld", |  | ||||||
|         subghz->txrx->frequency / 1000000 % 1000, |  | ||||||
|         subghz->txrx->frequency / 10000 % 100); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); |  | ||||||
|     if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || |  | ||||||
|        subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { |  | ||||||
|         snprintf(buffer_str, sizeof(buffer_str), "AM"); |  | ||||||
|     } else if( |  | ||||||
|         subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || |  | ||||||
|         subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { |  | ||||||
|         snprintf(buffer_str, sizeof(buffer_str), "FM"); |  | ||||||
|     } else { |  | ||||||
|         furi_crash(NULL); |  | ||||||
|     } |  | ||||||
|     widget_add_string_element( |  | ||||||
|         subghz->widget, 113, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); |  | ||||||
|     string_t text; |     string_t text; | ||||||
|  | 
 | ||||||
|  |     string_init(frequency_str); | ||||||
|  |     string_init(modulation_str); | ||||||
|     string_init(text); |     string_init(text); | ||||||
|  | 
 | ||||||
|  |     subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|  |     widget_add_string_element( | ||||||
|  |         subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(frequency_str)); | ||||||
|  | 
 | ||||||
|  |     widget_add_string_element( | ||||||
|  |         subghz->widget, | ||||||
|  |         113, | ||||||
|  |         0, | ||||||
|  |         AlignLeft, | ||||||
|  |         AlignTop, | ||||||
|  |         FontSecondary, | ||||||
|  |         string_get_cstr(modulation_str)); | ||||||
|  | 
 | ||||||
|     subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); |     subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); | ||||||
|     widget_add_string_multiline_element( |     widget_add_string_multiline_element( | ||||||
|         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); |         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); | ||||||
|  | 
 | ||||||
|  |     string_clear(frequency_str); | ||||||
|  |     string_clear(modulation_str); | ||||||
|     string_clear(text); |     string_clear(text); | ||||||
| 
 | 
 | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
| @ -50,7 +50,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) { | ||||||
|             memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name)); |             memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name) + 1); | ||||||
|             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 { | ||||||
|  | |||||||
| @ -6,27 +6,19 @@ | |||||||
| static void subghz_scene_read_raw_update_statusbar(void* context) { | static void subghz_scene_read_raw_update_statusbar(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     char frequency_str[20]; |  | ||||||
|     char preset_str[10]; |  | ||||||
| 
 | 
 | ||||||
|     snprintf( |     string_t frequency_str; | ||||||
|         frequency_str, |     string_t modulation_str; | ||||||
|         sizeof(frequency_str), |  | ||||||
|         "%03ld.%02ld", |  | ||||||
|         subghz->txrx->frequency / 1000000 % 1000, |  | ||||||
|         subghz->txrx->frequency / 10000 % 100); |  | ||||||
|     if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || |  | ||||||
|        subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { |  | ||||||
|         snprintf(preset_str, sizeof(preset_str), "AM"); |  | ||||||
|     } else if( |  | ||||||
|         subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || |  | ||||||
|         subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { |  | ||||||
|         snprintf(preset_str, sizeof(preset_str), "FM"); |  | ||||||
|     } else { |  | ||||||
|         furi_crash(NULL); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     subghz_read_raw_add_data_statusbar(subghz->subghz_read_raw, frequency_str, preset_str); |     string_init(frequency_str); | ||||||
|  |     string_init(modulation_str); | ||||||
|  | 
 | ||||||
|  |     subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|  |     subghz_read_raw_add_data_statusbar( | ||||||
|  |         subghz->subghz_read_raw, string_get_cstr(frequency_str), string_get_cstr(modulation_str)); | ||||||
|  | 
 | ||||||
|  |     string_clear(frequency_str); | ||||||
|  |     string_clear(modulation_str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) { | void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) { | ||||||
| @ -70,7 +62,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; |             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|             subghz_protocol_raw_save_to_file_stop( |             subghz_protocol_raw_save_to_file_stop( | ||||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); |                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| 
 | 
 | ||||||
|             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { |             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { | ||||||
|                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; |                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; | ||||||
| @ -95,7 +87,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             }; |             }; | ||||||
|             subghz_protocol_raw_save_to_file_stop( |             subghz_protocol_raw_save_to_file_stop( | ||||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); |                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| 
 | 
 | ||||||
|             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; |             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; | ||||||
| 
 | 
 | ||||||
| @ -106,17 +98,18 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { |             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) { | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); | ||||||
|             } else { |             } else { | ||||||
|  |                 subghz_get_preset_name(subghz, subghz->error_str); | ||||||
|                 if(subghz_protocol_raw_save_to_file_init( |                 if(subghz_protocol_raw_save_to_file_init( | ||||||
|                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result, |                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result, | ||||||
|                        "Raw_temp", |                        "Raw_temp", | ||||||
|                        subghz->txrx->frequency, |                        subghz->txrx->frequency, | ||||||
|                        subghz->txrx->preset)) { |                        string_get_cstr(subghz->error_str))) { | ||||||
|                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || |                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || | ||||||
|                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { |                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { | ||||||
|                         subghz_begin(subghz, subghz->txrx->preset); |                         subghz_begin(subghz, subghz->txrx->preset); | ||||||
|                         subghz_rx(subghz, subghz->txrx->frequency); |                         subghz_rx(subghz, subghz->txrx->frequency); | ||||||
|                     } |                     } | ||||||
|                     subghz->state_notifications = NOTIFICATION_RX_STATE; |                     subghz->state_notifications = SubGhzNotificationStateRX; | ||||||
|                 } else { |                 } else { | ||||||
|                     string_set(subghz->error_str, "No SD card"); |                     string_set(subghz->error_str, "No SD card"); | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
| @ -127,14 +120,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|             break; |             break; | ||||||
|         case SubghzCustomEventViewReadRAWMore: |         case SubghzCustomEventViewReadRAWMore: | ||||||
|             if(strcmp( |             if(strcmp( | ||||||
|                    subghz_protocol_get_last_file_name( |                    subghz_protocol_raw_get_last_file_name( | ||||||
|                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result), |                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result), | ||||||
|                    "")) { |                    "")) { | ||||||
|                 strlcpy( |                 strlcpy( | ||||||
|                     subghz->file_name, |                     subghz->file_name, | ||||||
|                     subghz_protocol_get_last_file_name( |                     subghz_protocol_raw_get_last_file_name( | ||||||
|                         (SubGhzProtocolRAW*)subghz->txrx->protocol_result), |                         (SubGhzProtocolRAW*)subghz->txrx->protocol_result), | ||||||
|                     strlen(subghz_protocol_get_last_file_name( |                     strlen(subghz_protocol_raw_get_last_file_name( | ||||||
|                         (SubGhzProtocolRAW*)subghz->txrx->protocol_result)) + |                         (SubGhzProtocolRAW*)subghz->txrx->protocol_result)) + | ||||||
|                         1); |                         1); | ||||||
|                 //set the path to read the file
 |                 //set the path to read the file
 | ||||||
| @ -145,7 +138,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     SUBGHZ_APP_PATH_FOLDER, |                     SUBGHZ_APP_PATH_FOLDER, | ||||||
|                     subghz->file_name, |                     subghz->file_name, | ||||||
|                     SUBGHZ_APP_EXTENSION); |                     SUBGHZ_APP_EXTENSION); | ||||||
|                 subghz_protocol_set_last_file_name( |                 subghz_protocol_raw_set_last_file_name( | ||||||
|                     (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); |                     (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); | ||||||
|                 string_clear(temp_str); |                 string_clear(temp_str); | ||||||
| 
 | 
 | ||||||
| @ -159,7 +152,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         switch(subghz->state_notifications) { |         switch(subghz->state_notifications) { | ||||||
|         case NOTIFICATION_RX_STATE: |         case SubGhzNotificationStateRX: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|             subghz_read_raw_update_sample_write( |             subghz_read_raw_update_sample_write( | ||||||
|                 subghz->subghz_read_raw, |                 subghz->subghz_read_raw, | ||||||
| @ -182,7 +175,7 @@ void subghz_scene_read_raw_on_exit(void* context) { | |||||||
|         subghz_rx_end(subghz); |         subghz_rx_end(subghz); | ||||||
|         subghz_sleep(subghz); |         subghz_sleep(subghz); | ||||||
|     }; |     }; | ||||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; |     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| 
 | 
 | ||||||
|     //Сallback restoration
 |     //Сallback restoration
 | ||||||
|     subghz_worker_set_pair_callback( |     subghz_worker_set_pair_callback( | ||||||
|  | |||||||
| @ -3,33 +3,29 @@ | |||||||
| 
 | 
 | ||||||
| static void subghz_scene_receiver_update_statusbar(void* context) { | static void subghz_scene_receiver_update_statusbar(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     char frequency_str[20]; |  | ||||||
|     char preset_str[10]; |  | ||||||
|     string_t history_stat_str; |     string_t history_stat_str; | ||||||
|     string_init(history_stat_str); |     string_init(history_stat_str); | ||||||
|     if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { |     if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { | ||||||
|         snprintf( |         string_t frequency_str; | ||||||
|             frequency_str, |         string_t modulation_str; | ||||||
|             sizeof(frequency_str), | 
 | ||||||
|             "%03ld.%02ld", |         string_init(frequency_str); | ||||||
|             subghz->txrx->frequency / 1000000 % 1000, |         string_init(modulation_str); | ||||||
|             subghz->txrx->frequency / 10000 % 100); | 
 | ||||||
|         if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || |         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|            subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { | 
 | ||||||
|             snprintf(preset_str, sizeof(preset_str), "AM"); |  | ||||||
|         } else if( |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { |  | ||||||
|             snprintf(preset_str, sizeof(preset_str), "FM"); |  | ||||||
|         } else { |  | ||||||
|             furi_crash(NULL); |  | ||||||
|         } |  | ||||||
|         subghz_receiver_add_data_statusbar( |         subghz_receiver_add_data_statusbar( | ||||||
|             subghz->subghz_receiver, frequency_str, preset_str, string_get_cstr(history_stat_str)); |             subghz->subghz_receiver, | ||||||
|  |             string_get_cstr(frequency_str), | ||||||
|  |             string_get_cstr(modulation_str), | ||||||
|  |             string_get_cstr(history_stat_str)); | ||||||
|  | 
 | ||||||
|  |         string_clear(frequency_str); | ||||||
|  |         string_clear(modulation_str); | ||||||
|     } else { |     } else { | ||||||
|         subghz_receiver_add_data_statusbar( |         subghz_receiver_add_data_statusbar( | ||||||
|             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); |             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); | ||||||
|         subghz->state_notifications = NOTIFICATION_IDLE_STATE; |         subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|     } |     } | ||||||
|     string_clear(history_stat_str); |     string_clear(history_stat_str); | ||||||
| } | } | ||||||
| @ -83,7 +79,7 @@ void subghz_scene_receiver_on_enter(void* context) { | |||||||
|     subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); |     subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz); | ||||||
|     subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz); |     subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz->state_notifications = NOTIFICATION_RX_STATE; |     subghz->state_notifications = SubGhzNotificationStateRX; | ||||||
|     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|         subghz_rx_end(subghz); |         subghz_rx_end(subghz); | ||||||
|     }; |     }; | ||||||
| @ -104,7 +100,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case SubghzCustomEventViewReceverBack: |         case SubghzCustomEventViewReceverBack: | ||||||
|             // Stop CC1101 Rx
 |             // Stop CC1101 Rx
 | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|                 subghz_rx_end(subghz); |                 subghz_rx_end(subghz); | ||||||
|                 subghz_sleep(subghz); |                 subghz_sleep(subghz); | ||||||
| @ -125,7 +121,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|             return true; |             return true; | ||||||
|             break; |             break; | ||||||
|         case SubghzCustomEventViewReceverConfig: |         case SubghzCustomEventViewReceverConfig: | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); |             subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver); | ||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); | ||||||
|             return true; |             return true; | ||||||
| @ -140,7 +136,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         switch(subghz->state_notifications) { |         switch(subghz->state_notifications) { | ||||||
|         case NOTIFICATION_RX_STATE: |         case SubGhzNotificationStateRX: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|  | |||||||
| @ -40,35 +40,42 @@ void subghz_scene_receiver_info_on_enter(void* context) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(subghz_scene_receiver_info_update_parser(subghz)) { |     if(subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|         char buffer_str[16]; |         string_t frequency_str; | ||||||
|         snprintf( |         string_t modulation_str; | ||||||
|             buffer_str, |  | ||||||
|             sizeof(buffer_str), |  | ||||||
|             "%03ld.%02ld", |  | ||||||
|             subghz->txrx->frequency / 1000000 % 1000, |  | ||||||
|             subghz->txrx->frequency / 10000 % 100); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             subghz->widget, 78, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); |  | ||||||
|         if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || |  | ||||||
|            subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { |  | ||||||
|             snprintf(buffer_str, sizeof(buffer_str), "AM"); |  | ||||||
|         } else if( |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { |  | ||||||
|             snprintf(buffer_str, sizeof(buffer_str), "FM"); |  | ||||||
|         } else { |  | ||||||
|             furi_crash(NULL); |  | ||||||
|         } |  | ||||||
|         widget_add_string_element( |  | ||||||
|             subghz->widget, 113, 0, AlignLeft, AlignTop, FontSecondary, buffer_str); |  | ||||||
|         string_t text; |         string_t text; | ||||||
|  | 
 | ||||||
|  |         string_init(frequency_str); | ||||||
|  |         string_init(modulation_str); | ||||||
|         string_init(text); |         string_init(text); | ||||||
|  | 
 | ||||||
|  |         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|  |         widget_add_string_element( | ||||||
|  |             subghz->widget, | ||||||
|  |             78, | ||||||
|  |             0, | ||||||
|  |             AlignLeft, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary, | ||||||
|  |             string_get_cstr(frequency_str)); | ||||||
|  | 
 | ||||||
|  |         widget_add_string_element( | ||||||
|  |             subghz->widget, | ||||||
|  |             113, | ||||||
|  |             0, | ||||||
|  |             AlignLeft, | ||||||
|  |             AlignTop, | ||||||
|  |             FontSecondary, | ||||||
|  |             string_get_cstr(modulation_str)); | ||||||
|  | 
 | ||||||
|         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); |         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text); | ||||||
|         widget_add_string_multiline_element( |         widget_add_string_multiline_element( | ||||||
|             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); |             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); | ||||||
|  | 
 | ||||||
|  |         string_clear(frequency_str); | ||||||
|  |         string_clear(modulation_str); | ||||||
|         string_clear(text); |         string_clear(text); | ||||||
| 
 | 
 | ||||||
|         if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && |         if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file && | ||||||
|            strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { |            strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { | ||||||
|             widget_add_button_element( |             widget_add_button_element( | ||||||
|                 subghz->widget, |                 subghz->widget, | ||||||
| @ -112,13 +119,13 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|                 if(!subghz_tx_start(subghz)) { |                 if(!subghz_tx_start(subghz)) { | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz->state_notifications = NOTIFICATION_TX_STATE; |                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) { |         } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) { | ||||||
|             //CC1101 Stop Tx -> Start RX
 |             //CC1101 Stop Tx -> Start RX
 | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
|             } |             } | ||||||
| @ -129,11 +136,11 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { |             if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { | ||||||
|                 subghz->txrx->hopper_state = SubGhzHopperStateRunnig; |                 subghz->txrx->hopper_state = SubGhzHopperStateRunnig; | ||||||
|             } |             } | ||||||
|             subghz->state_notifications = NOTIFICATION_RX_STATE; |             subghz->state_notifications = SubGhzNotificationStateRX; | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) { |         } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) { | ||||||
|             //CC1101 Stop RX -> Save
 |             //CC1101 Stop RX -> Save
 | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { |             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) { | ||||||
|                 subghz->txrx->hopper_state = SubGhzHopperStateOFF; |                 subghz->txrx->hopper_state = SubGhzHopperStateOFF; | ||||||
|             } |             } | ||||||
| @ -144,7 +151,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             if(!subghz_scene_receiver_info_update_parser(subghz)) { |             if(!subghz_scene_receiver_info_update_parser(subghz)) { | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_string && |             if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file && | ||||||
|                strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { |                strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) { | ||||||
|                 subghz_file_name_clear(subghz); |                 subghz_file_name_clear(subghz); | ||||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); |                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); | ||||||
| @ -156,10 +163,10 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | |||||||
|             subghz_hopper_update(subghz); |             subghz_hopper_update(subghz); | ||||||
|         } |         } | ||||||
|         switch(subghz->state_notifications) { |         switch(subghz->state_notifications) { | ||||||
|         case NOTIFICATION_TX_STATE: |         case SubGhzNotificationStateTX: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_red_10); |             notification_message(subghz->notifications, &sequence_blink_red_10); | ||||||
|             break; |             break; | ||||||
|         case NOTIFICATION_RX_STATE: |         case SubGhzNotificationStateRX: | ||||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); |             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ void subghz_scene_save_name_on_enter(void* context) { | |||||||
|         set_random_name(subghz->file_name, sizeof(subghz->file_name)); |         set_random_name(subghz->file_name, sizeof(subghz->file_name)); | ||||||
|         dev_name_empty = true; |         dev_name_empty = true; | ||||||
|     } else { |     } else { | ||||||
|         memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name)); |         memcpy(subghz->file_name_tmp, subghz->file_name, strlen(subghz->file_name) + 1); | ||||||
|         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAWMenu) == |         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAWMenu) == | ||||||
|            SubghzCustomEventManagerSet) { |            SubghzCustomEventManagerSet) { | ||||||
|             subghz_get_next_name_file(subghz); |             subghz_get_next_name_file(subghz); | ||||||
|  | |||||||
| @ -16,8 +16,8 @@ void subghz_scene_start_submenu_callback(void* context, uint32_t index) { | |||||||
| 
 | 
 | ||||||
| void subghz_scene_start_on_enter(void* context) { | void subghz_scene_start_on_enter(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) { |     if(subghz->state_notifications == SubGhzNotificationStateStarting) { | ||||||
|         subghz->state_notifications = NOTIFICATION_IDLE_STATE; |         subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|     } |     } | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); |         subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz); | ||||||
|  | |||||||
| @ -13,9 +13,12 @@ bool subghz_scene_transmitter_update_data_show(void* context) { | |||||||
| 
 | 
 | ||||||
|     if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { |     if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) { | ||||||
|         string_t key_str; |         string_t key_str; | ||||||
|  |         string_t frequency_str; | ||||||
|  |         string_t modulation_str; | ||||||
|  | 
 | ||||||
|         string_init(key_str); |         string_init(key_str); | ||||||
|         char frequency_str[10]; |         string_init(frequency_str); | ||||||
|         char preset_str[6]; |         string_init(modulation_str); | ||||||
|         uint8_t show_button = 0; |         uint8_t show_button = 0; | ||||||
|         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str); |         subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str); | ||||||
| 
 | 
 | ||||||
| @ -27,29 +30,17 @@ bool subghz_scene_transmitter_update_data_show(void* context) { | |||||||
|         } else { |         } else { | ||||||
|             show_button = 1; |             show_button = 1; | ||||||
|         } |         } | ||||||
|         snprintf( |  | ||||||
|             frequency_str, |  | ||||||
|             sizeof(frequency_str), |  | ||||||
|             "%03ld.%02ld", |  | ||||||
|             subghz->txrx->frequency / 1000000 % 1000, |  | ||||||
|             subghz->txrx->frequency / 10000 % 100); |  | ||||||
|         if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || |  | ||||||
|            subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { |  | ||||||
|             snprintf(preset_str, sizeof(preset_str), "AM"); |  | ||||||
|         } else if( |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || |  | ||||||
|             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { |  | ||||||
|             snprintf(preset_str, sizeof(preset_str), "FM"); |  | ||||||
|         } else { |  | ||||||
|             furi_crash(NULL); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|  |         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||||
|         subghz_transmitter_add_data_to_show( |         subghz_transmitter_add_data_to_show( | ||||||
|             subghz->subghz_transmitter, |             subghz->subghz_transmitter, | ||||||
|             string_get_cstr(key_str), |             string_get_cstr(key_str), | ||||||
|             frequency_str, |             string_get_cstr(frequency_str), | ||||||
|             preset_str, |             string_get_cstr(modulation_str), | ||||||
|             show_button); |             show_button); | ||||||
|  | 
 | ||||||
|  |         string_clear(frequency_str); | ||||||
|  |         string_clear(modulation_str); | ||||||
|         string_clear(key_str); |         string_clear(key_str); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
| @ -67,7 +58,7 @@ void subghz_scene_transmitter_on_enter(void* context) { | |||||||
|     subghz_transmitter_set_callback( |     subghz_transmitter_set_callback( | ||||||
|         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); |         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz); | ||||||
| 
 | 
 | ||||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; |     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -75,7 +66,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SubghzCustomEventViewTransmitterSendStart) { |         if(event.event == SubghzCustomEventViewTransmitterSendStart) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||||
|                 subghz_rx_end(subghz); |                 subghz_rx_end(subghz); | ||||||
|             } |             } | ||||||
| @ -84,20 +75,20 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
|                 if(!subghz_tx_start(subghz)) { |                 if(!subghz_tx_start(subghz)) { | ||||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); |                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz->state_notifications = NOTIFICATION_TX_STATE; |                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||||
|                     subghz_scene_transmitter_update_data_show(subghz); |                     subghz_scene_transmitter_update_data_show(subghz); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventViewTransmitterSendStop) { |         } else if(event.event == SubghzCustomEventViewTransmitterSendStop) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
|                 subghz_sleep(subghz); |                 subghz_sleep(subghz); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         } else if(event.event == SubghzCustomEventViewTransmitterBack) { |         } else if(event.event == SubghzCustomEventViewTransmitterBack) { | ||||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             scene_manager_search_and_switch_to_previous_scene( |             scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 subghz->scene_manager, SubGhzSceneStart); |                 subghz->scene_manager, SubGhzSceneStart); | ||||||
|             return true; |             return true; | ||||||
| @ -106,7 +97,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); |             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeTick) { |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|         if(subghz->state_notifications == NOTIFICATION_TX_STATE) { |         if(subghz->state_notifications == SubGhzNotificationStateTX) { | ||||||
|             notification_message(subghz->notifications, &sequence_blink_red_10); |             notification_message(subghz->notifications, &sequence_blink_red_10); | ||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
| @ -117,5 +108,5 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | |||||||
| void subghz_scene_transmitter_on_exit(void* context) { | void subghz_scene_transmitter_on_exit(void* context) { | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; |     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| #include "subghz_i.h" | #include "subghz_i.h" | ||||||
|  | #include <lib/toolbox/path.h> | ||||||
| 
 | 
 | ||||||
| const char* const subghz_frequencies_text[] = { | const char* const subghz_frequencies_text[] = { | ||||||
|     "300.00", |     "300.00", | ||||||
| @ -119,6 +120,9 @@ SubGhz* subghz_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); |         subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); | ||||||
| 
 | 
 | ||||||
|  |     //Dialog
 | ||||||
|  |     subghz->dialogs = furi_record_open("dialogs"); | ||||||
|  | 
 | ||||||
|     // Transmitter
 |     // Transmitter
 | ||||||
|     subghz->subghz_transmitter = subghz_transmitter_alloc(); |     subghz->subghz_transmitter = subghz_transmitter_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -224,6 +228,9 @@ void subghz_free(SubGhz* subghz) { | |||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); | ||||||
|     widget_free(subghz->widget); |     widget_free(subghz->widget); | ||||||
| 
 | 
 | ||||||
|  |     //Dialog
 | ||||||
|  |     furi_record_close("dialogs"); | ||||||
|  | 
 | ||||||
|     // Transmitter
 |     // Transmitter
 | ||||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); |     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||||
|     subghz_transmitter_free(subghz->subghz_transmitter); |     subghz_transmitter_free(subghz->subghz_transmitter); | ||||||
| @ -280,6 +287,14 @@ int32_t subghz_app(void* p) { | |||||||
| 
 | 
 | ||||||
|     // Check argument and run corresponding scene
 |     // Check argument and run corresponding scene
 | ||||||
|     if(p && subghz_key_load(subghz, p)) { |     if(p && subghz_key_load(subghz, p)) { | ||||||
|  |         string_t filename; | ||||||
|  |         string_init(filename); | ||||||
|  | 
 | ||||||
|  |         path_extract_filename_no_ext(p, filename); | ||||||
|  |         strlcpy( | ||||||
|  |             subghz->file_name, string_get_cstr(filename), strlen(string_get_cstr(filename)) + 1); | ||||||
|  |         string_clear(filename); | ||||||
|  | 
 | ||||||
|         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); |         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter); | ||||||
|     } else { |     } else { | ||||||
|         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); |         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); | ||||||
|  | |||||||
| @ -6,10 +6,74 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include "file-worker.h" | #include <lib/flipper_file/flipper_file.h> | ||||||
| #include "../notification/notification.h" | #include "../notification/notification.h" | ||||||
| #include "views/subghz_receiver.h" | #include "views/subghz_receiver.h" | ||||||
| 
 | 
 | ||||||
|  | bool subghz_set_pteset(SubGhz* subghz, const char* preset) { | ||||||
|  |     if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { | ||||||
|  |         subghz->txrx->preset = FuriHalSubGhzPresetOok270Async; | ||||||
|  |     } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { | ||||||
|  |         subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||||
|  |     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { | ||||||
|  |         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev238Async; | ||||||
|  |     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { | ||||||
|  |         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async; | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool subghz_get_preset_name(SubGhz* subghz, string_t preset) { | ||||||
|  |     const char* preset_name; | ||||||
|  |     switch(subghz->txrx->preset) { | ||||||
|  |     case FuriHalSubGhzPresetOok270Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPresetOok270Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPresetOok650Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPresetOok650Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPreset2FSKDev238Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPreset2FSKDev238Async"; | ||||||
|  |         break; | ||||||
|  |     case FuriHalSubGhzPreset2FSKDev476Async: | ||||||
|  |         preset_name = "FuriHalSubGhzPreset2FSKDev476Async"; | ||||||
|  |         break; | ||||||
|  |         FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset"); | ||||||
|  |     default: | ||||||
|  |         return false; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     string_set(preset, preset_name); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation) { | ||||||
|  |     furi_assert(subghz); | ||||||
|  |     if(frequency != NULL) { | ||||||
|  |         string_printf( | ||||||
|  |             frequency, | ||||||
|  |             "%03ld.%02ld", | ||||||
|  |             subghz->txrx->frequency / 1000000 % 1000, | ||||||
|  |             subghz->txrx->frequency / 10000 % 100); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(modulation != NULL) { | ||||||
|  |         if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async || | ||||||
|  |            subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) { | ||||||
|  |             string_set(modulation, "AM"); | ||||||
|  |         } else if( | ||||||
|  |             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async || | ||||||
|  |             subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) { | ||||||
|  |             string_set(modulation, "FM"); | ||||||
|  |         } else { | ||||||
|  |             furi_crash(NULL); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset) { | void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     furi_hal_subghz_reset(); |     furi_hal_subghz_reset(); | ||||||
| @ -79,17 +143,6 @@ void subghz_sleep(SubGhz* subghz) { | |||||||
|     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; |     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void subghz_frequency_preset_to_str(SubGhz* subghz, string_t output) { |  | ||||||
|     furi_assert(subghz); |  | ||||||
| 
 |  | ||||||
|     string_cat_printf( |  | ||||||
|         output, |  | ||||||
|         "Frequency: %d\n" |  | ||||||
|         "Preset: %d\n", |  | ||||||
|         (int)subghz->txrx->frequency, |  | ||||||
|         (int)subghz->txrx->preset); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool subghz_tx_start(SubGhz* subghz) { | bool subghz_tx_start(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
| @ -144,66 +197,78 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     furi_assert(file_path); |     furi_assert(file_path); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|     // Load device data
 |     // Load device data
 | ||||||
|     bool loaded = false; |     bool loaded = false; | ||||||
|     string_t path; |     string_t path; | ||||||
|     string_init_set_str(path, file_path); |     string_init_set_str(path, file_path); | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|     int res = 0; |     uint32_t version; | ||||||
|     int data = 0; |  | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|         if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { |         if(!flipper_file_open_existing(flipper_file, string_get_cstr(path))) { | ||||||
|  |             FURI_LOG_E( | ||||||
|  |                 SUBGHZ_PARSER_TAG, "Unable to open file for read: %s", string_get_cstr(path)); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_file_read_header(flipper_file, temp_str, &version)) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing or incorrect header"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Read and parse frequency from 1st line
 |         if(((!strcmp(string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |             (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) && | ||||||
|  |            version == SUBGHZ_KEY_FILE_VERSION) { | ||||||
|  |         } else { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Type or version mismatch"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data); |  | ||||||
|         if(res != 1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         subghz->txrx->frequency = (uint32_t)data; |  | ||||||
| 
 | 
 | ||||||
|         // Read and parse preset from 2st line
 |         if(!flipper_file_read_uint32( | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |                flipper_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Frequency"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data); |  | ||||||
|         if(res != 1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         subghz->txrx->preset = (FuriHalSubGhzPreset)data; |  | ||||||
| 
 | 
 | ||||||
|         // Read and parse name protocol from 2st line
 |         if(!flipper_file_read_string(flipper_file, "Preset", temp_str)) { | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Preset"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // strlen("Protocol: ") = 10
 |         if(!subghz_set_pteset(subghz, string_get_cstr(temp_str))) { | ||||||
|         string_right(temp_str, 10); |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!flipper_file_read_string(flipper_file, "Protocol", temp_str)) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Protocol"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         subghz->txrx->protocol_result = |         subghz->txrx->protocol_result = | ||||||
|             subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str)); |             subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str)); | ||||||
|         if(subghz->txrx->protocol_result == NULL) { |         if(subghz->txrx->protocol_result == NULL) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "This type of protocol was not found"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( |         if(!subghz->txrx->protocol_result->to_load_protocol_from_file( | ||||||
|                file_worker, subghz->txrx->protocol_result, string_get_cstr(path))) { |                flipper_file, subghz->txrx->protocol_result, string_get_cstr(path))) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         loaded = true; |         loaded = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     if(!loaded) { |     if(!loaded) { | ||||||
|         file_worker_show_error(file_worker, "Cannot parse\nfile"); |         dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile"); | ||||||
|     } |     } | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(path); |     string_clear(path); | ||||||
|     file_worker_close(file_worker); | 
 | ||||||
|     file_worker_free(file_worker); |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
| 
 | 
 | ||||||
|     return loaded; |     return loaded; | ||||||
| } | } | ||||||
| @ -211,23 +276,22 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | |||||||
| bool subghz_get_next_name_file(SubGhz* subghz) { | bool subghz_get_next_name_file(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     Storage* storage = furi_record_open("storage"); | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
|     string_init(temp_str); |     string_init(temp_str); | ||||||
|     bool res = false; |     bool res = false; | ||||||
| 
 | 
 | ||||||
|     if(strcmp(subghz->file_name, "")) { |     if(strcmp(subghz->file_name, "")) { | ||||||
|         //get the name of the next free file
 |         //get the name of the next free file
 | ||||||
|         file_worker_get_next_filename( |         storage_get_next_filename( | ||||||
|             file_worker, SUBGHZ_RAW_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str); |             storage, SUBGHZ_RAW_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str); | ||||||
| 
 | 
 | ||||||
|         memcpy(subghz->file_name, string_get_cstr(temp_str), strlen(string_get_cstr(temp_str))); |         memcpy(subghz->file_name, string_get_cstr(temp_str), strlen(string_get_cstr(temp_str))); | ||||||
|         res = true; |         res = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     file_worker_close(file_worker); |     furi_record_close("storage"); | ||||||
|     file_worker_free(file_worker); |  | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| @ -236,7 +300,8 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | |||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     furi_assert(subghz->txrx->protocol_result); |     furi_assert(subghz->txrx->protocol_result); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|     string_t dev_file_name; |     string_t dev_file_name; | ||||||
|     string_init(dev_file_name); |     string_init(dev_file_name); | ||||||
|     string_t temp_str; |     string_t temp_str; | ||||||
| @ -244,43 +309,71 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | |||||||
|     bool saved = false; |     bool saved = false; | ||||||
| 
 | 
 | ||||||
|     do { |     do { | ||||||
|  |         // Checking that this type of people can be saved
 | ||||||
|  |         if(subghz->txrx->protocol_result->to_save_file == NULL) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "No saving of this type of keys"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|         // Create subghz folder directory if necessary
 |         // Create subghz folder directory if necessary
 | ||||||
|         if(!file_worker_mkdir(file_worker, SUBGHZ_APP_FOLDER)) { |         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) { | ||||||
|  |             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // Create saved directory if necessary
 |         // Create saved directory if necessary
 | ||||||
|         if(!file_worker_mkdir(file_worker, SUBGHZ_APP_PATH_FOLDER)) { |         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) { | ||||||
|  |             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         // First remove subghz device file if it was saved
 |         // First remove subghz device file if it was saved
 | ||||||
|         string_printf( |         string_printf( | ||||||
|             dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); |             dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); | ||||||
|         if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { | 
 | ||||||
|  |         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         // Open file
 |         // Open file
 | ||||||
|         if(!file_worker_open( |         if(!flipper_file_open_always(flipper_file, string_get_cstr(dev_file_name))) { | ||||||
|                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to open file for write: %s", dev_file_name); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         //Get string frequency preset protocol
 | 
 | ||||||
|         subghz_frequency_preset_to_str(subghz, temp_str); |         if(!flipper_file_write_header_cstr( | ||||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { |                flipper_file, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add header"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         //Get string save
 | 
 | ||||||
|         subghz->txrx->protocol_result->to_save_string(subghz->txrx->protocol_result, temp_str); |         if(!flipper_file_write_uint32( | ||||||
|         // Prepare and write data to file
 |                flipper_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { | ||||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Frequency"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if(!subghz_get_preset_name(subghz, temp_str)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if(!flipper_file_write_string_cstr(flipper_file, "Preset", string_get_cstr(temp_str))) { | ||||||
|  |             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Preset"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(!subghz->txrx->protocol_result->to_save_file( | ||||||
|  |                subghz->txrx->protocol_result, flipper_file)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         saved = true; |         saved = true; | ||||||
|     } while(0); |     } while(0); | ||||||
| 
 | 
 | ||||||
|     string_clear(temp_str); |     string_clear(temp_str); | ||||||
|     string_clear(dev_file_name); |     string_clear(dev_file_name); | ||||||
|     file_worker_close(file_worker); | 
 | ||||||
|     file_worker_free(file_worker); |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
| 
 | 
 | ||||||
|     return saved; |     return saved; | ||||||
| } | } | ||||||
| @ -288,17 +381,12 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | |||||||
| bool subghz_load_protocol_from_file(SubGhz* subghz) { | bool subghz_load_protocol_from_file(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     string_t file_name; | ||||||
|     string_t protocol_file_name; |     string_init(file_name); | ||||||
|     string_init(protocol_file_name); |  | ||||||
|     string_t temp_str; |  | ||||||
|     string_init(temp_str); |  | ||||||
|     int sscanf_res = 0; |  | ||||||
|     int data = 0; |  | ||||||
| 
 | 
 | ||||||
|     // Input events and views are managed by file_select
 |     // Input events and views are managed by file_select
 | ||||||
|     bool res = file_worker_file_select( |     bool res = dialog_file_select_show( | ||||||
|         file_worker, |         subghz->dialogs, | ||||||
|         SUBGHZ_APP_PATH_FOLDER, |         SUBGHZ_APP_PATH_FOLDER, | ||||||
|         SUBGHZ_APP_EXTENSION, |         SUBGHZ_APP_EXTENSION, | ||||||
|         subghz->file_name, |         subghz->file_name, | ||||||
| @ -306,87 +394,24 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
|         NULL); |         NULL); | ||||||
| 
 | 
 | ||||||
|     if(res) { |     if(res) { | ||||||
|         // Get key file path
 |  | ||||||
|         string_printf( |         string_printf( | ||||||
|             protocol_file_name, |             file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); | ||||||
|             "%s/%s%s", |  | ||||||
|             SUBGHZ_APP_PATH_FOLDER, |  | ||||||
|             subghz->file_name, |  | ||||||
|             SUBGHZ_APP_EXTENSION); |  | ||||||
|     } else { |  | ||||||
|         string_clear(temp_str); |  | ||||||
|         string_clear(protocol_file_name); |  | ||||||
| 
 | 
 | ||||||
|         file_worker_close(file_worker); |         res = subghz_key_load(subghz, string_get_cstr(file_name)); | ||||||
|         file_worker_free(file_worker); |  | ||||||
|         return res; |  | ||||||
|     } |  | ||||||
|     res = false; |  | ||||||
|     do { |  | ||||||
|         if(!file_worker_open( |  | ||||||
|                file_worker, string_get_cstr(protocol_file_name), FSAM_READ, FSOM_OPEN_EXISTING)) { |  | ||||||
|             return res; |  | ||||||
|         } |  | ||||||
|         // Read and parse frequency from 1st line
 |  | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         sscanf_res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data); |  | ||||||
|         if(sscanf_res != 1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         subghz->txrx->frequency = (uint32_t)data; |  | ||||||
| 
 |  | ||||||
|         // Read and parse preset from 2st line
 |  | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         sscanf_res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data); |  | ||||||
|         if(sscanf_res != 1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         subghz->txrx->preset = (FuriHalSubGhzPreset)data; |  | ||||||
| 
 |  | ||||||
|         // Read and parse name protocol from 3st line
 |  | ||||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         // strlen("Protocol: ") = 10
 |  | ||||||
|         string_right(temp_str, 10); |  | ||||||
|         subghz->txrx->protocol_result = |  | ||||||
|             subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str)); |  | ||||||
|         if(subghz->txrx->protocol_result == NULL) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(subghz->txrx->protocol_result->to_load_protocol_from_file == NULL || |  | ||||||
|            !subghz->txrx->protocol_result->to_load_protocol_from_file( |  | ||||||
|                file_worker, subghz->txrx->protocol_result, string_get_cstr(protocol_file_name))) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         res = true; |  | ||||||
|     } while(0); |  | ||||||
| 
 |  | ||||||
|     if(!res) { |  | ||||||
|         file_worker_show_error(file_worker, "Cannot parse\nfile"); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(temp_str); |     string_clear(file_name); | ||||||
|     string_clear(protocol_file_name); |  | ||||||
| 
 |  | ||||||
|     file_worker_close(file_worker); |  | ||||||
|     file_worker_free(file_worker); |  | ||||||
| 
 | 
 | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_rename_file(SubGhz* subghz) { | bool subghz_rename_file(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     bool ret = false; |     bool ret = true; | ||||||
|     string_t old_path; |     string_t old_path; | ||||||
|     string_t new_path; |     string_t new_path; | ||||||
| 
 | 
 | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |     Storage* storage = furi_record_open("storage"); | ||||||
| 
 | 
 | ||||||
|     string_init_printf( |     string_init_printf( | ||||||
|         old_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); |         old_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); | ||||||
| @ -394,39 +419,33 @@ bool subghz_rename_file(SubGhz* subghz) { | |||||||
|     string_init_printf( |     string_init_printf( | ||||||
|         new_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); |         new_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); | ||||||
| 
 | 
 | ||||||
|     ret = file_worker_rename(file_worker, string_get_cstr(old_path), string_get_cstr(new_path)); |     FS_Error fs_result = | ||||||
|  |         storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); | ||||||
|  | 
 | ||||||
|  |     if(fs_result != FSE_OK && fs_result != FSE_EXIST) { | ||||||
|  |         dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory"); | ||||||
|  |         ret = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     string_clear(old_path); |     string_clear(old_path); | ||||||
|     string_clear(new_path); |     string_clear(new_path); | ||||||
|     file_worker_close(file_worker); |     furi_record_close("storage"); | ||||||
|     file_worker_free(file_worker); | 
 | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool subghz_delete_file(SubGhz* subghz) { | bool subghz_delete_file(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
| 
 | 
 | ||||||
|     bool result = true; |     Storage* storage = furi_record_open("storage"); | ||||||
|     FileWorker* file_worker = file_worker_alloc(false); |  | ||||||
|     string_t file_path; |     string_t file_path; | ||||||
|  |     string_init_printf( | ||||||
|  |         file_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); | ||||||
|  |     bool result = storage_simply_remove(storage, string_get_cstr(file_path)); | ||||||
|  |     furi_record_close("storage"); | ||||||
| 
 | 
 | ||||||
|     do { |     subghz_file_name_clear(subghz); | ||||||
|         // Get key file path
 |  | ||||||
|         string_init_printf( |  | ||||||
|             file_path, |  | ||||||
|             "%s/%s%s", |  | ||||||
|             SUBGHZ_APP_PATH_FOLDER, |  | ||||||
|             subghz->file_name_tmp, |  | ||||||
|             SUBGHZ_APP_EXTENSION); |  | ||||||
|         // Delete original file
 |  | ||||||
|         if(!file_worker_remove(file_worker, string_get_cstr(file_path))) { |  | ||||||
|             result = false; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } while(0); |  | ||||||
| 
 | 
 | ||||||
|     string_clear(file_path); |  | ||||||
|     file_worker_close(file_worker); |  | ||||||
|     file_worker_free(file_worker); |  | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
|  | #include <dialogs/dialogs.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| @ -33,11 +34,6 @@ | |||||||
| 
 | 
 | ||||||
| #define SUBGHZ_TEXT_STORE_SIZE 40 | #define SUBGHZ_TEXT_STORE_SIZE 40 | ||||||
| 
 | 
 | ||||||
| #define NOTIFICATION_STARTING_STATE 0u |  | ||||||
| #define NOTIFICATION_IDLE_STATE 1u |  | ||||||
| #define NOTIFICATION_TX_STATE 2u |  | ||||||
| #define NOTIFICATION_RX_STATE 3u |  | ||||||
| 
 |  | ||||||
| extern const char* const subghz_frequencies_text[]; | extern const char* const subghz_frequencies_text[]; | ||||||
| extern const uint32_t subghz_frequencies[]; | extern const uint32_t subghz_frequencies[]; | ||||||
| extern const uint32_t subghz_hopper_frequencies[]; | extern const uint32_t subghz_hopper_frequencies[]; | ||||||
| @ -45,6 +41,14 @@ extern const uint32_t subghz_frequencies_count; | |||||||
| extern const uint32_t subghz_hopper_frequencies_count; | extern const uint32_t subghz_hopper_frequencies_count; | ||||||
| extern const uint32_t subghz_frequencies_433_92; | extern const uint32_t subghz_frequencies_433_92; | ||||||
| 
 | 
 | ||||||
|  | /** SubGhzNotification state */ | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzNotificationStateStarting, | ||||||
|  |     SubGhzNotificationStateIDLE, | ||||||
|  |     SubGhzNotificationStateTX, | ||||||
|  |     SubGhzNotificationStateRX, | ||||||
|  | } SubGhzNotificationState; | ||||||
|  | 
 | ||||||
| /** SubGhzTxRx state */ | /** SubGhzTxRx state */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubGhzTxRxStateIDLE, |     SubGhzTxRxStateIDLE, | ||||||
| @ -101,9 +105,10 @@ struct SubGhz { | |||||||
|     Popup* popup; |     Popup* popup; | ||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
|  |     DialogsApp* dialogs; | ||||||
|     char file_name[SUBGHZ_TEXT_STORE_SIZE + 1]; |     char file_name[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||||
|     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; |     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||||
|     uint8_t state_notifications; |     SubGhzNotificationState state_notifications; | ||||||
| 
 | 
 | ||||||
|     SubghzReceiver* subghz_receiver; |     SubghzReceiver* subghz_receiver; | ||||||
|     SubghzTransmitter* subghz_transmitter; |     SubghzTransmitter* subghz_transmitter; | ||||||
| @ -133,6 +138,9 @@ typedef enum { | |||||||
|     SubGhzViewTestPacket, |     SubGhzViewTestPacket, | ||||||
| } SubGhzView; | } SubGhzView; | ||||||
| 
 | 
 | ||||||
|  | bool subghz_set_pteset(SubGhz* subghz, const char* preset); | ||||||
|  | bool subghz_get_preset_name(SubGhz* subghz, string_t preset); | ||||||
|  | void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation); | ||||||
| void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset); | void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset); | ||||||
| uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | ||||||
| void subghz_rx_end(SubGhz* subghz); | void subghz_rx_end(SubGhz* subghz); | ||||||
|  | |||||||
| @ -8,6 +8,8 @@ | |||||||
| #include <notification/notification-messages.h> | #include <notification/notification-messages.h> | ||||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "SubGhzTestStatic" | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubghzTestStaticStatusIDLE, |     SubghzTestStaticStatusIDLE, | ||||||
|     SubghzTestStaticStatusTX, |     SubghzTestStaticStatusTX, | ||||||
| @ -99,7 +101,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { | |||||||
|                     } else { |                     } else { | ||||||
|                         notification_message_block(notification, &sequence_set_red_255); |                         notification_message_block(notification, &sequence_set_red_255); | ||||||
| 
 | 
 | ||||||
|                         FURI_LOG_I("SubghzTestStatic", "TX Start"); |                         FURI_LOG_I(TAG, "TX Start"); | ||||||
| 
 | 
 | ||||||
|                         subghz_encoder_princeton_set( |                         subghz_encoder_princeton_set( | ||||||
|                             instance->encoder, subghz_test_static_keys[model->button], 10000); |                             instance->encoder, subghz_test_static_keys[model->button], 10000); | ||||||
| @ -110,7 +112,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { | |||||||
|                     } |                     } | ||||||
|                 } else if(event->type == InputTypeRelease) { |                 } else if(event->type == InputTypeRelease) { | ||||||
|                     if(instance->satus_tx == SubghzTestStaticStatusTX) { |                     if(instance->satus_tx == SubghzTestStaticStatusTX) { | ||||||
|                         FURI_LOG_I("SubghzTestStatic", "TX Stop"); |                         FURI_LOG_I(TAG, "TX Stop"); | ||||||
|                         subghz_encoder_princeton_print_log(instance->encoder); |                         subghz_encoder_princeton_print_log(instance->encoder); | ||||||
|                         furi_hal_subghz_stop_async_tx(); |                         furi_hal_subghz_stop_async_tx(); | ||||||
|                         notification_message(notification, &sequence_reset_red); |                         notification_message(notification, &sequence_reset_red); | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ static RpcSession* session = NULL; | |||||||
| static StreamBufferHandle_t output_stream = NULL; | static StreamBufferHandle_t output_stream = NULL; | ||||||
| static uint32_t command_id = 0; | static uint32_t command_id = 0; | ||||||
| 
 | 
 | ||||||
| #define TEST_RPC_TAG "TEST_RPC" | #define TAG "UnitTestsRpc" | ||||||
| #define MAX_RECEIVE_OUTPUT_TIMEOUT 3000 | #define MAX_RECEIVE_OUTPUT_TIMEOUT 3000 | ||||||
| #define MAX_NAME_LENGTH 255 | #define MAX_NAME_LENGTH 255 | ||||||
| #define MAX_DATA_SIZE 512 // have to be exact as in rpc_storage.c
 | #define MAX_DATA_SIZE 512 // have to be exact as in rpc_storage.c
 | ||||||
| @ -1334,7 +1334,7 @@ int run_minunit_test_rpc() { | |||||||
|     Storage* storage = furi_record_open("storage"); |     Storage* storage = furi_record_open("storage"); | ||||||
|     furi_record_close("storage"); |     furi_record_close("storage"); | ||||||
|     if(storage_sd_status(storage) != FSE_OK) { |     if(storage_sd_status(storage) != FSE_OK) { | ||||||
|         FURI_LOG_E("UNIT_TESTS", "SD card not mounted - skip storage tests"); |         FURI_LOG_E(TAG, "SD card not mounted - skip storage tests"); | ||||||
|     } else { |     } else { | ||||||
|         MU_RUN_SUITE(test_rpc_storage); |         MU_RUN_SUITE(test_rpc_storage); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
| #include <cli/cli.h> | #include <cli/cli.h> | ||||||
| #include <loader/loader.h> | #include <loader/loader.h> | ||||||
| 
 | 
 | ||||||
| #define TESTS_TAG "UNIT_TESTS" | #define TAG "UnitTests" | ||||||
| 
 | 
 | ||||||
| int run_minunit(); | int run_minunit(); | ||||||
| int run_minunit_test_irda_decoder_encoder(); | int run_minunit_test_irda_decoder_encoder(); | ||||||
| @ -42,7 +42,7 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { | |||||||
| 
 | 
 | ||||||
|     // TODO: lock device while test running
 |     // TODO: lock device while test running
 | ||||||
|     if(loader_is_locked(loader)) { |     if(loader_is_locked(loader)) { | ||||||
|         FURI_LOG_E(TESTS_TAG, "RPC: stop all applications to run tests"); |         FURI_LOG_E(TAG, "RPC: stop all applications to run tests"); | ||||||
|         notification_message(notification, &sequence_blink_magenta_100); |         notification_message(notification, &sequence_blink_magenta_100); | ||||||
|     } else { |     } else { | ||||||
|         notification_message_block(notification, &sequence_set_only_blue_255); |         notification_message_block(notification, &sequence_set_only_blue_255); | ||||||
| @ -56,21 +56,21 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) { | |||||||
|         test_result |= run_minunit_test_flipper_file(); |         test_result |= run_minunit_test_flipper_file(); | ||||||
|         cycle_counter = (DWT->CYCCNT - cycle_counter); |         cycle_counter = (DWT->CYCCNT - cycle_counter); | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_I(TESTS_TAG, "Consumed: %0.2fs", (float)cycle_counter / (SystemCoreClock)); |         FURI_LOG_I(TAG, "Consumed: %0.2fs", (float)cycle_counter / (SystemCoreClock)); | ||||||
| 
 | 
 | ||||||
|         if(test_result == 0) { |         if(test_result == 0) { | ||||||
|             delay(200); /* wait for tested services and apps to deallocate */ |             delay(200); /* wait for tested services and apps to deallocate */ | ||||||
|             uint32_t heap_after = memmgr_get_free_heap(); |             uint32_t heap_after = memmgr_get_free_heap(); | ||||||
|             notification_message(notification, &sequence_success); |             notification_message(notification, &sequence_success); | ||||||
|             if(heap_after != heap_before) { |             if(heap_after != heap_before) { | ||||||
|                 FURI_LOG_E(TESTS_TAG, "Leaked: %d", heap_before - heap_after); |                 FURI_LOG_E(TAG, "Leaked: %d", heap_before - heap_after); | ||||||
|             } else { |             } else { | ||||||
|                 FURI_LOG_I(TESTS_TAG, "No leaks"); |                 FURI_LOG_I(TAG, "No leaks"); | ||||||
|             } |             } | ||||||
|             FURI_LOG_I(TESTS_TAG, "PASSED"); |             FURI_LOG_I(TAG, "PASSED"); | ||||||
|         } else { |         } else { | ||||||
|             notification_message(notification, &sequence_error); |             notification_message(notification, &sequence_error); | ||||||
|             FURI_LOG_E(TESTS_TAG, "FAILED"); |             FURI_LOG_E(TAG, "FAILED"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,7 +36,10 @@ typedef enum _PB_CommandStatus { | |||||||
|     PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY = 18, /* *< Directory, you're going to remove is not empty */ |     PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY = 18, /* *< Directory, you're going to remove is not empty */ | ||||||
|     /* *< Application Errors */ |     /* *< Application Errors */ | ||||||
|     PB_CommandStatus_ERROR_APP_CANT_START = 16, /* *< Can't start app - internal error */ |     PB_CommandStatus_ERROR_APP_CANT_START = 16, /* *< Can't start app - internal error */ | ||||||
|     PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED = 17 /* *< Another app is running */ |     PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED = 17, /* *< Another app is running */ | ||||||
|  |     /* *< Virtual Display Errors */ | ||||||
|  |     PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED = 19, /* *< Virtual Display session can't be started twice */ | ||||||
|  |     PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED = 20 /* *< Virtual Display session can't be stopped when it's not started */ | ||||||
| } PB_CommandStatus; | } PB_CommandStatus; | ||||||
| 
 | 
 | ||||||
| /* Struct definitions */ | /* Struct definitions */ | ||||||
| @ -76,18 +79,20 @@ typedef struct _PB_Main { | |||||||
|         PB_StopSession stop_session; |         PB_StopSession stop_session; | ||||||
|         PB_Gui_StartScreenStreamRequest gui_start_screen_stream_request; |         PB_Gui_StartScreenStreamRequest gui_start_screen_stream_request; | ||||||
|         PB_Gui_StopScreenStreamRequest gui_stop_screen_stream_request; |         PB_Gui_StopScreenStreamRequest gui_stop_screen_stream_request; | ||||||
|         PB_Gui_ScreenStreamFrame gui_screen_stream_frame; |         PB_Gui_ScreenFrame gui_screen_frame; | ||||||
|         PB_Gui_SendInputEventRequest gui_send_input_event_request; |         PB_Gui_SendInputEventRequest gui_send_input_event_request; | ||||||
|         PB_Storage_StatRequest storage_stat_request; |         PB_Storage_StatRequest storage_stat_request; | ||||||
|         PB_Storage_StatResponse storage_stat_response; |         PB_Storage_StatResponse storage_stat_response; | ||||||
|  |         PB_Gui_StartVirtualDisplayRequest gui_start_virtual_display_request; | ||||||
|  |         PB_Gui_StopVirtualDisplayRequest gui_stop_virtual_display_request; | ||||||
|     } content;  |     } content;  | ||||||
| } PB_Main; | } PB_Main; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Helper constants for enums */ | /* Helper constants for enums */ | ||||||
| #define _PB_CommandStatus_MIN PB_CommandStatus_OK | #define _PB_CommandStatus_MIN PB_CommandStatus_OK | ||||||
| #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY | #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED | ||||||
| #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY+1)) | #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED+1)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| @ -124,10 +129,12 @@ extern "C" { | |||||||
| #define PB_Main_stop_session_tag                 19 | #define PB_Main_stop_session_tag                 19 | ||||||
| #define PB_Main_gui_start_screen_stream_request_tag 20 | #define PB_Main_gui_start_screen_stream_request_tag 20 | ||||||
| #define PB_Main_gui_stop_screen_stream_request_tag 21 | #define PB_Main_gui_stop_screen_stream_request_tag 21 | ||||||
| #define PB_Main_gui_screen_stream_frame_tag      22 | #define PB_Main_gui_screen_frame_tag             22 | ||||||
| #define PB_Main_gui_send_input_event_request_tag 23 | #define PB_Main_gui_send_input_event_request_tag 23 | ||||||
| #define PB_Main_storage_stat_request_tag         24 | #define PB_Main_storage_stat_request_tag         24 | ||||||
| #define PB_Main_storage_stat_response_tag        25 | #define PB_Main_storage_stat_response_tag        25 | ||||||
|  | #define PB_Main_gui_start_virtual_display_request_tag 26 | ||||||
|  | #define PB_Main_gui_stop_virtual_display_request_tag 27 | ||||||
| 
 | 
 | ||||||
| /* Struct field encoding specification for nanopb */ | /* Struct field encoding specification for nanopb */ | ||||||
| #define PB_Empty_FIELDLIST(X, a) \ | #define PB_Empty_FIELDLIST(X, a) \ | ||||||
| @ -162,10 +169,12 @@ X(a, STATIC,   ONEOF,    MSG_W_CB, (content,app_lock_status_response,content.app | |||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,stop_session,content.stop_session),  19) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,stop_session,content.stop_session),  19) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_start_screen_stream_request,content.gui_start_screen_stream_request),  20) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_start_screen_stream_request,content.gui_start_screen_stream_request),  20) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_stop_screen_stream_request,content.gui_stop_screen_stream_request),  21) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_stop_screen_stream_request,content.gui_stop_screen_stream_request),  21) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_screen_stream_frame,content.gui_screen_stream_frame),  22) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_screen_frame,content.gui_screen_frame),  22) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_send_input_event_request,content.gui_send_input_event_request),  23) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_send_input_event_request,content.gui_send_input_event_request),  23) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_stat_request,content.storage_stat_request),  24) \ | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_stat_request,content.storage_stat_request),  24) \ | ||||||
| X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_stat_response,content.storage_stat_response),  25) | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_stat_response,content.storage_stat_response),  25) \ | ||||||
|  | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_start_virtual_display_request,content.gui_start_virtual_display_request),  26) \ | ||||||
|  | X(a, STATIC,   ONEOF,    MSG_W_CB, (content,gui_stop_virtual_display_request,content.gui_stop_virtual_display_request),  27) | ||||||
| #define PB_Main_CALLBACK NULL | #define PB_Main_CALLBACK NULL | ||||||
| #define PB_Main_DEFAULT NULL | #define PB_Main_DEFAULT NULL | ||||||
| #define PB_Main_content_empty_MSGTYPE PB_Empty | #define PB_Main_content_empty_MSGTYPE PB_Empty | ||||||
| @ -186,10 +195,12 @@ X(a, STATIC,   ONEOF,    MSG_W_CB, (content,storage_stat_response,content.storag | |||||||
| #define PB_Main_content_stop_session_MSGTYPE PB_StopSession | #define PB_Main_content_stop_session_MSGTYPE PB_StopSession | ||||||
| #define PB_Main_content_gui_start_screen_stream_request_MSGTYPE PB_Gui_StartScreenStreamRequest | #define PB_Main_content_gui_start_screen_stream_request_MSGTYPE PB_Gui_StartScreenStreamRequest | ||||||
| #define PB_Main_content_gui_stop_screen_stream_request_MSGTYPE PB_Gui_StopScreenStreamRequest | #define PB_Main_content_gui_stop_screen_stream_request_MSGTYPE PB_Gui_StopScreenStreamRequest | ||||||
| #define PB_Main_content_gui_screen_stream_frame_MSGTYPE PB_Gui_ScreenStreamFrame | #define PB_Main_content_gui_screen_frame_MSGTYPE PB_Gui_ScreenFrame | ||||||
| #define PB_Main_content_gui_send_input_event_request_MSGTYPE PB_Gui_SendInputEventRequest | #define PB_Main_content_gui_send_input_event_request_MSGTYPE PB_Gui_SendInputEventRequest | ||||||
| #define PB_Main_content_storage_stat_request_MSGTYPE PB_Storage_StatRequest | #define PB_Main_content_storage_stat_request_MSGTYPE PB_Storage_StatRequest | ||||||
| #define PB_Main_content_storage_stat_response_MSGTYPE PB_Storage_StatResponse | #define PB_Main_content_storage_stat_response_MSGTYPE PB_Storage_StatResponse | ||||||
|  | #define PB_Main_content_gui_start_virtual_display_request_MSGTYPE PB_Gui_StartVirtualDisplayRequest | ||||||
|  | #define PB_Main_content_gui_stop_virtual_display_request_MSGTYPE PB_Gui_StopVirtualDisplayRequest | ||||||
| 
 | 
 | ||||||
| extern const pb_msgdesc_t PB_Empty_msg; | extern const pb_msgdesc_t PB_Empty_msg; | ||||||
| extern const pb_msgdesc_t PB_StopSession_msg; | extern const pb_msgdesc_t PB_StopSession_msg; | ||||||
| @ -203,9 +214,9 @@ extern const pb_msgdesc_t PB_Main_msg; | |||||||
| /* Maximum encoded size of messages (where known) */ | /* Maximum encoded size of messages (where known) */ | ||||||
| #define PB_Empty_size                            0 | #define PB_Empty_size                            0 | ||||||
| #define PB_StopSession_size                      0 | #define PB_StopSession_size                      0 | ||||||
| #if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenStreamFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) | #if defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) | ||||||
| #define PB_Main_size                             (10 + sizeof(union PB_Main_content_size_union)) | #define PB_Main_size                             (10 + sizeof(union PB_Main_content_size_union)) | ||||||
| union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenStreamFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f0[36];}; | union PB_Main_content_size_union {char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f0[36];}; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -6,18 +6,24 @@ | |||||||
| #error Regenerate this file with the current version of nanopb generator. | #error Regenerate this file with the current version of nanopb generator. | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | PB_BIND(PB_Gui_ScreenFrame, PB_Gui_ScreenFrame, AUTO) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| PB_BIND(PB_Gui_StartScreenStreamRequest, PB_Gui_StartScreenStreamRequest, AUTO) | PB_BIND(PB_Gui_StartScreenStreamRequest, PB_Gui_StartScreenStreamRequest, AUTO) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| PB_BIND(PB_Gui_StopScreenStreamRequest, PB_Gui_StopScreenStreamRequest, AUTO) | PB_BIND(PB_Gui_StopScreenStreamRequest, PB_Gui_StopScreenStreamRequest, AUTO) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| PB_BIND(PB_Gui_ScreenStreamFrame, PB_Gui_ScreenStreamFrame, AUTO) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| PB_BIND(PB_Gui_SendInputEventRequest, PB_Gui_SendInputEventRequest, AUTO) | PB_BIND(PB_Gui_SendInputEventRequest, PB_Gui_SendInputEventRequest, AUTO) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | PB_BIND(PB_Gui_StartVirtualDisplayRequest, PB_Gui_StartVirtualDisplayRequest, AUTO) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | PB_BIND(PB_Gui_StopVirtualDisplayRequest, PB_Gui_StopVirtualDisplayRequest, AUTO) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,18 +28,26 @@ typedef enum _PB_Gui_InputType { | |||||||
| } PB_Gui_InputType; | } PB_Gui_InputType; | ||||||
| 
 | 
 | ||||||
| /* Struct definitions */ | /* Struct definitions */ | ||||||
| typedef struct _PB_Gui_ScreenStreamFrame {  | typedef struct _PB_Gui_ScreenFrame {  | ||||||
|     pb_bytes_array_t *data;  |     pb_bytes_array_t *data;  | ||||||
| } PB_Gui_ScreenStreamFrame; | } PB_Gui_ScreenFrame; | ||||||
| 
 | 
 | ||||||
| typedef struct _PB_Gui_StartScreenStreamRequest {  | typedef struct _PB_Gui_StartScreenStreamRequest {  | ||||||
|     char dummy_field; |     char dummy_field; | ||||||
| } PB_Gui_StartScreenStreamRequest; | } PB_Gui_StartScreenStreamRequest; | ||||||
| 
 | 
 | ||||||
|  | typedef struct _PB_Gui_StartVirtualDisplayRequest {  | ||||||
|  |     char dummy_field; | ||||||
|  | } PB_Gui_StartVirtualDisplayRequest; | ||||||
|  | 
 | ||||||
| typedef struct _PB_Gui_StopScreenStreamRequest {  | typedef struct _PB_Gui_StopScreenStreamRequest {  | ||||||
|     char dummy_field; |     char dummy_field; | ||||||
| } PB_Gui_StopScreenStreamRequest; | } PB_Gui_StopScreenStreamRequest; | ||||||
| 
 | 
 | ||||||
|  | typedef struct _PB_Gui_StopVirtualDisplayRequest {  | ||||||
|  |     char dummy_field; | ||||||
|  | } PB_Gui_StopVirtualDisplayRequest; | ||||||
|  | 
 | ||||||
| typedef struct _PB_Gui_SendInputEventRequest {  | typedef struct _PB_Gui_SendInputEventRequest {  | ||||||
|     PB_Gui_InputKey key;  |     PB_Gui_InputKey key;  | ||||||
|     PB_Gui_InputType type;  |     PB_Gui_InputType type;  | ||||||
| @ -61,21 +69,30 @@ extern "C" { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Initializer values for message structs */ | /* Initializer values for message structs */ | ||||||
|  | #define PB_Gui_ScreenFrame_init_default          {NULL} | ||||||
| #define PB_Gui_StartScreenStreamRequest_init_default {0} | #define PB_Gui_StartScreenStreamRequest_init_default {0} | ||||||
| #define PB_Gui_StopScreenStreamRequest_init_default {0} | #define PB_Gui_StopScreenStreamRequest_init_default {0} | ||||||
| #define PB_Gui_ScreenStreamFrame_init_default    {NULL} |  | ||||||
| #define PB_Gui_SendInputEventRequest_init_default {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} | #define PB_Gui_SendInputEventRequest_init_default {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_init_default {0} | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_init_default {0} | ||||||
|  | #define PB_Gui_ScreenFrame_init_zero             {NULL} | ||||||
| #define PB_Gui_StartScreenStreamRequest_init_zero {0} | #define PB_Gui_StartScreenStreamRequest_init_zero {0} | ||||||
| #define PB_Gui_StopScreenStreamRequest_init_zero {0} | #define PB_Gui_StopScreenStreamRequest_init_zero {0} | ||||||
| #define PB_Gui_ScreenStreamFrame_init_zero       {NULL} |  | ||||||
| #define PB_Gui_SendInputEventRequest_init_zero   {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} | #define PB_Gui_SendInputEventRequest_init_zero   {_PB_Gui_InputKey_MIN, _PB_Gui_InputType_MIN} | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_init_zero {0} | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_init_zero {0} | ||||||
| 
 | 
 | ||||||
| /* Field tags (for use in manual encoding/decoding) */ | /* Field tags (for use in manual encoding/decoding) */ | ||||||
| #define PB_Gui_ScreenStreamFrame_data_tag        1 | #define PB_Gui_ScreenFrame_data_tag              1 | ||||||
| #define PB_Gui_SendInputEventRequest_key_tag     1 | #define PB_Gui_SendInputEventRequest_key_tag     1 | ||||||
| #define PB_Gui_SendInputEventRequest_type_tag    2 | #define PB_Gui_SendInputEventRequest_type_tag    2 | ||||||
| 
 | 
 | ||||||
| /* Struct field encoding specification for nanopb */ | /* Struct field encoding specification for nanopb */ | ||||||
|  | #define PB_Gui_ScreenFrame_FIELDLIST(X, a) \ | ||||||
|  | X(a, POINTER,  SINGULAR, BYTES,    data,              1) | ||||||
|  | #define PB_Gui_ScreenFrame_CALLBACK NULL | ||||||
|  | #define PB_Gui_ScreenFrame_DEFAULT NULL | ||||||
|  | 
 | ||||||
| #define PB_Gui_StartScreenStreamRequest_FIELDLIST(X, a) \ | #define PB_Gui_StartScreenStreamRequest_FIELDLIST(X, a) \ | ||||||
| 
 | 
 | ||||||
| #define PB_Gui_StartScreenStreamRequest_CALLBACK NULL | #define PB_Gui_StartScreenStreamRequest_CALLBACK NULL | ||||||
| @ -86,33 +103,44 @@ extern "C" { | |||||||
| #define PB_Gui_StopScreenStreamRequest_CALLBACK NULL | #define PB_Gui_StopScreenStreamRequest_CALLBACK NULL | ||||||
| #define PB_Gui_StopScreenStreamRequest_DEFAULT NULL | #define PB_Gui_StopScreenStreamRequest_DEFAULT NULL | ||||||
| 
 | 
 | ||||||
| #define PB_Gui_ScreenStreamFrame_FIELDLIST(X, a) \ |  | ||||||
| X(a, POINTER,  SINGULAR, BYTES,    data,              1) |  | ||||||
| #define PB_Gui_ScreenStreamFrame_CALLBACK NULL |  | ||||||
| #define PB_Gui_ScreenStreamFrame_DEFAULT NULL |  | ||||||
| 
 |  | ||||||
| #define PB_Gui_SendInputEventRequest_FIELDLIST(X, a) \ | #define PB_Gui_SendInputEventRequest_FIELDLIST(X, a) \ | ||||||
| X(a, STATIC,   SINGULAR, UENUM,    key,               1) \ | X(a, STATIC,   SINGULAR, UENUM,    key,               1) \ | ||||||
| X(a, STATIC,   SINGULAR, UENUM,    type,              2) | X(a, STATIC,   SINGULAR, UENUM,    type,              2) | ||||||
| #define PB_Gui_SendInputEventRequest_CALLBACK NULL | #define PB_Gui_SendInputEventRequest_CALLBACK NULL | ||||||
| #define PB_Gui_SendInputEventRequest_DEFAULT NULL | #define PB_Gui_SendInputEventRequest_DEFAULT NULL | ||||||
| 
 | 
 | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_FIELDLIST(X, a) \ | ||||||
|  | 
 | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_CALLBACK NULL | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_DEFAULT NULL | ||||||
|  | 
 | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_FIELDLIST(X, a) \ | ||||||
|  | 
 | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_CALLBACK NULL | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_DEFAULT NULL | ||||||
|  | 
 | ||||||
|  | extern const pb_msgdesc_t PB_Gui_ScreenFrame_msg; | ||||||
| extern const pb_msgdesc_t PB_Gui_StartScreenStreamRequest_msg; | extern const pb_msgdesc_t PB_Gui_StartScreenStreamRequest_msg; | ||||||
| extern const pb_msgdesc_t PB_Gui_StopScreenStreamRequest_msg; | extern const pb_msgdesc_t PB_Gui_StopScreenStreamRequest_msg; | ||||||
| extern const pb_msgdesc_t PB_Gui_ScreenStreamFrame_msg; |  | ||||||
| extern const pb_msgdesc_t PB_Gui_SendInputEventRequest_msg; | extern const pb_msgdesc_t PB_Gui_SendInputEventRequest_msg; | ||||||
|  | extern const pb_msgdesc_t PB_Gui_StartVirtualDisplayRequest_msg; | ||||||
|  | extern const pb_msgdesc_t PB_Gui_StopVirtualDisplayRequest_msg; | ||||||
| 
 | 
 | ||||||
| /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ | /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ | ||||||
|  | #define PB_Gui_ScreenFrame_fields &PB_Gui_ScreenFrame_msg | ||||||
| #define PB_Gui_StartScreenStreamRequest_fields &PB_Gui_StartScreenStreamRequest_msg | #define PB_Gui_StartScreenStreamRequest_fields &PB_Gui_StartScreenStreamRequest_msg | ||||||
| #define PB_Gui_StopScreenStreamRequest_fields &PB_Gui_StopScreenStreamRequest_msg | #define PB_Gui_StopScreenStreamRequest_fields &PB_Gui_StopScreenStreamRequest_msg | ||||||
| #define PB_Gui_ScreenStreamFrame_fields &PB_Gui_ScreenStreamFrame_msg |  | ||||||
| #define PB_Gui_SendInputEventRequest_fields &PB_Gui_SendInputEventRequest_msg | #define PB_Gui_SendInputEventRequest_fields &PB_Gui_SendInputEventRequest_msg | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_fields &PB_Gui_StartVirtualDisplayRequest_msg | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_fields &PB_Gui_StopVirtualDisplayRequest_msg | ||||||
| 
 | 
 | ||||||
| /* Maximum encoded size of messages (where known) */ | /* Maximum encoded size of messages (where known) */ | ||||||
| /* PB_Gui_ScreenStreamFrame_size depends on runtime parameters */ | /* PB_Gui_ScreenFrame_size depends on runtime parameters */ | ||||||
| #define PB_Gui_SendInputEventRequest_size        4 | #define PB_Gui_SendInputEventRequest_size        4 | ||||||
| #define PB_Gui_StartScreenStreamRequest_size     0 | #define PB_Gui_StartScreenStreamRequest_size     0 | ||||||
|  | #define PB_Gui_StartVirtualDisplayRequest_size   0 | ||||||
| #define PB_Gui_StopScreenStreamRequest_size      0 | #define PB_Gui_StopScreenStreamRequest_size      0 | ||||||
|  | #define PB_Gui_StopVirtualDisplayRequest_size    0 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } /* extern "C" */ | } /* extern "C" */ | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| Subproject commit 0e6d374ab1a12f95a3cd04444376a261e7252db4 | Subproject commit 6be7def6087c4d277386381ff2792fa622933668 | ||||||
| @ -1,148 +1,151 @@ | |||||||
| A00000000305076010 VISA ELO Credit | Filetype: Flipper EMV resources | ||||||
| A0000000031010 VISA Debit/Credit (Classic) | Version: 1 | ||||||
| A000000003101001 VISA Credit | # EMV Application ID code: Application ID name | ||||||
| A000000003101002 VISA Debit | A00000000305076010: VISA ELO Credit | ||||||
| A0000000032010 VISA Electron | A0000000031010: VISA Debit/Credit (Classic) | ||||||
| A0000000032020 VISA | A000000003101001: VISA Credit | ||||||
| A0000000033010 VISA Interlink | A000000003101002: VISA Debit | ||||||
| A0000000034010 VISA Specific | A0000000032010: VISA Electron | ||||||
| A0000000035010 VISA Specific | A0000000032020: VISA | ||||||
| A0000000036010 Domestic Visa Cash | A0000000033010: VISA Interlink | ||||||
| A0000000036020 International Visa Cash | A0000000034010: VISA Specific | ||||||
| A0000000038002 VISA Auth EMV-CAP (DPA) | A0000000035010: VISA Specific | ||||||
| A0000000038010 VISA Plus | A0000000036010: Domestic Visa Cash | ||||||
| A0000000039010 VISA Loyalty | A0000000036020: International Visa Cash | ||||||
| A000000003999910 VISA Proprietary ATM | A0000000038002: VISA Auth EMV-CAP (DPA) | ||||||
| A00000000401 MasterCard PayPass | A0000000038010: VISA Plus | ||||||
| A0000000041010 MasterCard Global | A0000000039010: VISA Loyalty | ||||||
| A00000000410101213 MasterCard Credit | A000000003999910: VISA Proprietary ATM | ||||||
| A00000000410101215 MasterCard Credit | A00000000401: MasterCard PayPass | ||||||
| A0000000042010 MasterCard Specific | A0000000041010: MasterCard Global | ||||||
| A0000000043010 MasterCard Specific | A00000000410101213: MasterCard Credit | ||||||
| A0000000043060 Maestro (Debit) | A00000000410101215: MasterCard Credit | ||||||
| A000000004306001 Maestro (Debit) | A0000000042010: MasterCard Specific | ||||||
| A0000000044010 MasterCard Specific | A0000000043010: MasterCard Specific | ||||||
| A0000000045010 MasterCard Specific | A0000000043060: Maestro (Debit) | ||||||
| A0000000046000 Cirrus | A000000004306001: Maestro (Debit) | ||||||
| A0000000048002 SecureCode EMV-CAP | A0000000044010: MasterCard Specific | ||||||
| A0000000049999 MasterCard PayPass | A0000000045010: MasterCard Specific | ||||||
| A0000000050001 Maestro UK | A0000000046000: Cirrus | ||||||
| A0000000050002 Solo | A0000000048002: SecureCode EMV-CAP | ||||||
| A00000002401 Self Service | A0000000049999: MasterCard PayPass | ||||||
| A000000025 American Express | A0000000050001: Maestro UK | ||||||
| A0000000250000 American Express | A0000000050002: Solo | ||||||
| A00000002501 American Express | A00000002401: Self Service | ||||||
| A000000025010402 American Express | A000000025: American Express | ||||||
| A000000025010701 ExpressPay | A0000000250000: American Express | ||||||
| A000000025010801 American Express | A00000002501: American Express | ||||||
| A0000000291010 Link / American Express | A000000025010402: American Express | ||||||
| A0000000421010 Cartes Bancaire EMV Card | A000000025010701: ExpressPay | ||||||
| A0000000426010 Apple Pay | A000000025010801: American Express | ||||||
| A00000006510 JCB | A0000000291010: Link / American Express | ||||||
| A0000000651010 JCB J Smart Credit | A0000000421010: Cartes Bancaire EMV Card | ||||||
| A00000006900 Moneo | A0000000426010: Apple Pay | ||||||
| A000000077010000021000000000003B Visa AEPN | A00000006510: JCB | ||||||
| A000000098 Debit Card | A0000000651010: JCB J Smart Credit | ||||||
| A0000000980848 Debit Card | A00000006900: Moneo | ||||||
| A0000001211010 Dankort VISA GEM Vision | A000000077010000021000000000003B: Visa AEPN | ||||||
| A0000001410001 PagoBANCOMAT | A000000098: Debit Card | ||||||
| A0000001523010 Discover, Pulse D Pas | A0000000980848: Debit Card | ||||||
| A0000001524010 Discover | A0000001211010: Dankort VISA GEM Vision | ||||||
| A0000001544442 Banricompras Debito | A0000001410001: PagoBANCOMAT | ||||||
| A000000172950001 BAROC Taiwan | A0000001523010: Discover, Pulse D Pas | ||||||
| A0000002281010 SPAN (M/Chip) | A0000001524010: Discover | ||||||
| A0000002282010 SPAN (VIS) | A0000001544442: Banricompras Debito | ||||||
| A0000002771010 INTERAC | A000000172950001: BAROC Taiwan | ||||||
| A00000031510100528 Currence PuC | A0000002281010: SPAN (M/Chip) | ||||||
| A0000003156020 Chipknip | A0000002282010: SPAN (VIS) | ||||||
| A0000003591010028001 Girocard EAPS | A0000002771010: INTERAC | ||||||
| A0000003710001 InterSwitch Verve Card | A00000031510100528: Currence PuC | ||||||
| A0000004540010 Etranzact Genesis Card | A0000003156020: Chipknip | ||||||
| A0000004540011 Etranzact Genesis Card 2 | A0000003591010028001: Girocard EAPS | ||||||
| A0000004766C GOOGLE_PAYMENT | A0000003710001: InterSwitch Verve Card | ||||||
| A0000005241010 RuPay | A0000004540010: Etranzact Genesis Card | ||||||
| A0000006723010 TROY chip credit card | A0000004540011: Etranzact Genesis Card 2 | ||||||
| A0000006723020 TROY chip debit card | A0000004766C: GOOGLE_PAYMENT | ||||||
| A0000007705850 XTRAPOWER | A0000005241010: RuPay | ||||||
| B012345678 Maestro TEST | A0000006723010: TROY chip credit card | ||||||
| D27600002545500100 Girocard | A0000006723020: TROY chip debit card | ||||||
| D5780000021010 Bankaxept | A0000007705850: XTRAPOWER | ||||||
| F0000000030001 BRADESCO | B012345678: Maestro TEST | ||||||
| A000000003000000 (VISA) Card Manager | D27600002545500100: Girocard | ||||||
| A000000003534441 Schlumberger SD | D5780000021010: Bankaxept | ||||||
| A0000000035350 Security Domain | F0000000030001: BRADESCO | ||||||
| A000000003535041 Security Domain | A000000003000000: (VISA) Card Manager | ||||||
| A0000000040000 MasterCard Card Manager | A000000003534441: Schlumberger SD | ||||||
| A000000018434D Gemplus card manager | A0000000035350: Security Domain | ||||||
| A000000018434D00 Gemplus Security Domain | A000000003535041: Security Domain | ||||||
| A0000000960200 Proton WISD | A0000000040000: MasterCard Card Manager | ||||||
| A0000001510000 Global Platform SD | A000000018434D: Gemplus card manager | ||||||
| A00000015153504341534400 CASD_AID | A000000018434D00: Gemplus Security Domain | ||||||
| A000000476A010 GSD_MANAGER_AID | A0000000960200: Proton WISD | ||||||
| A000000476A110 GSD_MANAGER_AID | A0000001510000: Global Platform SD | ||||||
| 315041592E5359532E4444463031 Visa PSE  | A00000015153504341534400: CASD_AID | ||||||
| 325041592E5359532E4444463031 Visa PPSE | A000000476A010: GSD_MANAGER_AID | ||||||
| A0000000042203 MasterCard Specific | A000000476A110: GSD_MANAGER_AID | ||||||
| A0000000045555 APDULogger | 315041592E5359532E4444463031: Visa PSE  | ||||||
| A0000000090001FF44FF1289 Orange | 325041592E5359532E4444463031: Visa PPSE | ||||||
| A0000000101030 Maestro-CH | A0000000042203: MasterCard Specific | ||||||
| A00000001800 Gemplus | A0000000045555: APDULogger | ||||||
| A0000000181001 gemplus util packages | A0000000090001FF44FF1289: Orange | ||||||
| A000000025010104 American Express | A0000000101030: Maestro-CH | ||||||
| A00000002949034010100001 HSBC | A00000001800: Gemplus | ||||||
| A00000002949282010100000 Barclay | A0000000181001: gemplus util packages | ||||||
| A00000005945430100 Girocard Electronic Cash | A000000025010104: American Express | ||||||
| A0000000980840 Visa Common Debit | A00000002949034010100001: HSBC | ||||||
| A0000001570010 AMEX | A00000002949282010100000: Barclay | ||||||
| A0000001570020 MasterCard | A00000005945430100: Girocard Electronic Cash | ||||||
| A0000001570021 Maestro | A0000000980840: Visa Common Debit | ||||||
| A0000001570022 Maestro | A0000001570010: AMEX | ||||||
| A0000001570023 CASH | A0000001570020: MasterCard | ||||||
| A0000001570030 VISA | A0000001570021: Maestro | ||||||
| A0000001570031 VISA | A0000001570022: Maestro | ||||||
| A0000001570040 JCB | A0000001570023: CASH | ||||||
| A0000001570050 Postcard | A0000001570030: VISA | ||||||
| A0000001570051 Postcard | A0000001570031: VISA | ||||||
| A0000001570100 MCard | A0000001570040: JCB | ||||||
| A0000001570104 MyOne | A0000001570050: Postcard | ||||||
| A000000157010C WIRCard | A0000001570051: Postcard | ||||||
| A000000157010D Power Card | A0000001570100: MCard | ||||||
| A0000001574443 DINERS CLUB | A0000001570104: MyOne | ||||||
| A0000001574444 Supercard Plus | A000000157010C: WIRCard | ||||||
| A00000022820101010 SPAN | A000000157010D: Power Card | ||||||
| A000000308000010000100 ID-ONE PIV BIO | A0000001574443: DINERS CLUB | ||||||
| A0000003241010 Discover Zip | A0000001574444: Supercard Plus | ||||||
| A000000333010101 UnionPay Debit | A00000022820101010: SPAN | ||||||
| A000000333010102 UnionPay Credit | A000000308000010000100: ID-ONE PIV BIO | ||||||
| A000000333010103 UnionPay Quasi Credit | A0000003241010: Discover Zip | ||||||
| A000000333010106 UnionPay Electronic Cash | A000000333010101: UnionPay Debit | ||||||
| A000000333010108 U.S. UnionPay Common Debit | A000000333010102: UnionPay Credit | ||||||
| A000000337102000 Classic | A000000333010103: UnionPay Quasi Credit | ||||||
| A000000337101001 Prepaye Online | A000000333010106: UnionPay Electronic Cash | ||||||
| A000000337102001 Prepaye Possibile Offiline | A000000333010108: U.S. UnionPay Common Debit | ||||||
| A000000337601001 Porte Monnaie Electronique | A000000337102000: Classic | ||||||
| A0000006581010 MIR Credit | A000000337101001: Prepaye Online | ||||||
| A0000006581011 MIR Credit | A000000337102001: Prepaye Possibile Offiline | ||||||
| A0000006582010 MIR Debit | A000000337601001: Porte Monnaie Electronique | ||||||
| D040000001000002 Paylife Quick IEP | A0000006581010: MIR Credit | ||||||
| D040000002000002 RFU | A0000006581011: MIR Credit | ||||||
| D040000003000002 POS | A0000006582010: MIR Debit | ||||||
| D040000004000002 ATM | D040000001000002: Paylife Quick IEP | ||||||
| D04000000B000002 Retail | D040000002000002: RFU | ||||||
| D04000000C000002 Bank_Data | D040000003000002: POS | ||||||
| D04000000D000002 Shopping | D040000004000002: ATM | ||||||
| D040000013000001 DF_UNI_Kepler1 | D04000000B000002: Retail | ||||||
| D040000013000001 DF_Schüler1 | D04000000C000002: Bank_Data | ||||||
| D040000013000002 DF_UNI_Kepler2 | D04000000D000002: Shopping | ||||||
| D040000013000002 DF_Schüler2 | D040000013000001: DF_UNI_Kepler1 | ||||||
| D040000014000001 DF_Mensa | D040000013000001: DF_Schüler1 | ||||||
| D040000015000001 DF_UNI_Ausweis | D040000013000002: DF_UNI_Kepler2 | ||||||
| D040000015000001 DF_Ausweis | D040000013000002: DF_Schüler2 | ||||||
| D0400000190001 EMV ATM Maestro | D040000014000001: DF_Mensa | ||||||
| D0400000190002 EMV POS Maestro | D040000015000001: DF_UNI_Ausweis | ||||||
| D0400000190003 EMV ATM MasterCard | D040000015000001: DF_Ausweis | ||||||
| D0400000190004 EMV POS MasterCard | D0400000190001: EMV ATM Maestro | ||||||
| D276000025 Girocard | D0400000190002: EMV POS Maestro | ||||||
| D27600002547410100 Girocard ATM | D0400000190003: EMV ATM MasterCard | ||||||
| D7560000010101 Reka Card | D0400000190004: EMV POS MasterCard | ||||||
| D7560000300101 M Budget | D276000025: Girocard | ||||||
|  | D27600002547410100: Girocard ATM | ||||||
|  | D7560000010101: Reka Card | ||||||
|  | D7560000300101: M Budget | ||||||
| @ -1,249 +1,252 @@ | |||||||
| 0004 AFG | Filetype: Flipper EMV resources | ||||||
| 0008 ALB | Version: 1 | ||||||
| 0010 ATA | # EMV country code: country name | ||||||
| 0012 DZA | 0004: AFG | ||||||
| 0016 ASM | 0008: ALB | ||||||
| 0020 AND | 0010: ATA | ||||||
| 0024 AGO | 0012: DZA | ||||||
| 0028 ATG | 0016: ASM | ||||||
| 0031 AZE | 0020: AND | ||||||
| 0032 ARG | 0024: AGO | ||||||
| 0036 AUS | 0028: ATG | ||||||
| 0040 AUT | 0031: AZE | ||||||
| 0044 BHS | 0032: ARG | ||||||
| 0048 BHR | 0036: AUS | ||||||
| 0050 BGD | 0040: AUT | ||||||
| 0051 ARM | 0044: BHS | ||||||
| 0052 BRB | 0048: BHR | ||||||
| 0056 BEL | 0050: BGD | ||||||
| 0060 BMU | 0051: ARM | ||||||
| 0064 BTN | 0052: BRB | ||||||
| 0068 BOL | 0056: BEL | ||||||
| 0070 BIH | 0060: BMU | ||||||
| 0072 BWA | 0064: BTN | ||||||
| 0074 BVT | 0068: BOL | ||||||
| 0076 BRA | 0070: BIH | ||||||
| 0084 BLZ | 0072: BWA | ||||||
| 0086 IOT | 0074: BVT | ||||||
| 0090 SLB | 0076: BRA | ||||||
| 0092 VGB | 0084: BLZ | ||||||
| 0096 BRN | 0086: IOT | ||||||
| 0100 BGR | 0090: SLB | ||||||
| 0104 MMR | 0092: VGB | ||||||
| 0108 BDI | 0096: BRN | ||||||
| 0112 BLR | 0100: BGR | ||||||
| 0116 KHM | 0104: MMR | ||||||
| 0120 CMR | 0108: BDI | ||||||
| 0124 CAN | 0112: BLR | ||||||
| 0132 CPV | 0116: KHM | ||||||
| 0136 CYM | 0120: CMR | ||||||
| 0140 CAF | 0124: CAN | ||||||
| 0144 LKA | 0132: CPV | ||||||
| 0148 TCD | 0136: CYM | ||||||
| 0152 CHL | 0140: CAF | ||||||
| 0156 CHN | 0144: LKA | ||||||
| 0158 TWN | 0148: TCD | ||||||
| 0162 CXR | 0152: CHL | ||||||
| 0166 CCK | 0156: CHN | ||||||
| 0170 COL | 0158: TWN | ||||||
| 0174 COM | 0162: CXR | ||||||
| 0175 MYT | 0166: CCK | ||||||
| 0178 COG | 0170: COL | ||||||
| 0180 COD | 0174: COM | ||||||
| 0184 COK | 0175: MYT | ||||||
| 0188 CRI | 0178: COG | ||||||
| 0191 HRV | 0180: COD | ||||||
| 0192 CUB | 0184: COK | ||||||
| 0196 CYP | 0188: CRI | ||||||
| 0203 CZE | 0191: HRV | ||||||
| 0204 BEN | 0192: CUB | ||||||
| 0208 DNK | 0196: CYP | ||||||
| 0212 DMA | 0203: CZE | ||||||
| 0214 DOM | 0204: BEN | ||||||
| 0218 ECU | 0208: DNK | ||||||
| 0222 SLV | 0212: DMA | ||||||
| 0226 GNQ | 0214: DOM | ||||||
| 0231 ETH | 0218: ECU | ||||||
| 0232 ERI | 0222: SLV | ||||||
| 0233 EST | 0226: GNQ | ||||||
| 0234 FRO | 0231: ETH | ||||||
| 0238 FLK | 0232: ERI | ||||||
| 0239 SGS | 0233: EST | ||||||
| 0242 FJI | 0234: FRO | ||||||
| 0246 FIN | 0238: FLK | ||||||
| 0248 ALA | 0239: SGS | ||||||
| 0250 FRA | 0242: FJI | ||||||
| 0254 GUF | 0246: FIN | ||||||
| 0258 PYF | 0248: ALA | ||||||
| 0260 ATF | 0250: FRA | ||||||
| 0262 DJI | 0254: GUF | ||||||
| 0266 GAB | 0258: PYF | ||||||
| 0268 GEO | 0260: ATF | ||||||
| 0270 GMB | 0262: DJI | ||||||
| 0275 PSE | 0266: GAB | ||||||
| 0276 DEU | 0268: GEO | ||||||
| 0288 GHA | 0270: GMB | ||||||
| 0292 GIB | 0275: PSE | ||||||
| 0296 KIR | 0276: DEU | ||||||
| 0300 GRC | 0288: GHA | ||||||
| 0304 GRL | 0292: GIB | ||||||
| 0308 GRD | 0296: KIR | ||||||
| 0312 GLP | 0300: GRC | ||||||
| 0316 GUM | 0304: GRL | ||||||
| 0320 GTM | 0308: GRD | ||||||
| 0324 GIN | 0312: GLP | ||||||
| 0328 GUY | 0316: GUM | ||||||
| 0332 HTI | 0320: GTM | ||||||
| 0334 HMD | 0324: GIN | ||||||
| 0336 VAT | 0328: GUY | ||||||
| 0340 HND | 0332: HTI | ||||||
| 0344 HKG | 0334: HMD | ||||||
| 0348 HUN | 0336: VAT | ||||||
| 0352 ISL | 0340: HND | ||||||
| 0356 IND | 0344: HKG | ||||||
| 0360 IDN | 0348: HUN | ||||||
| 0364 IRN | 0352: ISL | ||||||
| 0368 IRQ | 0356: IND | ||||||
| 0372 IRL | 0360: IDN | ||||||
| 0376 ISR | 0364: IRN | ||||||
| 0380 ITA | 0368: IRQ | ||||||
| 0384 CIV | 0372: IRL | ||||||
| 0388 JAM | 0376: ISR | ||||||
| 0392 JPN | 0380: ITA | ||||||
| 0398 KAZ | 0384: CIV | ||||||
| 0400 JOR | 0388: JAM | ||||||
| 0404 KEN | 0392: JPN | ||||||
| 0408 PRK | 0398: KAZ | ||||||
| 0410 KOR | 0400: JOR | ||||||
| 0414 KWT | 0404: KEN | ||||||
| 0417 KGZ | 0408: PRK | ||||||
| 0418 LAO | 0410: KOR | ||||||
| 0422 LBN | 0414: KWT | ||||||
| 0426 LSO | 0417: KGZ | ||||||
| 0428 LVA | 0418: LAO | ||||||
| 0430 LBR | 0422: LBN | ||||||
| 0434 LBY | 0426: LSO | ||||||
| 0438 LIE | 0428: LVA | ||||||
| 0440 LTU | 0430: LBR | ||||||
| 0442 LUX | 0434: LBY | ||||||
| 0446 MAC | 0438: LIE | ||||||
| 0450 MDG | 0440: LTU | ||||||
| 0454 MWI | 0442: LUX | ||||||
| 0458 MYS | 0446: MAC | ||||||
| 0462 MDV | 0450: MDG | ||||||
| 0466 MLI | 0454: MWI | ||||||
| 0470 MLT | 0458: MYS | ||||||
| 0474 MTQ | 0462: MDV | ||||||
| 0478 MRT | 0466: MLI | ||||||
| 0480 MUS | 0470: MLT | ||||||
| 0484 MEX | 0474: MTQ | ||||||
| 0492 MCO | 0478: MRT | ||||||
| 0496 MNG | 0480: MUS | ||||||
| 0498 MDA | 0484: MEX | ||||||
| 0499 MNE | 0492: MCO | ||||||
| 0500 MSR | 0496: MNG | ||||||
| 0504 MAR | 0498: MDA | ||||||
| 0508 MOZ | 0499: MNE | ||||||
| 0512 OMN | 0500: MSR | ||||||
| 0516 NAM | 0504: MAR | ||||||
| 0520 NRU | 0508: MOZ | ||||||
| 0524 NPL | 0512: OMN | ||||||
| 0528 NLD | 0516: NAM | ||||||
| 0531 CUW | 0520: NRU | ||||||
| 0533 ABW | 0524: NPL | ||||||
| 0534 SXM | 0528: NLD | ||||||
| 0535 BES | 0531: CUW | ||||||
| 0540 NCL | 0533: ABW | ||||||
| 0548 VUT | 0534: SXM | ||||||
| 0554 NZL | 0535: BES | ||||||
| 0558 NIC | 0540: NCL | ||||||
| 0562 NER | 0548: VUT | ||||||
| 0566 NGA | 0554: NZL | ||||||
| 0570 NIU | 0558: NIC | ||||||
| 0574 NFK | 0562: NER | ||||||
| 0578 NOR | 0566: NGA | ||||||
| 0580 MNP | 0570: NIU | ||||||
| 0581 UMI | 0574: NFK | ||||||
| 0583 FSM | 0578: NOR | ||||||
| 0584 MHL | 0580: MNP | ||||||
| 0585 PLW | 0581: UMI | ||||||
| 0586 PAK | 0583: FSM | ||||||
| 0591 PAN | 0584: MHL | ||||||
| 0598 PNG | 0585: PLW | ||||||
| 0600 PRY | 0586: PAK | ||||||
| 0604 PER | 0591: PAN | ||||||
| 0608 PHL | 0598: PNG | ||||||
| 0612 PCN | 0600: PRY | ||||||
| 0616 POL | 0604: PER | ||||||
| 0620 PRT | 0608: PHL | ||||||
| 0624 GNB | 0612: PCN | ||||||
| 0626 TLS | 0616: POL | ||||||
| 0630 PRI | 0620: PRT | ||||||
| 0634 QAT | 0624: GNB | ||||||
| 0638 REU | 0626: TLS | ||||||
| 0642 ROU | 0630: PRI | ||||||
| 0643 RUS | 0634: QAT | ||||||
| 0646 RWA | 0638: REU | ||||||
| 0652 BLM | 0642: ROU | ||||||
| 0654 SHN | 0643: RUS | ||||||
| 0659 KNA | 0646: RWA | ||||||
| 0660 AIA | 0652: BLM | ||||||
| 0662 LCA | 0654: SHN | ||||||
| 0663 MAF | 0659: KNA | ||||||
| 0666 SPM | 0660: AIA | ||||||
| 0670 VCT | 0662: LCA | ||||||
| 0674 SMR | 0663: MAF | ||||||
| 0678 STP | 0666: SPM | ||||||
| 0682 SAU | 0670: VCT | ||||||
| 0686 SEN | 0674: SMR | ||||||
| 0688 SRB | 0678: STP | ||||||
| 0690 SYC | 0682: SAU | ||||||
| 0694 SLE | 0686: SEN | ||||||
| 0702 SGP | 0688: SRB | ||||||
| 0703 SVK | 0690: SYC | ||||||
| 0704 VNM | 0694: SLE | ||||||
| 0705 SVN | 0702: SGP | ||||||
| 0706 SOM | 0703: SVK | ||||||
| 0710 ZAF | 0704: VNM | ||||||
| 0716 ZWE | 0705: SVN | ||||||
| 0724 ESP | 0706: SOM | ||||||
| 0728 SSD | 0710: ZAF | ||||||
| 0729 SDN | 0716: ZWE | ||||||
| 0732 ESH | 0724: ESP | ||||||
| 0740 SUR | 0728: SSD | ||||||
| 0744 SJM | 0729: SDN | ||||||
| 0748 SWZ | 0732: ESH | ||||||
| 0752 SWE | 0740: SUR | ||||||
| 0756 CHE | 0744: SJM | ||||||
| 0760 SYR | 0748: SWZ | ||||||
| 0762 TJK | 0752: SWE | ||||||
| 0764 THA | 0756: CHE | ||||||
| 0768 TGO | 0760: SYR | ||||||
| 0772 TKL | 0762: TJK | ||||||
| 0776 TON | 0764: THA | ||||||
| 0780 TTO | 0768: TGO | ||||||
| 0784 ARE | 0772: TKL | ||||||
| 0788 TUN | 0776: TON | ||||||
| 0792 TUR | 0780: TTO | ||||||
| 0795 TKM | 0784: ARE | ||||||
| 0796 TCA | 0788: TUN | ||||||
| 0798 TUV | 0792: TUR | ||||||
| 0800 UGA | 0795: TKM | ||||||
| 0804 UKR | 0796: TCA | ||||||
| 0807 MKD | 0798: TUV | ||||||
| 0818 EGY | 0800: UGA | ||||||
| 0826 GBR | 0804: UKR | ||||||
| 0831 GGY | 0807: MKD | ||||||
| 0832 JEY | 0818: EGY | ||||||
| 0833 IMN | 0826: GBR | ||||||
| 0834 TZA | 0831: GGY | ||||||
| 0840 USA | 0832: JEY | ||||||
| 0850 VIR | 0833: IMN | ||||||
| 0854 BFA | 0834: TZA | ||||||
| 0858 URY | 0840: USA | ||||||
| 0860 UZB | 0850: VIR | ||||||
| 0862 VEN | 0854: BFA | ||||||
| 0876 WLF | 0858: URY | ||||||
| 0882 WSM | 0860: UZB | ||||||
| 0887 YEM | 0862: VEN | ||||||
| 0894 ZMB | 0876: WLF | ||||||
|  | 0882: WSM | ||||||
|  | 0887: YEM | ||||||
|  | 0894: ZMB | ||||||
| @ -1,168 +1,171 @@ | |||||||
| 0997 USN | Filetype: Flipper EMV resources | ||||||
| 0994 XSU | Version: 1 | ||||||
| 0990 CLF | # EMV currency code: currency name | ||||||
| 0986 BRL | 0997: USN | ||||||
| 0985 PLN | 0994: XSU | ||||||
| 0984 BOV | 0990: CLF | ||||||
| 0981 GEL | 0986: BRL | ||||||
| 0980 UAH | 0985: PLN | ||||||
| 0979 MXV | 0984: BOV | ||||||
| 0978 EUR | 0981: GEL | ||||||
| 0977 BAM | 0980: UAH | ||||||
| 0976 CDF | 0979: MXV | ||||||
| 0975 BGN | 0978: EUR | ||||||
| 0973 AOA | 0977: BAM | ||||||
| 0972 TJS | 0976: CDF | ||||||
| 0971 AFN | 0975: BGN | ||||||
| 0970 COU | 0973: AOA | ||||||
| 0969 MGA | 0972: TJS | ||||||
| 0968 SRD | 0971: AFN | ||||||
| 0967 ZMW | 0970: COU | ||||||
| 0965 XUA | 0969: MGA | ||||||
| 0960 XDR | 0968: SRD | ||||||
| 0953 XPF | 0967: ZMW | ||||||
| 0952 XOF | 0965: XUA | ||||||
| 0951 XCD | 0960: XDR | ||||||
| 0950 XAF | 0953: XPF | ||||||
| 0949 TRY | 0952: XOF | ||||||
| 0948 CHW | 0951: XCD | ||||||
| 0947 CHE | 0950: XAF | ||||||
| 0946 RON | 0949: TRY | ||||||
| 0944 AZN | 0948: CHW | ||||||
| 0943 MZN | 0947: CHE | ||||||
| 0941 RSD | 0946: RON | ||||||
| 0940 UYI | 0944: AZN | ||||||
| 0938 SDG | 0943: MZN | ||||||
| 0937 VEF | 0941: RSD | ||||||
| 0936 GHS | 0940: UYI | ||||||
| 0934 TMT | 0938: SDG | ||||||
| 0933 BYN | 0937: VEF | ||||||
| 0932 ZWL | 0936: GHS | ||||||
| 0931 CUC | 0934: TMT | ||||||
| 0930 STN | 0933: BYN | ||||||
| 0929 MRU | 0932: ZWL | ||||||
| 0901 TWD | 0931: CUC | ||||||
| 0886 YER | 0930: STN | ||||||
| 0882 WST | 0929: MRU | ||||||
| 0860 UZS | 0901: TWD | ||||||
| 0858 UYU | 0886: YER | ||||||
| 0840 USD | 0882: WST | ||||||
| 0834 TZS | 0860: UZS | ||||||
| 0826 GBP | 0858: UYU | ||||||
| 0818 EGP | 0840: USD | ||||||
| 0807 MKD | 0834: TZS | ||||||
| 0800 UGX | 0826: GBP | ||||||
| 0788 TND | 0818: EGP | ||||||
| 0784 AED | 0807: MKD | ||||||
| 0780 TTD | 0800: UGX | ||||||
| 0776 TOP | 0788: TND | ||||||
| 0764 THB | 0784: AED | ||||||
| 0760 SYP | 0780: TTD | ||||||
| 0756 CHF | 0776: TOP | ||||||
| 0752 SEK | 0764: THB | ||||||
| 0748 SZL | 0760: SYP | ||||||
| 0728 SSP | 0756: CHF | ||||||
| 0710 ZAR | 0752: SEK | ||||||
| 0706 SOS | 0748: SZL | ||||||
| 0704 VND | 0728: SSP | ||||||
| 0702 SGD | 0710: ZAR | ||||||
| 0694 SLL | 0706: SOS | ||||||
| 0690 SCR | 0704: VND | ||||||
| 0682 SAR | 0702: SGD | ||||||
| 0654 SHP | 0694: SLL | ||||||
| 0646 RWF | 0690: SCR | ||||||
| 0643 RUB | 0682: SAR | ||||||
| 0634 QAR | 0654: SHP | ||||||
| 0608 PHP | 0646: RWF | ||||||
| 0604 PEN | 0643: RUB | ||||||
| 0600 PYG | 0634: QAR | ||||||
| 0598 PGK | 0608: PHP | ||||||
| 0590 PAB | 0604: PEN | ||||||
| 0586 PKR | 0600: PYG | ||||||
| 0578 NOK | 0598: PGK | ||||||
| 0566 NGN | 0590: PAB | ||||||
| 0558 NIO | 0586: PKR | ||||||
| 0554 NZD | 0578: NOK | ||||||
| 0548 VUV | 0566: NGN | ||||||
| 0533 AWG | 0558: NIO | ||||||
| 0532 ANG | 0554: NZD | ||||||
| 0524 NPR | 0548: VUV | ||||||
| 0516 NAD | 0533: AWG | ||||||
| 0512 OMR | 0532: ANG | ||||||
| 0504 MAD | 0524: NPR | ||||||
| 0498 MDL | 0516: NAD | ||||||
| 0496 MNT | 0512: OMR | ||||||
| 0484 MXN | 0504: MAD | ||||||
| 0480 MUR | 0498: MDL | ||||||
| 0462 MVR | 0496: MNT | ||||||
| 0458 MYR | 0484: MXN | ||||||
| 0454 MWK | 0480: MUR | ||||||
| 0446 MOP | 0462: MVR | ||||||
| 0434 LYD | 0458: MYR | ||||||
| 0430 LRD | 0454: MWK | ||||||
| 0426 LSL | 0446: MOP | ||||||
| 0422 LBP | 0434: LYD | ||||||
| 0418 LAK | 0430: LRD | ||||||
| 0417 KGS | 0426: LSL | ||||||
| 0414 KWD | 0422: LBP | ||||||
| 0410 KRW | 0418: LAK | ||||||
| 0408 KPW | 0417: KGS | ||||||
| 0404 KES | 0414: KWD | ||||||
| 0400 JOD | 0410: KRW | ||||||
| 0398 KZT | 0408: KPW | ||||||
| 0392 JPY | 0404: KES | ||||||
| 0388 JMD | 0400: JOD | ||||||
| 0376 ILS | 0398: KZT | ||||||
| 0368 IQD | 0392: JPY | ||||||
| 0364 IRR | 0388: JMD | ||||||
| 0360 IDR | 0376: ILS | ||||||
| 0356 INR | 0368: IQD | ||||||
| 0352 ISK | 0364: IRR | ||||||
| 0348 HUF | 0360: IDR | ||||||
| 0344 HKD | 0356: INR | ||||||
| 0340 HNL | 0352: ISK | ||||||
| 0332 HTG | 0348: HUF | ||||||
| 0328 GYD | 0344: HKD | ||||||
| 0324 GNF | 0340: HNL | ||||||
| 0320 GTQ | 0332: HTG | ||||||
| 0292 GIP | 0328: GYD | ||||||
| 0270 GMD | 0324: GNF | ||||||
| 0262 DJF | 0320: GTQ | ||||||
| 0242 FJD | 0292: GIP | ||||||
| 0238 FKP | 0270: GMD | ||||||
| 0232 ERN | 0262: DJF | ||||||
| 0230 ETB | 0242: FJD | ||||||
| 0222 SVC | 0238: FKP | ||||||
| 0214 DOP | 0232: ERN | ||||||
| 0208 DKK | 0230: ETB | ||||||
| 0203 CZK | 0222: SVC | ||||||
| 0192 CUP | 0214: DOP | ||||||
| 0191 HRK | 0208: DKK | ||||||
| 0188 CRC | 0203: CZK | ||||||
| 0174 KMF | 0192: CUP | ||||||
| 0170 COP | 0191: HRK | ||||||
| 0156 CNY | 0188: CRC | ||||||
| 0152 CLP | 0174: KMF | ||||||
| 0144 LKR | 0170: COP | ||||||
| 0136 KYD | 0156: CNY | ||||||
| 0132 CVE | 0152: CLP | ||||||
| 0124 CAD | 0144: LKR | ||||||
| 0116 KHR | 0136: KYD | ||||||
| 0108 BIF | 0132: CVE | ||||||
| 0104 MMK | 0124: CAD | ||||||
| 0096 BND | 0116: KHR | ||||||
| 0090 SBD | 0108: BIF | ||||||
| 0084 BZD | 0104: MMK | ||||||
| 0072 BWP | 0096: BND | ||||||
| 0068 BOB | 0090: SBD | ||||||
| 0064 BTN | 0084: BZD | ||||||
| 0060 BMD | 0072: BWP | ||||||
| 0052 BBD | 0068: BOB | ||||||
| 0051 AMD | 0064: BTN | ||||||
| 0050 BDT | 0060: BMD | ||||||
| 0048 BHD | 0052: BBD | ||||||
| 0044 BSD | 0051: AMD | ||||||
| 0036 AUD | 0050: BDT | ||||||
| 0032 ARS | 0048: BHD | ||||||
| 0012 DZD | 0044: BSD | ||||||
| 0008 ALL | 0036: AUD | ||||||
|  | 0032: ARS | ||||||
|  | 0012: DZD | ||||||
|  | 0008: ALL | ||||||
| @ -3,10 +3,12 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi-hal-version.h> | #include <furi-hal-version.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "Flipper" | ||||||
|  | 
 | ||||||
| static void flipper_print_version(const char* target, const Version* version) { | static void flipper_print_version(const char* target, const Version* version) { | ||||||
|     if(version) { |     if(version) { | ||||||
|         FURI_LOG_I( |         FURI_LOG_I( | ||||||
|             "FLIPPER", |             TAG, | ||||||
|             "\r\n\t%s version:\t%s\r\n" |             "\r\n\t%s version:\t%s\r\n" | ||||||
|             "\tBuild date:\t\t%s\r\n" |             "\tBuild date:\t\t%s\r\n" | ||||||
|             "\tGit Commit:\t\t%s (%s)\r\n" |             "\tGit Commit:\t\t%s (%s)\r\n" | ||||||
| @ -18,7 +20,7 @@ static void flipper_print_version(const char* target, const Version* version) { | |||||||
|             version_get_gitbranchnum(version), |             version_get_gitbranchnum(version), | ||||||
|             version_get_gitbranch(version)); |             version_get_gitbranch(version)); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_I("FLIPPER", "No build info for %s", target); |         FURI_LOG_I(TAG, "No build info for %s", target); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -31,10 +33,10 @@ void flipper_init() { | |||||||
|     version = (const Version*)furi_hal_version_get_firmware_version(); |     version = (const Version*)furi_hal_version_get_firmware_version(); | ||||||
|     flipper_print_version("Firmware", version); |     flipper_print_version("Firmware", version); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("FLIPPER", "starting services"); |     FURI_LOG_I(TAG, "starting services"); | ||||||
| 
 | 
 | ||||||
|     for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { |     for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { | ||||||
|         FURI_LOG_I("FLIPPER", "starting service %s", FLIPPER_SERVICES[i].name); |         FURI_LOG_I(TAG, "starting service %s", FLIPPER_SERVICES[i].name); | ||||||
| 
 | 
 | ||||||
|         FuriThread* thread = furi_thread_alloc(); |         FuriThread* thread = furi_thread_alloc(); | ||||||
| 
 | 
 | ||||||
| @ -45,5 +47,5 @@ void flipper_init() { | |||||||
|         furi_thread_start(thread); |         furi_thread_start(thread); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_I("FLIPPER", "services startup complete"); |     FURI_LOG_I(TAG, "services startup complete"); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								core/furi/common_defines.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										6
									
								
								core/furi/common_defines.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -65,3 +65,9 @@ | |||||||
| #ifndef TOSTRING | #ifndef TOSTRING | ||||||
| #define TOSTRING(x) STRINGIFY(x) | #define TOSTRING(x) STRINGIFY(x) | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef REVERSE_BYTES_U32 | ||||||
|  | #define REVERSE_BYTES_U32(x)                                                        \ | ||||||
|  |     ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ | ||||||
|  |      (((x)&0xFF000000) >> 24)) | ||||||
|  | #endif | ||||||
| @ -57,7 +57,7 @@ | |||||||
| #endif /* CMSIS_device_header */ | #endif /* CMSIS_device_header */ | ||||||
| 
 | 
 | ||||||
| #define configENABLE_FPU                         1 | #define configENABLE_FPU                         1 | ||||||
| #define configENABLE_MPU                         1 | #define configENABLE_MPU                         0 | ||||||
| 
 | 
 | ||||||
| #define configUSE_PREEMPTION                     1 | #define configUSE_PREEMPTION                     1 | ||||||
| #define configSUPPORT_STATIC_ALLOCATION          0 | #define configSUPPORT_STATIC_ALLOCATION          0 | ||||||
| @ -101,6 +101,9 @@ | |||||||
| #define configTIMER_TASK_PRIORITY                ( 2 ) | #define configTIMER_TASK_PRIORITY                ( 2 ) | ||||||
| #define configTIMER_QUEUE_LENGTH                 32 | #define configTIMER_QUEUE_LENGTH                 32 | ||||||
| #define configTIMER_TASK_STACK_DEPTH             256 | #define configTIMER_TASK_STACK_DEPTH             256 | ||||||
|  | #define configTIMER_SERVICE_TASK_NAME          "TimersSrv" | ||||||
|  | 
 | ||||||
|  | #define configIDLE_TASK_NAME                  "(-_-)" | ||||||
| 
 | 
 | ||||||
| /* Set the following definitions to 1 to include the API function, or zero
 | /* Set the following definitions to 1 to include the API function, or zero
 | ||||||
| to exclude the API function. */ | to exclude the API function. */ | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								firmware/targets/f6/Inc/stm32_assert.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								firmware/targets/f6/Inc/stm32_assert.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | /**
 | ||||||
|  |   ****************************************************************************** | ||||||
|  |   * @file    stm32_assert.h | ||||||
|  |   * @brief   STM32 assert file. | ||||||
|  |   ****************************************************************************** | ||||||
|  |   * @attention | ||||||
|  |   * | ||||||
|  |   * <h2><center>© Copyright (c) 2019 STMicroelectronics. | ||||||
|  |   * All rights reserved.</center></h2> | ||||||
|  |   * | ||||||
|  |   * This software component is licensed by ST under BSD 3-Clause license, | ||||||
|  |   * the "License"; You may not use this file except in compliance with the | ||||||
|  |   * License. You may obtain a copy of the License at: | ||||||
|  |   *                        opensource.org/licenses/BSD-3-Clause | ||||||
|  |   * | ||||||
|  |   ****************************************************************************** | ||||||
|  |   */ | ||||||
|  | 
 | ||||||
|  | /* Define to prevent recursive inclusion -------------------------------------*/ | ||||||
|  | #ifndef __STM32_ASSERT_H | ||||||
|  | #define __STM32_ASSERT_H | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  |  extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef  USE_FULL_ASSERT | ||||||
|  |   #define assert_param(expr) ((expr) ? (void)0U : assert_failed()) | ||||||
|  |   void assert_failed(); | ||||||
|  | #else | ||||||
|  |   #define assert_param(expr) ((void)0U) | ||||||
|  | #endif /* USE_FULL_ASSERT */ | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif /* __STM32_ASSERT_H */ | ||||||
|  | 
 | ||||||
|  | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||||
| @ -184,7 +184,7 @@ | |||||||
|   * @brief Uncomment the line below to expanse the "assert_param" macro in the |   * @brief Uncomment the line below to expanse the "assert_param" macro in the | ||||||
|   *        HAL drivers code |   *        HAL drivers code | ||||||
|   */ |   */ | ||||||
| /* #define USE_FULL_ASSERT    1U */ | #define USE_FULL_ASSERT    1U | ||||||
| 
 | 
 | ||||||
| /* ################## SPI peripheral configuration ########################## */ | /* ################## SPI peripheral configuration ########################## */ | ||||||
| 
 | 
 | ||||||
| @ -329,17 +329,8 @@ | |||||||
| 
 | 
 | ||||||
| /* Exported macro ------------------------------------------------------------*/ | /* Exported macro ------------------------------------------------------------*/ | ||||||
| #ifdef  USE_FULL_ASSERT | #ifdef  USE_FULL_ASSERT | ||||||
| /**
 |   #define assert_param(expr) ((expr) ? (void)0U : assert_failed()) | ||||||
|   * @brief  The assert_param macro is used for function's parameters check. |   void assert_failed(); | ||||||
|   * @param expr If expr is false, it calls assert_failed function |  | ||||||
|   *         which reports the name of the source file and the source |  | ||||||
|   *         line number of the call that failed. |  | ||||||
|   *         If expr is true, it returns no value. |  | ||||||
|   * @retval None |  | ||||||
|   */ |  | ||||||
|   #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) |  | ||||||
| /* Exported functions ------------------------------------------------------- */ |  | ||||||
|   void assert_failed(uint8_t* file, uint32_t line); |  | ||||||
| #else | #else | ||||||
|   #define assert_param(expr) ((void)0U) |   #define assert_param(expr) ((void)0U) | ||||||
| #endif /* USE_FULL_ASSERT */ | #endif /* USE_FULL_ASSERT */ | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| #include "main.h" | #include "main.h" | ||||||
| 
 | 
 | ||||||
| #include "fatfs/fatfs.h" |  | ||||||
| 
 |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <flipper.h> | #include <flipper.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "Main" | ||||||
|  | 
 | ||||||
| int main(void) { | int main(void) { | ||||||
|     // Initialize FURI layer
 |     // Initialize FURI layer
 | ||||||
|     furi_init(); |     furi_init(); | ||||||
| @ -16,13 +16,9 @@ int main(void) { | |||||||
|     // Flipper FURI HAL
 |     // Flipper FURI HAL
 | ||||||
|     furi_hal_init(); |     furi_hal_init(); | ||||||
| 
 | 
 | ||||||
|     // 3rd party
 |  | ||||||
|     MX_FATFS_Init(); |  | ||||||
|     FURI_LOG_I("HAL", "FATFS OK"); |  | ||||||
| 
 |  | ||||||
|     // CMSIS initialization
 |     // CMSIS initialization
 | ||||||
|     osKernelInitialize(); |     osKernelInitialize(); | ||||||
|     FURI_LOG_I("HAL", "KERNEL OK"); |     FURI_LOG_I(TAG, "KERNEL OK"); | ||||||
| 
 | 
 | ||||||
|     // Init flipper
 |     // Init flipper
 | ||||||
|     flipper_init(); |     flipper_init(); | ||||||
| @ -47,9 +43,6 @@ void Error_Handler(void) { | |||||||
|     * @retval None |     * @retval None | ||||||
|     */ |     */ | ||||||
| void assert_failed(uint8_t *file, uint32_t line) { | void assert_failed(uint8_t *file, uint32_t line) { | ||||||
|     /* USER CODE BEGIN 6 */ |     furi_crash("HAL assert failed"); | ||||||
|     /* User can add his own implementation to report the file name and line number,
 |  | ||||||
|          tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ |  | ||||||
|     /* USER CODE END 6 */ |  | ||||||
| } | } | ||||||
| #endif /* USE_FULL_ASSERT */ | #endif /* USE_FULL_ASSERT */ | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #define BATTERY_SERVICE_TAG "battery service" | #define TAG "BtBatterySvc" | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint16_t svc_handle; |     uint16_t svc_handle; | ||||||
| @ -23,7 +23,7 @@ void battery_svc_start() { | |||||||
|     // Add Battery service
 |     // Add Battery service
 | ||||||
|     status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle); |     status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status); |         FURI_LOG_E(TAG, "Failed to add Battery service: %d", status); | ||||||
|     } |     } | ||||||
|     // Add Battery level characteristic
 |     // Add Battery level characteristic
 | ||||||
|     status = aci_gatt_add_char(battery_svc->svc_handle, |     status = aci_gatt_add_char(battery_svc->svc_handle, | ||||||
| @ -37,7 +37,7 @@ void battery_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_CONSTANT, |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|                                 &battery_svc->char_level_handle); |                                 &battery_svc->char_level_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status); |         FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -47,12 +47,12 @@ void battery_svc_stop() { | |||||||
|         // Delete Battery level characteristic
 |         // Delete Battery level characteristic
 | ||||||
|         status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle); |         status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery level characteristic: %d", status); |             FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status); | ||||||
|         } |         } | ||||||
|         // Delete Battery service
 |         // Delete Battery service
 | ||||||
|         status = aci_gatt_del_service(battery_svc->svc_handle); |         status = aci_gatt_del_service(battery_svc->svc_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to delete Battery service: %d", status); |             FURI_LOG_E(TAG, "Failed to delete Battery service: %d", status); | ||||||
|         } |         } | ||||||
|         free(battery_svc); |         free(battery_svc); | ||||||
|         battery_svc = NULL; |         battery_svc = NULL; | ||||||
| @ -65,14 +65,14 @@ bool battery_svc_update_level(uint8_t battery_charge) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     // Update battery level characteristic
 |     // Update battery level characteristic
 | ||||||
|     FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic"); |     FURI_LOG_I(TAG, "Updating battery level characteristic"); | ||||||
|     tBleStatus result = aci_gatt_update_char_value(battery_svc->svc_handle, |     tBleStatus result = aci_gatt_update_char_value(battery_svc->svc_handle, | ||||||
|                                           battery_svc->char_level_handle, |                                           battery_svc->char_level_handle, | ||||||
|                                           0, |                                           0, | ||||||
|                                           1, |                                           1, | ||||||
|                                           &battery_charge); |                                           &battery_charge); | ||||||
|     if(result) { |     if(result) { | ||||||
|         FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed updating RX characteristic: %d", result); |         FURI_LOG_E(TAG, "Failed updating RX characteristic: %d", result); | ||||||
|     } |     } | ||||||
|     return result != BLE_STATUS_SUCCESS; |     return result != BLE_STATUS_SUCCESS; | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| #define BLE_APP_TAG "ble app" | #define TAG "Bt" | ||||||
| 
 | 
 | ||||||
| PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; | PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t ble_app_cmd_buffer; | ||||||
| PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; | PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint32_t ble_app_nvm[BLE_NVM_SRAM_SIZE]; | ||||||
| @ -33,7 +33,7 @@ bool ble_app_init() { | |||||||
|     ble_app->hci_mtx = osMutexNew(NULL); |     ble_app->hci_mtx = osMutexNew(NULL); | ||||||
|     ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); |     ble_app->hci_sem = osSemaphoreNew(1, 0, NULL); | ||||||
|     // HCI transport layer thread to handle user asynch events
 |     // HCI transport layer thread to handle user asynch events
 | ||||||
|     ble_app->hci_thread_attr.name = "ble hci"; |     ble_app->hci_thread_attr.name = "BleHciWorker"; | ||||||
|     ble_app->hci_thread_attr.stack_size = 1024; |     ble_app->hci_thread_attr.stack_size = 1024; | ||||||
|     ble_app->hci_thread_id = osThreadNew(ble_app_hci_thread, NULL, &ble_app->hci_thread_attr); |     ble_app->hci_thread_id = osThreadNew(ble_app_hci_thread, NULL, &ble_app->hci_thread_attr); | ||||||
| 
 | 
 | ||||||
| @ -53,7 +53,7 @@ bool ble_app_init() { | |||||||
|     }; |     }; | ||||||
|     status = SHCI_C2_Config(&config_param); |     status = SHCI_C2_Config(&config_param); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(BLE_APP_TAG, "Failed to configure 2nd core: %d", status); |         FURI_LOG_E(TAG, "Failed to configure 2nd core: %d", status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Start ble stack on 2nd core
 |     // Start ble stack on 2nd core
 | ||||||
| @ -82,7 +82,7 @@ bool ble_app_init() { | |||||||
|     }; |     }; | ||||||
|     status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); |     status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(BLE_APP_TAG, "Failed to start ble stack: %d", status); |         FURI_LOG_E(TAG, "Failed to start ble stack: %d", status); | ||||||
|     } |     } | ||||||
|     return status == SHCI_Success; |     return status == SHCI_Success; | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,8 @@ | |||||||
| #include "app_debug.h" | #include "app_debug.h" | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
|  | #define TAG "Core2" | ||||||
|  | 
 | ||||||
| #define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) | #define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U)) | ||||||
| 
 | 
 | ||||||
| PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; | PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_event_pool[POOL_SIZE]; | ||||||
| @ -17,6 +19,16 @@ PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_b | |||||||
| PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; | PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U]; | ||||||
| PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; | PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255]; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     // Stage 1: core2 startup and FUS
 | ||||||
|  |     BleGlueStatusStartup, | ||||||
|  |     BleGlueStatusBroken, | ||||||
|  |     BleGlueStatusFusStarted, | ||||||
|  |     // Stage 2: radio stack
 | ||||||
|  |     BleGlueStatusRadioStackStarted, | ||||||
|  |     BleGlueStatusRadioStackMissing | ||||||
|  | } BleGlueStatus; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     osMutexId_t shci_mtx; |     osMutexId_t shci_mtx; | ||||||
|     osSemaphoreId_t shci_sem; |     osSemaphoreId_t shci_sem; | ||||||
| @ -33,13 +45,6 @@ static void ble_glue_user_event_thread(void *argument); | |||||||
| static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); | static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status); | ||||||
| static void ble_glue_sys_user_event_callback(void* pPayload); | static void ble_glue_sys_user_event_callback(void* pPayload); | ||||||
| 
 | 
 | ||||||
| BleGlueStatus ble_glue_get_status() { |  | ||||||
|     if(!ble_glue) { |  | ||||||
|         return BleGlueStatusUninitialized; |  | ||||||
|     } |  | ||||||
|     return ble_glue->status; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { | void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) { | ||||||
|     furi_assert(ble_glue); |     furi_assert(ble_glue); | ||||||
|     furi_assert(callback); |     furi_assert(callback); | ||||||
| @ -50,7 +55,7 @@ void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback | |||||||
| void ble_glue_init() { | void ble_glue_init() { | ||||||
|     ble_glue = furi_alloc(sizeof(BleGlue)); |     ble_glue = furi_alloc(sizeof(BleGlue)); | ||||||
|     ble_glue->status = BleGlueStatusStartup; |     ble_glue->status = BleGlueStatusStartup; | ||||||
|     ble_glue->shci_user_event_thread_attr.name = "ble_shci_evt"; |     ble_glue->shci_user_event_thread_attr.name = "BleShciWorker"; | ||||||
|     ble_glue->shci_user_event_thread_attr.stack_size = 1024; |     ble_glue->shci_user_event_thread_attr.stack_size = 1024; | ||||||
| 
 | 
 | ||||||
|     // Configure the system Power Mode
 |     // Configure the system Power Mode
 | ||||||
| @ -94,6 +99,68 @@ void ble_glue_init() { | |||||||
|      */ |      */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool ble_glue_wait_status(BleGlueStatus status) { | ||||||
|  |     bool ret = false; | ||||||
|  |     size_t countdown = 1000; | ||||||
|  |     while (countdown > 0) { | ||||||
|  |         if (ble_glue->status == status) { | ||||||
|  |             ret = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         countdown--; | ||||||
|  |         osDelay(1); | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ble_glue_start() { | ||||||
|  |     furi_assert(ble_glue); | ||||||
|  | 
 | ||||||
|  |     if (!ble_glue_wait_status(BleGlueStatusFusStarted)) { | ||||||
|  |         // shutdown core2 power
 | ||||||
|  |         FURI_LOG_E(TAG, "Core2 catastrophic failure, cutting its power"); | ||||||
|  |         LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN); | ||||||
|  |         ble_glue->status = BleGlueStatusBroken; | ||||||
|  |         furi_hal_power_insomnia_exit(); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ret = false; | ||||||
|  |     furi_hal_power_insomnia_enter(); | ||||||
|  |     if(ble_app_init()) { | ||||||
|  |         FURI_LOG_I(TAG, "Radio stack started"); | ||||||
|  |         ble_glue->status = BleGlueStatusRadioStackStarted; | ||||||
|  |         ret = true; | ||||||
|  |         if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { | ||||||
|  |             FURI_LOG_I(TAG, "Flash activity control switched to SEM7"); | ||||||
|  |         } else { | ||||||
|  |             FURI_LOG_E(TAG, "Failed to switch flash activity control to SEM7"); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_E(TAG, "Radio stack startup failed"); | ||||||
|  |         ble_glue->status = BleGlueStatusRadioStackMissing; | ||||||
|  |     } | ||||||
|  |     furi_hal_power_insomnia_exit(); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ble_glue_is_alive() { | ||||||
|  |     if(!ble_glue) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ble_glue->status >= BleGlueStatusFusStarted; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ble_glue_is_radio_stack_ready() { | ||||||
|  |     if(!ble_glue) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ble_glue->status == BleGlueStatusRadioStackStarted; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { | static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) { | ||||||
|     switch (status) { |     switch (status) { | ||||||
|     case SHCI_TL_CmdBusy: |     case SHCI_TL_CmdBusy: | ||||||
| @ -124,21 +191,11 @@ static void ble_glue_sys_user_event_callback( void * pPayload ) { | |||||||
|     TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); |     TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload); | ||||||
|      |      | ||||||
|     if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { |     if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { | ||||||
|         if(ble_app_init()) { |         FURI_LOG_I(TAG, "Fus started"); | ||||||
|             FURI_LOG_I("Core2", "BLE stack started"); |         ble_glue->status = BleGlueStatusFusStarted; | ||||||
|             ble_glue->status = BleGlueStatusStarted; |  | ||||||
|             if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) { |  | ||||||
|                 FURI_LOG_I("Core2", "Flash activity control switched to SEM7"); |  | ||||||
|             } else { |  | ||||||
|                 FURI_LOG_E("Core2", "Failed to switch flash activity control to SEM7"); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             FURI_LOG_E("Core2", "BLE stack startup failed"); |  | ||||||
|             ble_glue->status = BleGlueStatusBleStackMissing; |  | ||||||
|         } |  | ||||||
|         furi_hal_power_insomnia_exit(); |         furi_hal_power_insomnia_exit(); | ||||||
|     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { |     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) { | ||||||
|         FURI_LOG_E("Core2", "Error during initialization"); |         FURI_LOG_E(TAG, "Error during initialization"); | ||||||
|         furi_hal_power_insomnia_exit(); |         furi_hal_power_insomnia_exit(); | ||||||
|     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { |     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE) { | ||||||
|         SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; |         SHCI_C2_BleNvmRamUpdate_Evt_t* p_sys_ble_nvm_ram_update_event = (SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload; | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -8,17 +9,33 @@ extern "C" { | |||||||
| 
 | 
 | ||||||
| typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); | typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context); | ||||||
| 
 | 
 | ||||||
| typedef enum { |  | ||||||
|     BleGlueStatusUninitialized, |  | ||||||
|     BleGlueStatusStartup, |  | ||||||
|     BleGlueStatusBleStackMissing, |  | ||||||
|     BleGlueStatusStarted |  | ||||||
| } BleGlueStatus; |  | ||||||
| 
 | 
 | ||||||
|  | /** Initialize start core2 and initialize transport */ | ||||||
| void ble_glue_init(); | void ble_glue_init(); | ||||||
| 
 | 
 | ||||||
| BleGlueStatus ble_glue_get_status(); | /** Start Core2 Radio stack
 | ||||||
|  |  * | ||||||
|  |  * @return     true on success | ||||||
|  |  */ | ||||||
|  | bool ble_glue_start(); | ||||||
| 
 | 
 | ||||||
|  | /** Is core2 alive and at least FUS is running
 | ||||||
|  |  *  | ||||||
|  |  * @return     true if core2 is alive | ||||||
|  |  */ | ||||||
|  | bool ble_glue_is_alive(); | ||||||
|  | 
 | ||||||
|  | /** Is core2 radio stack present and ready
 | ||||||
|  |  * | ||||||
|  |  * @return     true if present and ready | ||||||
|  |  */ | ||||||
|  | bool ble_glue_is_radio_stack_ready(); | ||||||
|  | 
 | ||||||
|  | /** Set callback for NVM in RAM changes
 | ||||||
|  |  * | ||||||
|  |  * @param[in]  callback  The callback to call on NVM change | ||||||
|  |  * @param      context   The context for callback | ||||||
|  |  */ | ||||||
| void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); | void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #define DEV_INFO_SVC_TAG "dev info service" | #define TAG "BtDevInfoSvc" | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint16_t service_handle; |     uint16_t service_handle; | ||||||
| @ -29,7 +29,7 @@ void dev_info_svc_start() { | |||||||
|     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; |     uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; | ||||||
|     status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc->service_handle); |     status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc->service_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add Device Information Service: %d", status); |         FURI_LOG_E(TAG, "Failed to add Device Information Service: %d", status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Add characteristics
 |     // Add characteristics
 | ||||||
| @ -45,7 +45,7 @@ void dev_info_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_CONSTANT, |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|                                 &dev_info_svc->man_name_char_handle); |                                 &dev_info_svc->man_name_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add manufacturer name char: %d", status); |         FURI_LOG_E(TAG, "Failed to add manufacturer name char: %d", status); | ||||||
|     } |     } | ||||||
|     uuid = SERIAL_NUMBER_UUID; |     uuid = SERIAL_NUMBER_UUID; | ||||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, |     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||||
| @ -59,7 +59,7 @@ void dev_info_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_CONSTANT, |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|                                 &dev_info_svc->serial_num_char_handle); |                                 &dev_info_svc->serial_num_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add serial number char: %d", status); |         FURI_LOG_E(TAG, "Failed to add serial number char: %d", status); | ||||||
|     } |     } | ||||||
|     uuid = FIRMWARE_REVISION_UUID; |     uuid = FIRMWARE_REVISION_UUID; | ||||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, |     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||||
| @ -73,7 +73,7 @@ void dev_info_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_CONSTANT, |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|                                 &dev_info_svc->firmware_rev_char_handle); |                                 &dev_info_svc->firmware_rev_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add firmware revision char: %d", status); |         FURI_LOG_E(TAG, "Failed to add firmware revision char: %d", status); | ||||||
|     } |     } | ||||||
|     uuid = SOFTWARE_REVISION_UUID; |     uuid = SOFTWARE_REVISION_UUID; | ||||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, |     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||||
| @ -87,7 +87,7 @@ void dev_info_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_CONSTANT, |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|                                 &dev_info_svc->software_rev_char_handle); |                                 &dev_info_svc->software_rev_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to add software revision char: %d", status); |         FURI_LOG_E(TAG, "Failed to add software revision char: %d", status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Update characteristics
 |     // Update characteristics
 | ||||||
| @ -97,7 +97,7 @@ void dev_info_svc_start() { | |||||||
|                                         strlen(dev_info_man_name), |                                         strlen(dev_info_man_name), | ||||||
|                                         (uint8_t*)dev_info_man_name); |                                         (uint8_t*)dev_info_man_name); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update manufacturer name char: %d", status); |         FURI_LOG_E(TAG, "Failed to update manufacturer name char: %d", status); | ||||||
|     } |     } | ||||||
|     status = aci_gatt_update_char_value(dev_info_svc->service_handle, |     status = aci_gatt_update_char_value(dev_info_svc->service_handle, | ||||||
|                                         dev_info_svc->serial_num_char_handle, |                                         dev_info_svc->serial_num_char_handle, | ||||||
| @ -105,7 +105,7 @@ void dev_info_svc_start() { | |||||||
|                                         strlen(dev_info_serial_num), |                                         strlen(dev_info_serial_num), | ||||||
|                                         (uint8_t*)dev_info_serial_num); |                                         (uint8_t*)dev_info_serial_num); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update serial number char: %d", status); |         FURI_LOG_E(TAG, "Failed to update serial number char: %d", status); | ||||||
|     } |     } | ||||||
|     status = aci_gatt_update_char_value(dev_info_svc->service_handle, |     status = aci_gatt_update_char_value(dev_info_svc->service_handle, | ||||||
|                                         dev_info_svc->firmware_rev_char_handle, |                                         dev_info_svc->firmware_rev_char_handle, | ||||||
| @ -113,7 +113,7 @@ void dev_info_svc_start() { | |||||||
|                                         strlen(dev_info_firmware_rev_num), |                                         strlen(dev_info_firmware_rev_num), | ||||||
|                                         (uint8_t*)dev_info_firmware_rev_num); |                                         (uint8_t*)dev_info_firmware_rev_num); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update firmware revision char: %d", status); |         FURI_LOG_E(TAG, "Failed to update firmware revision char: %d", status); | ||||||
|     } |     } | ||||||
|     status = aci_gatt_update_char_value(dev_info_svc->service_handle, |     status = aci_gatt_update_char_value(dev_info_svc->service_handle, | ||||||
|                                         dev_info_svc->software_rev_char_handle, |                                         dev_info_svc->software_rev_char_handle, | ||||||
| @ -121,7 +121,7 @@ void dev_info_svc_start() { | |||||||
|                                         strlen(dev_info_software_rev_num), |                                         strlen(dev_info_software_rev_num), | ||||||
|                                         (uint8_t*)dev_info_software_rev_num); |                                         (uint8_t*)dev_info_software_rev_num); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to update software revision char: %d", status); |         FURI_LOG_E(TAG, "Failed to update software revision char: %d", status); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -131,24 +131,24 @@ void dev_info_svc_stop() { | |||||||
|         // Delete service characteristics
 |         // Delete service characteristics
 | ||||||
|         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); |         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete manufacturer name char: %d", status); |             FURI_LOG_E(TAG, "Failed to delete manufacturer name char: %d", status); | ||||||
|         } |         } | ||||||
|         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle); |         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete serial number char: %d", status); |             FURI_LOG_E(TAG, "Failed to delete serial number char: %d", status); | ||||||
|         } |         } | ||||||
|         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle); |         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete firmware revision char: %d", status); |             FURI_LOG_E(TAG, "Failed to delete firmware revision char: %d", status); | ||||||
|         } |         } | ||||||
|         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle); |         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete software revision char: %d", status); |             FURI_LOG_E(TAG, "Failed to delete software revision char: %d", status); | ||||||
|         } |         } | ||||||
|         // Delete service
 |         // Delete service
 | ||||||
|         status = aci_gatt_del_service(dev_info_svc->service_handle); |         status = aci_gatt_del_service(dev_info_svc->service_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(DEV_INFO_SVC_TAG, "Failed to delete device info service: %d", status); |             FURI_LOG_E(TAG, "Failed to delete device info service: %d", status); | ||||||
|         } |         } | ||||||
|         free(dev_info_svc); |         free(dev_info_svc); | ||||||
|         dev_info_svc = NULL; |         dev_info_svc = NULL; | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| 
 | 
 | ||||||
| #define GAP_TAG "BLE" | #define TAG "BtGap" | ||||||
| 
 | 
 | ||||||
| #define FAST_ADV_TIMEOUT 30000 | #define FAST_ADV_TIMEOUT 30000 | ||||||
| #define INITIAL_ADV_TIMEOUT 60000 | #define INITIAL_ADV_TIMEOUT 60000 | ||||||
| @ -80,7 +80,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | |||||||
|             if (disconnection_complete_event->Connection_Handle == gap->gap_svc.connection_handle) { |             if (disconnection_complete_event->Connection_Handle == gap->gap_svc.connection_handle) { | ||||||
|                 gap->gap_svc.connection_handle = 0; |                 gap->gap_svc.connection_handle = 0; | ||||||
|                 gap->state = GapStateIdle; |                 gap->state = GapStateIdle; | ||||||
|                 FURI_LOG_I(GAP_TAG, "Disconnect from client. Reason: %d", disconnection_complete_event->Reason); |                 FURI_LOG_I(TAG, "Disconnect from client. Reason: %d", disconnection_complete_event->Reason); | ||||||
|             } |             } | ||||||
|             if(gap->enable_adv) { |             if(gap->enable_adv) { | ||||||
|                 // Restart advertising
 |                 // Restart advertising
 | ||||||
| @ -96,28 +96,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | |||||||
|             meta_evt = (evt_le_meta_event*) event_pckt->data; |             meta_evt = (evt_le_meta_event*) event_pckt->data; | ||||||
|             switch (meta_evt->subevent) { |             switch (meta_evt->subevent) { | ||||||
|                 case EVT_LE_CONN_UPDATE_COMPLETE: |                 case EVT_LE_CONN_UPDATE_COMPLETE: | ||||||
|                 FURI_LOG_D(GAP_TAG, "Connection update event"); |                 FURI_LOG_D(TAG, "Connection update event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|                 case EVT_LE_PHY_UPDATE_COMPLETE: |                 case EVT_LE_PHY_UPDATE_COMPLETE: | ||||||
|                 evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; |                 evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; | ||||||
|                 if(evt_le_phy_update_complete->Status) { |                 if(evt_le_phy_update_complete->Status) { | ||||||
|                     FURI_LOG_E(GAP_TAG, "Update PHY failed, status %d", evt_le_phy_update_complete->Status); |                     FURI_LOG_E(TAG, "Update PHY failed, status %d", evt_le_phy_update_complete->Status); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_I(GAP_TAG, "Update PHY succeed"); |                     FURI_LOG_I(TAG, "Update PHY succeed"); | ||||||
|                 } |                 } | ||||||
|                 ret = hci_le_read_phy(gap->gap_svc.connection_handle,&tx_phy,&rx_phy); |                 ret = hci_le_read_phy(gap->gap_svc.connection_handle,&tx_phy,&rx_phy); | ||||||
|                 if(ret) { |                 if(ret) { | ||||||
|                     FURI_LOG_E(GAP_TAG, "Read PHY failed, status: %d", ret); |                     FURI_LOG_E(TAG, "Read PHY failed, status: %d", ret); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_I(GAP_TAG, "PHY Params TX = %d, RX = %d ", tx_phy, rx_phy); |                     FURI_LOG_I(TAG, "PHY Params TX = %d, RX = %d ", tx_phy, rx_phy); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|                 case EVT_LE_CONN_COMPLETE: |                 case EVT_LE_CONN_COMPLETE: | ||||||
|                 furi_hal_power_insomnia_enter(); |                 furi_hal_power_insomnia_enter(); | ||||||
|                 hci_le_connection_complete_event_rp0* connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data; |                 hci_le_connection_complete_event_rp0* connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data; | ||||||
|                 FURI_LOG_I(GAP_TAG, "Connection complete for connection handle 0x%x", connection_complete_event->Connection_Handle); |                 FURI_LOG_I(TAG, "Connection complete for connection handle 0x%x", connection_complete_event->Connection_Handle); | ||||||
| 
 | 
 | ||||||
|                 // Stop advertising as connection completed
 |                 // Stop advertising as connection completed
 | ||||||
|                 osTimerStop(gap->advertise_timer); |                 osTimerStop(gap->advertise_timer); | ||||||
| @ -141,7 +141,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | |||||||
|                 aci_gap_pairing_complete_event_rp0 *pairing_complete; |                 aci_gap_pairing_complete_event_rp0 *pairing_complete; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: |             case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Limited discoverable event"); |                 FURI_LOG_I(TAG, "Limited discoverable event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_PASS_KEY_REQUEST: |             case EVT_BLUE_GAP_PASS_KEY_REQUEST: | ||||||
| @ -149,39 +149,39 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | |||||||
|                 // Generate random PIN code
 |                 // Generate random PIN code
 | ||||||
|                 uint32_t pin = rand() % 999999; |                 uint32_t pin = rand() % 999999; | ||||||
|                 aci_gap_pass_key_resp(gap->gap_svc.connection_handle, pin); |                 aci_gap_pass_key_resp(gap->gap_svc.connection_handle, pin); | ||||||
|                 FURI_LOG_I(GAP_TAG, "Pass key request event. Pin: %d", pin); |                 FURI_LOG_I(TAG, "Pass key request event. Pin: %d", pin); | ||||||
|                 BleEvent event = {.type = BleEventTypePinCodeShow, .data.pin_code = pin}; |                 BleEvent event = {.type = BleEventTypePinCodeShow, .data.pin_code = pin}; | ||||||
|                 gap->on_event_cb(event, gap->context); |                 gap->on_event_cb(event, gap->context); | ||||||
|             } |             } | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: |             case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Authorization request event"); |                 FURI_LOG_I(TAG, "Authorization request event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: |             case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Slave security initiated"); |                 FURI_LOG_I(TAG, "Slave security initiated"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_BOND_LOST: |             case EVT_BLUE_GAP_BOND_LOST: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Bond lost event. Start rebonding"); |                 FURI_LOG_I(TAG, "Bond lost event. Start rebonding"); | ||||||
|                 aci_gap_allow_rebond(gap->gap_svc.connection_handle); |                 aci_gap_allow_rebond(gap->gap_svc.connection_handle); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_DEVICE_FOUND: |             case EVT_BLUE_GAP_DEVICE_FOUND: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Device found event"); |                 FURI_LOG_I(TAG, "Device found event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: |             case EVT_BLUE_GAP_ADDR_NOT_RESOLVED: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Address not resolved event"); |                 FURI_LOG_I(TAG, "Address not resolved event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: |             case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Key press notification event"); |                 FURI_LOG_I(TAG, "Key press notification event"); | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: |             case EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Hex_value = %lx", |                 FURI_LOG_I(TAG, "Hex_value = %lx", | ||||||
|                             ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value); |                             ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value); | ||||||
|                 aci_gap_numeric_comparison_value_confirm_yesno(gap->gap_svc.connection_handle, 1); |                 aci_gap_numeric_comparison_value_confirm_yesno(gap->gap_svc.connection_handle, 1); | ||||||
|                 break; |                 break; | ||||||
| @ -189,17 +189,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | |||||||
|             case EVT_BLUE_GAP_PAIRING_CMPLT: |             case EVT_BLUE_GAP_PAIRING_CMPLT: | ||||||
|                 pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; |                 pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; | ||||||
|                 if (pairing_complete->Status) { |                 if (pairing_complete->Status) { | ||||||
|                     FURI_LOG_E(GAP_TAG, "Pairing failed with status: %d. Terminating connection", pairing_complete->Status); |                     FURI_LOG_E(TAG, "Pairing failed with status: %d. Terminating connection", pairing_complete->Status); | ||||||
|                     aci_gap_terminate(gap->gap_svc.connection_handle, 5); |                     aci_gap_terminate(gap->gap_svc.connection_handle, 5); | ||||||
|                 } else { |                 } else { | ||||||
|                     FURI_LOG_I(GAP_TAG, "Pairing complete"); |                     FURI_LOG_I(TAG, "Pairing complete"); | ||||||
|                     BleEvent event = {.type = BleEventTypeConnected}; |                     BleEvent event = {.type = BleEventTypeConnected}; | ||||||
|                     gap->on_event_cb(event, gap->context); |                     gap->on_event_cb(event, gap->context); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case EVT_BLUE_GAP_PROCEDURE_COMPLETE: |             case EVT_BLUE_GAP_PROCEDURE_COMPLETE: | ||||||
|                 FURI_LOG_I(GAP_TAG, "Procedure complete event"); |                 FURI_LOG_I(TAG, "Procedure complete event"); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             default: |             default: | ||||||
| @ -286,11 +286,11 @@ static void gap_init_svc(Gap* gap) { | |||||||
|     // Set GAP characteristics
 |     // Set GAP characteristics
 | ||||||
|     status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.dev_name_char_handle, 0, strlen(name), (uint8_t *) name); |     status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.dev_name_char_handle, 0, strlen(name), (uint8_t *) name); | ||||||
|     if (status) { |     if (status) { | ||||||
|         FURI_LOG_E(GAP_TAG, "Failed updating name characteristic: %d", status); |         FURI_LOG_E(TAG, "Failed updating name characteristic: %d", status); | ||||||
|     } |     } | ||||||
|     status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.appearance_char_handle, 0, 2, gap_appearence_char_uuid); |     status = aci_gatt_update_char_value(gap->gap_svc.gap_svc_handle, gap->gap_svc.appearance_char_handle, 0, 2, gap_appearence_char_uuid); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(GAP_TAG, "Failed updating appearence characteristic: %d", status); |         FURI_LOG_E(TAG, "Failed updating appearence characteristic: %d", status); | ||||||
|     } |     } | ||||||
|     // Set default PHY
 |     // Set default PHY
 | ||||||
|     hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED); |     hci_le_set_default_phy(ALL_PHYS_PREFERENCE, TX_2M_PREFERRED, RX_2M_PREFERRED); | ||||||
| @ -322,7 +322,7 @@ static void gap_advertise_start(GapState new_state) | |||||||
|         // Stop advertising
 |         // Stop advertising
 | ||||||
|         status = aci_gap_set_non_discoverable(); |         status = aci_gap_set_non_discoverable(); | ||||||
|         if (status) { |         if (status) { | ||||||
|             FURI_LOG_E(GAP_TAG, "Stop Advertising Failed, result: %d", status); |             FURI_LOG_E(TAG, "Stop Advertising Failed, result: %d", status); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     // Configure advertising
 |     // Configure advertising
 | ||||||
| @ -331,7 +331,7 @@ static void gap_advertise_start(GapState new_state) | |||||||
|                                         strlen(name), (uint8_t*)name, |                                         strlen(name), (uint8_t*)name, | ||||||
|                                         gap->gap_svc.adv_svc_uuid_len, gap->gap_svc.adv_svc_uuid, 0, 0); |                                         gap->gap_svc.adv_svc_uuid_len, gap->gap_svc.adv_svc_uuid, 0, 0); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(GAP_TAG, "Set discoverable err: %d", status); |         FURI_LOG_E(TAG, "Set discoverable err: %d", status); | ||||||
|     } |     } | ||||||
|     gap->state = new_state; |     gap->state = new_state; | ||||||
|     BleEvent event = {.type = BleEventTypeStartAdvertising}; |     BleEvent event = {.type = BleEventTypeStartAdvertising}; | ||||||
| @ -355,14 +355,14 @@ static void gap_advertise_stop() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gap_start_advertising() { | void gap_start_advertising() { | ||||||
|     FURI_LOG_I(GAP_TAG, "Start advertising"); |     FURI_LOG_I(TAG, "Start advertising"); | ||||||
|     gap->enable_adv = true; |     gap->enable_adv = true; | ||||||
|     GapCommand command = GapCommandAdvFast; |     GapCommand command = GapCommandAdvFast; | ||||||
|     furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK); |     furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void gap_stop_advertising() { | void gap_stop_advertising() { | ||||||
|     FURI_LOG_I(GAP_TAG, "Stop advertising"); |     FURI_LOG_I(TAG, "Stop advertising"); | ||||||
|     gap->enable_adv = false; |     gap->enable_adv = false; | ||||||
|     GapCommand command = GapCommandAdvStop; |     GapCommand command = GapCommandAdvStop; | ||||||
|     furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK); |     furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK); | ||||||
| @ -374,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool gap_init(BleEventCallback on_event_cb, void* context) { | bool gap_init(BleEventCallback on_event_cb, void* context) { | ||||||
|     if (ble_glue_get_status() != BleGlueStatusStarted) { |     if (!ble_glue_is_radio_stack_ready()) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -393,7 +393,7 @@ bool gap_init(BleEventCallback on_event_cb, void* context) { | |||||||
|     gap->enable_adv = true; |     gap->enable_adv = true; | ||||||
| 
 | 
 | ||||||
|     // Thread configuration
 |     // Thread configuration
 | ||||||
|     gap->thread_attr.name = "BLE advertising"; |     gap->thread_attr.name = "BleGapWorker"; | ||||||
|     gap->thread_attr.stack_size = 1024; |     gap->thread_attr.stack_size = 1024; | ||||||
|     gap->thread_id = osThreadNew(gap_app, NULL, &gap->thread_attr); |     gap->thread_id = osThreadNew(gap_app, NULL, &gap->thread_attr); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,22 +4,27 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #define SERIAL_SERVICE_TAG "serial service" | #define TAG "BtSerialSvc" | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint16_t svc_handle; |     uint16_t svc_handle; | ||||||
|     uint16_t rx_char_handle; |     uint16_t rx_char_handle; | ||||||
|     uint16_t tx_char_handle; |     uint16_t tx_char_handle; | ||||||
|  |     uint16_t flow_ctrl_char_handle; | ||||||
|  |     osMutexId_t buff_size_mtx; | ||||||
|  |     uint32_t buff_size; | ||||||
|  |     uint16_t bytes_ready_to_receive; | ||||||
|     SerialSvcDataReceivedCallback on_received_cb; |     SerialSvcDataReceivedCallback on_received_cb; | ||||||
|     SerialSvcDataSentCallback on_sent_cb; |     SerialSvcDataSentCallback on_sent_cb; | ||||||
|     void* context; |     void* context; | ||||||
| } SerialSvc; | } SerialSvc; | ||||||
| 
 | 
 | ||||||
| static SerialSvc* serial_svc; | static SerialSvc* serial_svc = NULL; | ||||||
| 
 | 
 | ||||||
| static const uint8_t service_uuid[] = {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f}; | static const uint8_t service_uuid[] = {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f}; | ||||||
| static const uint8_t char_rx_uuid[] = {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; |  | ||||||
| static const uint8_t char_tx_uuid[] = {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; | static const uint8_t char_tx_uuid[] = {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; | ||||||
|  | static const uint8_t char_rx_uuid[] = {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; | ||||||
|  | static const uint8_t flow_ctrl_uuid[] = {0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; | ||||||
| 
 | 
 | ||||||
| static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { | static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { | ||||||
|     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; |     SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; | ||||||
| @ -32,16 +37,26 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void *event) { | |||||||
|             if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 2) { |             if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 2) { | ||||||
|                 // Descriptor handle
 |                 // Descriptor handle
 | ||||||
|                 ret = SVCCTL_EvtAckFlowEnable; |                 ret = SVCCTL_EvtAckFlowEnable; | ||||||
|                 FURI_LOG_D(SERIAL_SERVICE_TAG, "RX descriptor event"); |                 FURI_LOG_D(TAG, "RX descriptor event"); | ||||||
|             } else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) { |             } else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) { | ||||||
|                 FURI_LOG_D(SERIAL_SERVICE_TAG, "Received %d bytes", attribute_modified->Attr_Data_Length); |                 FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length); | ||||||
|                 if(serial_svc->on_received_cb) { |                 if(serial_svc->on_received_cb) { | ||||||
|                     serial_svc->on_received_cb(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length, serial_svc->context); |                     furi_check(osMutexAcquire(serial_svc->buff_size_mtx, osWaitForever) == osOK); | ||||||
|  |                     if(attribute_modified->Attr_Data_Length > serial_svc->bytes_ready_to_receive) { | ||||||
|  |                         FURI_LOG_W( | ||||||
|  |                             TAG, "Received %d, while was ready to receive %d bytes. Can lead to buffer overflow!", | ||||||
|  |                             attribute_modified->Attr_Data_Length, serial_svc->bytes_ready_to_receive); | ||||||
|  |                     } | ||||||
|  |                     serial_svc->bytes_ready_to_receive -= MIN(serial_svc->bytes_ready_to_receive, attribute_modified->Attr_Data_Length); | ||||||
|  |                     uint32_t buff_free_size = | ||||||
|  |                         serial_svc->on_received_cb(attribute_modified->Attr_Data, attribute_modified->Attr_Data_Length, serial_svc->context); | ||||||
|  |                     FURI_LOG_D(TAG, "Available buff size: %d", buff_free_size); | ||||||
|  |                     furi_check(osMutexRelease(serial_svc->buff_size_mtx) == osOK); | ||||||
|                 } |                 } | ||||||
|                 ret = SVCCTL_EvtAckFlowEnable; |                 ret = SVCCTL_EvtAckFlowEnable; | ||||||
|             } |             } | ||||||
|         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { |         } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { | ||||||
|             FURI_LOG_D(SERIAL_SERVICE_TAG, "Ack received", blecore_evt->ecode); |             FURI_LOG_D(TAG, "Ack received", blecore_evt->ecode); | ||||||
|             if(serial_svc->on_sent_cb) { |             if(serial_svc->on_sent_cb) { | ||||||
|                 serial_svc->on_sent_cb(serial_svc->context); |                 serial_svc->on_sent_cb(serial_svc->context); | ||||||
|             } |             } | ||||||
| @ -58,9 +73,9 @@ void serial_svc_start() { | |||||||
|     SVCCTL_RegisterSvcHandler(serial_svc_event_handler); |     SVCCTL_RegisterSvcHandler(serial_svc_event_handler); | ||||||
| 
 | 
 | ||||||
|     // Add service
 |     // Add service
 | ||||||
|     status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 6, &serial_svc->svc_handle); |     status = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)service_uuid, PRIMARY_SERVICE, 10, &serial_svc->svc_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add Serial service: %d", status); |         FURI_LOG_E(TAG, "Failed to add Serial service: %d", status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Add RX characteristics
 |     // Add RX characteristics
 | ||||||
| @ -73,7 +88,7 @@ void serial_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_VARIABLE, |                                 CHAR_VALUE_LEN_VARIABLE, | ||||||
|                                 &serial_svc->rx_char_handle); |                                 &serial_svc->rx_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add RX characteristic: %d", status); |         FURI_LOG_E(TAG, "Failed to add RX characteristic: %d", status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Add TX characteristic
 |     // Add TX characteristic
 | ||||||
| @ -86,14 +101,47 @@ void serial_svc_start() { | |||||||
|                                 CHAR_VALUE_LEN_VARIABLE, |                                 CHAR_VALUE_LEN_VARIABLE, | ||||||
|                                 &serial_svc->tx_char_handle); |                                 &serial_svc->tx_char_handle); | ||||||
|     if(status) { |     if(status) { | ||||||
|         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to add TX characteristic: %d", status); |         FURI_LOG_E(TAG, "Failed to add TX characteristic: %d", status); | ||||||
|     } |     } | ||||||
|  |     // Add Flow Control characteristic
 | ||||||
|  |     status = aci_gatt_add_char(serial_svc->svc_handle, UUID_TYPE_128, (const Char_UUID_t*)flow_ctrl_uuid, | ||||||
|  |                                 sizeof(uint32_t), | ||||||
|  |                                 CHAR_PROP_READ | CHAR_PROP_NOTIFY, | ||||||
|  |                                 ATTR_PERMISSION_AUTHEN_READ, | ||||||
|  |                                 GATT_DONT_NOTIFY_EVENTS, | ||||||
|  |                                 10, | ||||||
|  |                                 CHAR_VALUE_LEN_CONSTANT, | ||||||
|  |                                 &serial_svc->flow_ctrl_char_handle); | ||||||
|  |     if(status) { | ||||||
|  |         FURI_LOG_E(TAG, "Failed to add Flow Control characteristic: %d", status); | ||||||
|  |     } | ||||||
|  |     // Allocate buffer size mutex
 | ||||||
|  |     serial_svc->buff_size_mtx = osMutexNew(NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void serial_svc_set_callbacks(SerialSvcDataReceivedCallback on_received_cb, SerialSvcDataSentCallback on_sent_cb, void* context) { | void serial_svc_set_callbacks(uint16_t buff_size, SerialSvcDataReceivedCallback on_received_cb, SerialSvcDataSentCallback on_sent_cb, void* context) { | ||||||
|  |     furi_assert(serial_svc); | ||||||
|     serial_svc->on_received_cb = on_received_cb; |     serial_svc->on_received_cb = on_received_cb; | ||||||
|     serial_svc->on_sent_cb = on_sent_cb; |     serial_svc->on_sent_cb = on_sent_cb; | ||||||
|     serial_svc->context = context; |     serial_svc->context = context; | ||||||
|  |     serial_svc->buff_size = buff_size; | ||||||
|  |     serial_svc->bytes_ready_to_receive = buff_size; | ||||||
|  |     uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); | ||||||
|  |     aci_gatt_update_char_value(serial_svc->svc_handle, serial_svc->flow_ctrl_char_handle, 0, sizeof(uint32_t), (uint8_t*)&buff_size_reversed); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void serial_svc_notify_buffer_is_empty() { | ||||||
|  |     furi_assert(serial_svc); | ||||||
|  |     furi_assert(serial_svc->buff_size_mtx); | ||||||
|  | 
 | ||||||
|  |     furi_check(osMutexAcquire(serial_svc->buff_size_mtx, osWaitForever) == osOK); | ||||||
|  |     if(serial_svc->bytes_ready_to_receive == 0) { | ||||||
|  |         FURI_LOG_D(TAG, "Buffer is empty. Notifying client"); | ||||||
|  |         serial_svc->bytes_ready_to_receive = serial_svc->buff_size; | ||||||
|  |         uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); | ||||||
|  |         aci_gatt_update_char_value(serial_svc->svc_handle, serial_svc->flow_ctrl_char_handle, 0, sizeof(uint32_t), (uint8_t*)&buff_size_reversed); | ||||||
|  |     } | ||||||
|  |     furi_check(osMutexRelease(serial_svc->buff_size_mtx) == osOK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void serial_svc_stop() { | void serial_svc_stop() { | ||||||
| @ -102,17 +150,23 @@ void serial_svc_stop() { | |||||||
|         // Delete characteristics
 |         // Delete characteristics
 | ||||||
|         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle); |         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete TX characteristic: %d", status); |             FURI_LOG_E(TAG, "Failed to delete TX characteristic: %d", status); | ||||||
|         } |         } | ||||||
|         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle); |         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete RX characteristic: %d", status); |             FURI_LOG_E(TAG, "Failed to delete RX characteristic: %d", status); | ||||||
|  |         } | ||||||
|  |         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->flow_ctrl_char_handle); | ||||||
|  |         if(status) { | ||||||
|  |             FURI_LOG_E(TAG, "Failed to delete Flow Control characteristic: %d", status); | ||||||
|         } |         } | ||||||
|         // Delete service
 |         // Delete service
 | ||||||
|         status = aci_gatt_del_service(serial_svc->svc_handle); |         status = aci_gatt_del_service(serial_svc->svc_handle); | ||||||
|         if(status) { |         if(status) { | ||||||
|             FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed to delete Serial service: %d", status); |             FURI_LOG_E(TAG, "Failed to delete Serial service: %d", status); | ||||||
|         } |         } | ||||||
|  |         // Delete buffer size mutex
 | ||||||
|  |         osMutexDelete(serial_svc->buff_size_mtx); | ||||||
|         free(serial_svc); |         free(serial_svc); | ||||||
|         serial_svc = NULL; |         serial_svc = NULL; | ||||||
|     } |     } | ||||||
| @ -122,14 +176,13 @@ bool serial_svc_update_tx(uint8_t* data, uint8_t data_len) { | |||||||
|     if(data_len > SERIAL_SVC_DATA_LEN_MAX) { |     if(data_len > SERIAL_SVC_DATA_LEN_MAX) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     FURI_LOG_D(SERIAL_SERVICE_TAG, "Updating char %d len", data_len); |  | ||||||
|     tBleStatus result = aci_gatt_update_char_value(serial_svc->svc_handle, |     tBleStatus result = aci_gatt_update_char_value(serial_svc->svc_handle, | ||||||
|                                         serial_svc->tx_char_handle, |                                         serial_svc->tx_char_handle, | ||||||
|                                         0, |                                         0, | ||||||
|                                         data_len, |                                         data_len, | ||||||
|                                         data); |                                         data); | ||||||
|     if(result) { |     if(result) { | ||||||
|         FURI_LOG_E(SERIAL_SERVICE_TAG, "Failed updating TX characteristic: %d", result); |         FURI_LOG_E(TAG, "Failed updating TX characteristic: %d", result); | ||||||
|     } |     } | ||||||
|     return result != BLE_STATUS_SUCCESS; |     return result != BLE_STATUS_SUCCESS; | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,12 +9,14 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| typedef void(*SerialSvcDataReceivedCallback)(uint8_t* buff, uint16_t size, void* context); | typedef uint16_t(*SerialSvcDataReceivedCallback)(uint8_t* buff, uint16_t size, void* context); | ||||||
| typedef void(*SerialSvcDataSentCallback)(void* context); | typedef void(*SerialSvcDataSentCallback)(void* context); | ||||||
| 
 | 
 | ||||||
| void serial_svc_start(); | void serial_svc_start(); | ||||||
| 
 | 
 | ||||||
| void serial_svc_set_callbacks(SerialSvcDataReceivedCallback on_received_cb, SerialSvcDataSentCallback on_sent_cb, void* context); | void serial_svc_set_callbacks(uint16_t buff_size, SerialSvcDataReceivedCallback on_received_cb, SerialSvcDataSentCallback on_sent_cb, void* context); | ||||||
|  | 
 | ||||||
|  | void serial_svc_notify_buffer_is_empty(); | ||||||
| 
 | 
 | ||||||
| void serial_svc_stop(); | void serial_svc_stop(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
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