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 | ||||
| bootloader_flash: | ||||
| ifeq ($(FORCE), '1') | ||||
| ifeq ($(FORCE), 1) | ||||
| 	rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true | ||||
| endif | ||||
| 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash | ||||
| 
 | ||||
| .PHONY: firmware_flash | ||||
| firmware_flash: | ||||
| ifeq ($(FORCE), '1') | ||||
| ifeq ($(FORCE), 1) | ||||
| 	rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true | ||||
| endif | ||||
| 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash | ||||
|  | ||||
| @ -65,55 +65,55 @@ extern int32_t power_settings_app(void* p); | ||||
| const FlipperApplication FLIPPER_SERVICES[] = { | ||||
| /* Services */ | ||||
| #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 | ||||
| 
 | ||||
| #ifdef SRV_BT | ||||
|     {.app = bt_srv, .name = "BT", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = bt_srv, .name = "BtSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_CLI | ||||
|     {.app = cli_srv, .name = "Cli", .stack_size = 4096, .icon = NULL}, | ||||
|     {.app = cli_srv, .name = "CliSrv", .stack_size = 4096, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_DIALOGS | ||||
|     {.app = dialogs_srv, .name = "Dialogs", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = dialogs_srv, .name = "DialogsSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_DOLPHIN | ||||
|     {.app = dolphin_srv, .name = "Dolphin", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = dolphin_srv, .name = "DolphinSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_DESKTOP | ||||
|     {.app = desktop_srv, .name = "Desktop", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = desktop_srv, .name = "DesktopSrv", .stack_size = 2048, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_GUI | ||||
|     {.app = gui_srv, .name = "Gui", .stack_size = 8192, .icon = NULL}, | ||||
|     {.app = gui_srv, .name = "GuiSrv", .stack_size = 2048, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_INPUT | ||||
|     {.app = input_srv, .name = "Input", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = input_srv, .name = "InputSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_LOADER | ||||
|     {.app = loader_srv, .name = "Loader", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = loader_srv, .name = "LoaderSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_NOTIFICATION | ||||
|     {.app = notification_srv, .name = "Notification", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = notification_srv, .name = "NotificationSrv", .stack_size = 1536, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_POWER | ||||
|     {.app = power_srv, .name = "Power", .stack_size = 1024, .icon = NULL}, | ||||
|     {.app = power_srv, .name = "PowerSrv", .stack_size = 1024, .icon = NULL}, | ||||
| #endif | ||||
| 
 | ||||
| #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 | ||||
| 
 | ||||
| #ifdef SRV_STORAGE | ||||
|     {.app = storage_srv, .name = "Storage", .stack_size = 4096, .icon = NULL}, | ||||
|     {.app = storage_srv, .name = "StorageSrv", .stack_size = 3072, .icon = NULL}, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -231,6 +231,10 @@ endif | ||||
| SRV_RPC ?= 0 | ||||
| ifeq ($(SRV_RPC), 1) | ||||
| CFLAGS		+= -DSRV_RPC | ||||
| ifeq ($(SRV_RPC_DEBUG), 1) | ||||
| CFLAGS		+= -DSRV_RPC_DEBUG | ||||
| endif | ||||
| SRV_CLI		= 1 | ||||
| endif | ||||
| 
 | ||||
| SRV_LOADER ?= 0 | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| #include "archive_files.h" | ||||
| #include "archive_browser.h" | ||||
| 
 | ||||
| #define TAG "Archive" | ||||
| 
 | ||||
| bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { | ||||
|     furi_assert(file_info); | ||||
|     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); | ||||
| 
 | ||||
|     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))) { | ||||
|         FURI_LOG_E("Archive", "Append write error"); | ||||
|         FURI_LOG_E(TAG, "Append write error"); | ||||
|     } | ||||
| 
 | ||||
|     file_worker_close(file_worker); | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| #include "battery_service.h" | ||||
| #include "bt_keys_storage.h" | ||||
| 
 | ||||
| #define BT_SERVICE_TAG "BT" | ||||
| #define TAG "BtSrv" | ||||
| 
 | ||||
| static void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -81,14 +81,15 @@ Bt* bt_alloc() { | ||||
| } | ||||
| 
 | ||||
| // 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); | ||||
|     Bt* bt = context; | ||||
| 
 | ||||
|     size_t bytes_processed = rpc_session_feed(bt->rpc_session, data, size, 1000); | ||||
|     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
 | ||||
| @ -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
 | ||||
| static void bt_on_gap_event_callback(BleEvent event, void* context) { | ||||
|     furi_assert(context); | ||||
| @ -129,12 +135,13 @@ static void bt_on_gap_event_callback(BleEvent event, void* context) { | ||||
|         BtMessage message = {.type = BtMessageTypeUpdateStatusbar}; | ||||
|         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
|         // 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); | ||||
|         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); | ||||
|         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
 | ||||
|         PowerInfo 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; | ||||
|         furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
|     } 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) { | ||||
|             rpc_session_close(bt->rpc_session); | ||||
|             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) { | ||||
|     furi_assert(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}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| @ -188,20 +195,20 @@ int32_t bt_srv() { | ||||
| 
 | ||||
|     // Read keys
 | ||||
|     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
 | ||||
|     if(!furi_hal_bt_start_core2()) { | ||||
|         FURI_LOG_E(BT_SERVICE_TAG, "Core2 startup failed"); | ||||
|         FURI_LOG_E(TAG, "Core2 startup failed"); | ||||
|     } else { | ||||
|         view_port_enabled_set(bt->statusbar_view_port, true); | ||||
|         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) { | ||||
|                 furi_hal_bt_start_advertising(); | ||||
|             } | ||||
|         } 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); | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| #include <furi.h> | ||||
| #include <file-worker.h> | ||||
| 
 | ||||
| #define BT_SETTINGS_TAG "bt settings" | ||||
| #define TAG "BtSettings" | ||||
| #define BT_SETTINGS_PATH "/int/bt.settings" | ||||
| 
 | ||||
| bool bt_settings_load(BtSettings* bt_settings) { | ||||
| @ -10,7 +10,7 @@ bool bt_settings_load(BtSettings* bt_settings) { | ||||
|     bool file_loaded = false; | ||||
|     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); | ||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||
|         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); | ||||
| 
 | ||||
|     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) { | ||||
|             FURI_LOG_E(BT_SETTINGS_TAG, "Settings version mismatch"); | ||||
|             FURI_LOG_E(TAG, "Settings version mismatch"); | ||||
|         } else { | ||||
|             osKernelLock(); | ||||
|             *bt_settings = settings; | ||||
|             osKernelUnlock(); | ||||
|         } | ||||
|     } else { | ||||
|         FURI_LOG_E(BT_SETTINGS_TAG, "Settings load failed"); | ||||
|         FURI_LOG_E(TAG, "Settings load failed"); | ||||
|     } | ||||
|     return file_loaded; | ||||
| } | ||||
| @ -41,7 +41,7 @@ bool bt_settings_save(BtSettings* bt_settings) { | ||||
|     FileWorker* file_worker = file_worker_alloc(true); | ||||
|     if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { | ||||
|         if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) { | ||||
|             FURI_LOG_I(BT_SETTINGS_TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); | ||||
|             FURI_LOG_I(TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); | ||||
|             result = true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -6,6 +6,9 @@ | ||||
| #include <furi-hal-usb-hid.h> | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| #define TAG "BadUsb" | ||||
| #define WORKER_TAG TAG "Worker" | ||||
| 
 | ||||
| typedef enum { | ||||
|     EventTypeInput, | ||||
|     EventTypeWorkerState, | ||||
| @ -191,7 +194,7 @@ static bool ducky_parse_line(string_t line, BadUsbParams* app) { | ||||
| 
 | ||||
| static void badusb_worker(void* 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")); | ||||
|     BadUsbEvent evt; | ||||
|     string_t line; | ||||
| @ -203,7 +206,7 @@ static void badusb_worker(void* context) { | ||||
|         uint32_t flags = | ||||
|             osThreadFlagsWait(WorkerCmdStart | WorkerCmdStop, osFlagsWaitAny, osWaitForever); | ||||
|         if(flags & WorkerCmdStart) { | ||||
|             FURI_LOG_I("BadUSB worker", "Start"); | ||||
|             FURI_LOG_I(WORKER_TAG, "Start"); | ||||
|             do { | ||||
|                 ret = storage_file_read(script_file, buffer, 16); | ||||
|                 for(uint16_t i = 0; i < ret; i++) { | ||||
| @ -211,7 +214,7 @@ static void badusb_worker(void* context) { | ||||
|                         line_cnt++; | ||||
|                         if(ducky_parse_line(line, app) == false) { | ||||
|                             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.worker.state = WorkerStateScriptError; | ||||
|                             evt.worker.line = line_cnt; | ||||
| @ -231,7 +234,7 @@ static void badusb_worker(void* context) { | ||||
|             } while(ret > 0); | ||||
|         } | ||||
|     } else { | ||||
|         FURI_LOG_E("BadUSB worker", "Script file open error"); | ||||
|         FURI_LOG_E(WORKER_TAG, "Script file open error"); | ||||
|         evt.type = EventTypeWorkerState; | ||||
|         evt.worker.state = WorkerStateNoFile; | ||||
|         osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); | ||||
| @ -243,7 +246,7 @@ static void badusb_worker(void* context) { | ||||
|     storage_file_close(script_file); | ||||
|     storage_file_free(script_file); | ||||
| 
 | ||||
|     FURI_LOG_I("BadUSB worker", "End"); | ||||
|     FURI_LOG_I(WORKER_TAG, "End"); | ||||
|     evt.type = EventTypeWorkerState; | ||||
|     evt.worker.state = WorkerStateDone; | ||||
|     osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever); | ||||
| @ -324,7 +327,7 @@ int32_t bad_usb_app(void* p) { | ||||
|                     } | ||||
|                 } | ||||
|             } 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) { | ||||
|                     worker_running = false; | ||||
|                     if(app_state == AppStateExit) | ||||
|  | ||||
| @ -14,6 +14,8 @@ | ||||
| 
 | ||||
| #include "view_display_test.h" | ||||
| 
 | ||||
| #define TAG "DisplayTest" | ||||
| 
 | ||||
| typedef struct { | ||||
|     Gui* gui; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
| @ -77,7 +79,7 @@ static uint32_t display_test_exit_callback(void* context) { | ||||
| 
 | ||||
| static void display_test_reload_config(DisplayTest* instance) { | ||||
|     FURI_LOG_I( | ||||
|         "DisplayTest", | ||||
|         TAG, | ||||
|         "contrast: %d, regulation_ratio: %d, bias: %d", | ||||
|         instance->config_contrast, | ||||
|         instance->config_regulation_ratio, | ||||
|  | ||||
| @ -2,6 +2,8 @@ | ||||
| #include <gui/gui.h> | ||||
| #include <input/input.h> | ||||
| 
 | ||||
| #define TAG "KeypadTest" | ||||
| 
 | ||||
| typedef struct { | ||||
|     bool press[5]; | ||||
|     uint16_t up; | ||||
| @ -80,7 +82,7 @@ int32_t keypad_test_app(void* p) { | ||||
| 
 | ||||
|     ValueMutex state_mutex; | ||||
|     if(!init_mutex(&state_mutex, &_state, sizeof(KeypadTestState))) { | ||||
|         FURI_LOG_E("KeypadTest", "cannot create mutex"); | ||||
|         FURI_LOG_E(TAG, "cannot create mutex"); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
| @ -101,7 +103,7 @@ int32_t keypad_test_app(void* p) { | ||||
|         if(event_status == osOK) { | ||||
|             if(event.type == EventTypeInput) { | ||||
|                 FURI_LOG_I( | ||||
|                     "KeypadTest", | ||||
|                     TAG, | ||||
|                     "key: %s type: %s", | ||||
|                     input_get_key_name(event.input.key), | ||||
|                     input_get_type_name(event.input.type)); | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| #include "desktop_animation.h" | ||||
| 
 | ||||
| #define TAG "DesktopAnimation" | ||||
| 
 | ||||
| static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | ||||
| 
 | ||||
| const Icon* desktop_get_icon() { | ||||
| @ -12,10 +14,10 @@ const Icon* desktop_get_icon() { | ||||
|     DolphinStats stats = dolphin_stats(dolphin); | ||||
|     float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp())); | ||||
| 
 | ||||
|     FURI_LOG_I("desktop-animation", "background change"); | ||||
|     FURI_LOG_I("desktop-animation", "icounter: %d", stats.icounter); | ||||
|     FURI_LOG_I("desktop-animation", "butthurt: %d", stats.butthurt); | ||||
|     FURI_LOG_I("desktop-animation", "time since deeed: %.0f", timediff); | ||||
|     FURI_LOG_I(TAG, "background change"); | ||||
|     FURI_LOG_I(TAG, "icounter: %d", stats.icounter); | ||||
|     FURI_LOG_I(TAG, "butthurt: %d", stats.butthurt); | ||||
|     FURI_LOG_I(TAG, "time since deeed: %.0f", timediff); | ||||
| #endif | ||||
| 
 | ||||
|     if((random() % 100) > 50) { // temp rnd selection
 | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| #include "view-holder.h" | ||||
| #include <gui/view_i.h> | ||||
| 
 | ||||
| #define TAG "ViewHolder" | ||||
| 
 | ||||
| struct ViewHolder { | ||||
|     View* view; | ||||
|     ViewPort* view_port; | ||||
| @ -125,7 +127,7 @@ static void view_holder_input_callback(InputEvent* event, void* context) { | ||||
|         view_holder->ongoing_input &= ~key_bit; | ||||
|     } else if(!(view_holder->ongoing_input & key_bit)) { | ||||
|         FURI_LOG_W( | ||||
|             "ViewHolder", | ||||
|             TAG, | ||||
|             "non-complementary input, discarding key: %s, type: %s", | ||||
|             input_get_key_name(event->key), | ||||
|             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()); | ||||
| 
 | ||||
|     if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { | ||||
|         FURI_LOG_I("dolphin-state", "Increasing butthurt"); | ||||
|         FURI_LOG_I("DolphinState", "Increasing butthurt"); | ||||
|         dolphin_state_butthurted(state); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| #include <math.h> | ||||
| #include <toolbox/saved_struct.h> | ||||
| 
 | ||||
| #define DOLPHIN_STATE_TAG "DolphinState" | ||||
| #define TAG "DolphinState" | ||||
| #define DOLPHIN_STATE_PATH "/int/dolphin.state" | ||||
| #define DOLPHIN_STATE_HEADER_MAGIC 0xD0 | ||||
| #define DOLPHIN_STATE_HEADER_VERSION 0x01 | ||||
| @ -48,10 +48,10 @@ bool dolphin_state_save(DolphinState* dolphin_state) { | ||||
|         DOLPHIN_STATE_HEADER_VERSION); | ||||
| 
 | ||||
|     if(result) { | ||||
|         FURI_LOG_I(DOLPHIN_STATE_TAG, "State saved"); | ||||
|         FURI_LOG_I(TAG, "State saved"); | ||||
|         dolphin_state->dirty = false; | ||||
|     } else { | ||||
|         FURI_LOG_E(DOLPHIN_STATE_TAG, "Failed to save state"); | ||||
|         FURI_LOG_E(TAG, "Failed to save state"); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| @ -66,7 +66,7 @@ bool dolphin_state_load(DolphinState* dolphin_state) { | ||||
|         DOLPHIN_STATE_HEADER_VERSION); | ||||
| 
 | ||||
|     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)); | ||||
|         dolphin_state->dirty = true; | ||||
|     } | ||||
|  | ||||
| @ -8,11 +8,12 @@ | ||||
| #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) | ||||
| 
 | ||||
| typedef enum { | ||||
|     WorkerEvtStop = (1 << 0), | ||||
|     WorkerEvtRxDone = (1 << 1), | ||||
|     WorkerEvtReserved = (1 << 0), // Reserved for StreamBuffer internal event
 | ||||
|     WorkerEvtStop = (1 << 1), | ||||
|     WorkerEvtRxDone = (1 << 2), | ||||
| 
 | ||||
|     WorkerEvtTxStop = (1 << 2), | ||||
|     WorkerEvtCdcRx = (1 << 3), | ||||
|     WorkerEvtTxStop = (1 << 3), | ||||
|     WorkerEvtCdcRx = (1 << 4), | ||||
| } WorkerEvtFlags; | ||||
| 
 | ||||
| #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->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_context(usb_uart->tx_thread, NULL); | ||||
|     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->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_context(usb_uart->thread, cfg); | ||||
|         furi_thread_set_callback(usb_uart->thread, usb_uart_worker); | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| #include "gui_i.h" | ||||
| 
 | ||||
| #define TAG "GuiSrv" | ||||
| 
 | ||||
| ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { | ||||
|     // Iterating backward
 | ||||
|     ViewPortArray_it_t it; | ||||
| @ -190,7 +192,7 @@ void gui_input(Gui* gui, InputEvent* input_event) { | ||||
|         gui->ongoing_input |= key_bit; | ||||
|     } else if(!(gui->ongoing_input & key_bit)) { | ||||
|         FURI_LOG_D( | ||||
|             "Gui", | ||||
|             TAG, | ||||
|             "non-complementary input, discarding key: %s type: %s, sequence: %p", | ||||
|             input_get_key_name(input_event->key), | ||||
|             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); | ||||
|     } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) { | ||||
|         FURI_LOG_D( | ||||
|             "Gui", | ||||
|             TAG, | ||||
|             "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port", | ||||
|             gui->ongoing_input_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); | ||||
|     } else { | ||||
|         FURI_LOG_D( | ||||
|             "Gui", | ||||
|             TAG, | ||||
|             "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p", | ||||
|             gui->ongoing_input_view_port, | ||||
|             view_port, | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| #include "view_dispatcher_i.h" | ||||
| 
 | ||||
| #define TAG "ViewDispatcher" | ||||
| 
 | ||||
| ViewDispatcher* view_dispatcher_alloc() { | ||||
|     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; | ||||
|     } else if(!(view_dispatcher->ongoing_input & key_bit)) { | ||||
|         FURI_LOG_D( | ||||
|             "ViewDispatcher", | ||||
|             TAG, | ||||
|             "non-complementary input, discarding key: %s, type: %s, sequence: %p", | ||||
|             input_get_key_name(event->key), | ||||
|             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) { | ||||
|         FURI_LOG_D( | ||||
|             "ViewDispatcher", | ||||
|             TAG, | ||||
|             "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->current_view, | ||||
|  | ||||
| @ -11,6 +11,8 @@ | ||||
| #include <furi-hal-irda.h> | ||||
| #include <file-worker-cpp.h> | ||||
| 
 | ||||
| #define TAG "IrdaFileParser" | ||||
| 
 | ||||
| bool IrdaAppFileParser::open_irda_file_read(const char* name) { | ||||
|     std::string full_filename; | ||||
|     if(name[0] != '/') | ||||
| @ -154,11 +156,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     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); | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", | ||||
|             "Unknown protocol(\'%.*s...\'): \'%s\'", | ||||
|             end_of_str, | ||||
|             str.c_str(), | ||||
|             protocol_name); | ||||
|             TAG, "Unknown protocol(\'%.*s...\'): \'%s\'", end_of_str, str.c_str(), protocol_name); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
| @ -167,7 +165,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     if(address != (address & address_mask)) { | ||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", | ||||
|             TAG, | ||||
|             "Signal(\'%.*s...\'): address is too long (mask for this protocol is 0x%08X): 0x%X", | ||||
|             end_of_str, | ||||
|             str.c_str(), | ||||
| @ -181,7 +179,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     if(command != (command & command_mask)) { | ||||
|         size_t end_of_str = MIN(str.find_last_not_of(" \t\r\n") + 1, (size_t)30); | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", | ||||
|             TAG, | ||||
|             "Signal(\'%.*s...\'): command is too long (mask for this protocol is 0x%08X): 0x%X", | ||||
|             end_of_str, | ||||
|             str.c_str(), | ||||
| @ -256,7 +254,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     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); | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", | ||||
|             TAG, | ||||
|             "RAW signal(\'%.*s...\'): frequency is out of bounds (%ld-%ld): %ld", | ||||
|             end_of_str, | ||||
|             string.c_str(), | ||||
| @ -269,7 +267,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     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); | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", | ||||
|             TAG, | ||||
|             "RAW signal(\'%.*s...\'): duty cycle is out of bounds (0-100): %ld", | ||||
|             end_of_str, | ||||
|             string.c_str(), | ||||
| @ -283,8 +281,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|     if(last_valid_ch != std::string_view::npos) { | ||||
|         str.remove_suffix(str.size() - last_valid_ch - 1); | ||||
|     } else { | ||||
|         FURI_LOG_E( | ||||
|             "IrdaFileParser", "RAW signal(\'%.*s\'): no timings", header_len, string.c_str()); | ||||
|         FURI_LOG_E(TAG, "RAW signal(\'%.*s\'): no timings", header_len, string.c_str()); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
| @ -303,7 +300,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|         parsed = std::sscanf(str.data(), "%9s", buf); | ||||
|         if(parsed != 1) { | ||||
|             FURI_LOG_E( | ||||
|                 "IrdaFileParser", | ||||
|                 TAG, | ||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%*s\'", | ||||
|                 header_len, | ||||
|                 string.c_str(), | ||||
| @ -318,7 +315,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
|         int value = atoi(buf); | ||||
|         if(value <= 0) { | ||||
|             FURI_LOG_E( | ||||
|                 "IrdaFileParser", | ||||
|                 TAG, | ||||
|                 "RAW signal(\'%.*s...\'): failed on timing[%ld] \'%s\'", | ||||
|                 header_len, | ||||
|                 string.c_str(), | ||||
| @ -330,7 +327,7 @@ std::unique_ptr<IrdaAppFileParser::IrdaFileSignal> | ||||
| 
 | ||||
|         if(raw_signal.timings_cnt >= max_raw_timings_in_signal) { | ||||
|             FURI_LOG_E( | ||||
|                 "IrdaFileParser", | ||||
|                 TAG, | ||||
|                 "RAW signal(\'%.*s...\'): too much timings (max %ld)", | ||||
|                 header_len, | ||||
|                 string.c_str(), | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| #include "loader/loader.h" | ||||
| #include "loader_i.h" | ||||
| 
 | ||||
| #define TAG "LoaderSrv" | ||||
| 
 | ||||
| #define LOADER_THREAD_FLAG_SHOW_MENU (1 << 0) | ||||
| #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(furi_thread_get_state(loader_instance->thread) != FuriThreadStateStopped) { | ||||
|         FURI_LOG_E( | ||||
|             LOADER_LOG_TAG, "Can't start app. %s is running", loader_instance->current_app->name); | ||||
|         FURI_LOG_E(TAG, "Can't start app. %s is running", loader_instance->current_app->name); | ||||
|         return; | ||||
|     } | ||||
|     furi_hal_power_insomnia_enter(); | ||||
|     loader_instance->current_app = flipper_app; | ||||
| 
 | ||||
|     FURI_LOG_I( | ||||
|         LOADER_LOG_TAG, "Starting furi application: %s", loader_instance->current_app->name); | ||||
|     FURI_LOG_I(TAG, "Starting furi application: %s", loader_instance->current_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_context(loader_instance->thread, NULL); | ||||
| @ -79,14 +79,14 @@ LoaderStatus loader_start(Loader* instance, const char* name, const char* args) | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     bool locked = loader_lock(instance); | ||||
| 
 | ||||
|     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 */ | ||||
|         return LoaderStatusErrorAppStarted; | ||||
|     } | ||||
| @ -97,10 +97,10 @@ LoaderStatus loader_start(Loader* instance, const char* name, const char* args) | ||||
|         string_set_str(instance->args, args); | ||||
|         string_strim(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 { | ||||
|         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); | ||||
| @ -155,7 +155,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con | ||||
|         delay(20); | ||||
|         int heap_diff = instance->free_heap_size - memmgr_get_free_heap(); | ||||
|         FURI_LOG_I( | ||||
|             LOADER_LOG_TAG, | ||||
|             TAG, | ||||
|             "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", | ||||
|             heap_diff, | ||||
|             furi_thread_get_heap_size(instance->thread)); | ||||
| @ -266,7 +266,7 @@ static void loader_add_cli_command(FlipperApplication* app) { | ||||
| } | ||||
| 
 | ||||
| static void loader_build_menu() { | ||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Building main menu"); | ||||
|     FURI_LOG_I(TAG, "Building main menu"); | ||||
|     size_t i; | ||||
|     for(i = 0; i < FLIPPER_APPS_COUNT; i++) { | ||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_APPS[i]); | ||||
| @ -300,7 +300,7 @@ static void loader_build_menu() { | ||||
|         loader_submenu_callback, | ||||
|         (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++) { | ||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_PLUGINS[i]); | ||||
|         submenu_add_item( | ||||
| @ -311,7 +311,7 @@ static void loader_build_menu() { | ||||
|             (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++) { | ||||
|         loader_add_cli_command((FlipperApplication*)&FLIPPER_DEBUG_APPS[i]); | ||||
|         submenu_add_item( | ||||
| @ -322,7 +322,7 @@ static void loader_build_menu() { | ||||
|             (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++) { | ||||
|         submenu_add_item( | ||||
|             loader_instance->settings_menu, | ||||
| @ -339,7 +339,7 @@ void loader_show_menu() { | ||||
| } | ||||
| 
 | ||||
| int32_t loader_srv(void* p) { | ||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Starting"); | ||||
|     FURI_LOG_I(TAG, "Starting"); | ||||
| 
 | ||||
|     loader_instance = loader_alloc(); | ||||
| 
 | ||||
| @ -350,7 +350,7 @@ int32_t loader_srv(void* p) { | ||||
|         FLIPPER_ON_SYSTEM_START[i](); | ||||
|     } | ||||
| 
 | ||||
|     FURI_LOG_I(LOADER_LOG_TAG, "Started"); | ||||
|     FURI_LOG_I(TAG, "Started"); | ||||
| 
 | ||||
|     furi_record_create("loader", loader_instance); | ||||
| 
 | ||||
|  | ||||
| @ -12,8 +12,6 @@ | ||||
| #include <applications.h> | ||||
| #include <assets_icons.h> | ||||
| 
 | ||||
| #define LOADER_LOG_TAG "loader" | ||||
| 
 | ||||
| struct Loader { | ||||
|     osThreadId_t loader_thread; | ||||
|     FuriThread* thread; | ||||
|  | ||||
| @ -1,49 +1,80 @@ | ||||
| #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 | ||||
|     nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) { | ||||
|     bool found = false; | ||||
|     FileWorker* file_worker = file_worker_alloc(true); | ||||
| static bool nfc_emv_parser_search_data( | ||||
|     Storage* storage, | ||||
|     const char* file_name, | ||||
|     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)) { | ||||
|         if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) { | ||||
|             found = true; | ||||
|         } | ||||
|     } | ||||
|     do { | ||||
|         // Open file
 | ||||
|         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); | ||||
|     file_worker_free(file_worker); | ||||
|     return found; | ||||
|     string_clear(temp_str); | ||||
|     flipper_file_free(file); | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) { | ||||
|     bool result = false; | ||||
| bool nfc_emv_parser_get_aid_name( | ||||
|     Storage* storage, | ||||
|     uint8_t* aid, | ||||
|     uint8_t aid_len, | ||||
|     string_t aid_name) { | ||||
|     furi_assert(storage); | ||||
|     bool parsed = false; | ||||
|     string_t key; | ||||
|     string_init(key); | ||||
|     for(uint8_t i = 0; i < aid_len; 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); | ||||
|     return result; | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) { | ||||
|     bool result = false; | ||||
| bool nfc_emv_parser_get_country_name( | ||||
|     Storage* storage, | ||||
|     uint16_t country_code, | ||||
|     string_t country_name) { | ||||
|     bool parsed = false; | ||||
|     string_t key; | ||||
|     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); | ||||
|     return result; | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) { | ||||
|     bool result = false; | ||||
| bool nfc_emv_parser_get_currency_name( | ||||
|     Storage* storage, | ||||
|     uint16_t currency_code, | ||||
|     string_t currency_name) { | ||||
|     bool parsed = false; | ||||
|     string_t key; | ||||
|     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); | ||||
|     return result; | ||||
|     return parsed; | ||||
| } | ||||
|  | ||||
| @ -3,25 +3,39 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <m-string.h> | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| /** Get EMV application name by number
 | ||||
|  * @param storage Storage instance | ||||
|  * @param aid - AID number array | ||||
|  * @param aid_len - AID length | ||||
|  * @param aid_name - string to keep AID name | ||||
|  * @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
 | ||||
|  * @param storage Storage instance | ||||
|  * @param country_code - ISO 3166 country code | ||||
|  * @param country_name - string to keep country name | ||||
|  * @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
 | ||||
|  * @param storage Storage instance | ||||
|  * @param currency_code - ISO 3166 currency code | ||||
|  * @param currency_name - string to keep currency name | ||||
|  * @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_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100); | ||||
| 
 | ||||
|     // Nfc device
 | ||||
|     nfc->dev = nfc_device_alloc(); | ||||
| 
 | ||||
|     // Open GUI record
 | ||||
|     nfc->gui = furi_record_open("gui"); | ||||
|     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); | ||||
| @ -82,6 +85,9 @@ Nfc* nfc_alloc() { | ||||
| void nfc_free(Nfc* nfc) { | ||||
|     furi_assert(nfc); | ||||
| 
 | ||||
|     // Nfc device
 | ||||
|     nfc_device_free(nfc->dev); | ||||
| 
 | ||||
|     // Submenu
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|     submenu_free(nfc->submenu); | ||||
| @ -154,8 +160,12 @@ int32_t nfc_app(void* p) { | ||||
|     char* args = p; | ||||
| 
 | ||||
|     // Check argument and run corresponding scene
 | ||||
|     if((*args != '\0') && nfc_device_load(&nfc->dev, p)) { | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|     if((*args != '\0') && nfc_device_load(nfc->dev, p)) { | ||||
|         if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); | ||||
|         } else { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|         } | ||||
|     } else { | ||||
|         scene_manager_next_scene(nfc->scene_manager, 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/hex.h> | ||||
| 
 | ||||
| #define NFC_DEVICE_MAX_DATA_LEN 14 | ||||
| #include <lib/flipper_file/flipper_file.h> | ||||
| 
 | ||||
| static const char* nfc_app_folder = "/any/nfc"; | ||||
| static const char* nfc_app_extension = ".nfc"; | ||||
| 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) { | ||||
|     string_strim(str); | ||||
|     uint8_t nibble_high = 0; | ||||
|     uint8_t nibble_low = 0; | ||||
|     bool parsed = true; | ||||
| 
 | ||||
|     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; | ||||
| NfcDevice* nfc_device_alloc() { | ||||
|     NfcDevice* nfc_dev = furi_alloc(sizeof(NfcDevice)); | ||||
|     nfc_dev->storage = furi_record_open("storage"); | ||||
|     nfc_dev->dialogs = furi_record_open("dialogs"); | ||||
|     return nfc_dev; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|         string_set_str(format_string, "UID\n"); | ||||
|         string_set_str(format_string, "UID"); | ||||
|     } 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) { | ||||
|         string_set_str(format_string, "Mifare Ultralight\n"); | ||||
|         string_set_str(format_string, "Mifare Ultralight"); | ||||
|     } 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) { | ||||
| @ -59,228 +52,166 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) { | ||||
|     NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data; | ||||
|     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) { | ||||
| static bool nfc_device_save_mifare_ul_data(FlipperFile* file, NfcDevice* dev) { | ||||
|     bool saved = false; | ||||
|     MifareUlData* data = &dev->dev_data.mf_ul_data; | ||||
|     string_printf(mifare_ul_string, "Signature:"); | ||||
|     for(uint8_t i = 0; i < sizeof(data->signature); i++) { | ||||
|         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; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
| 
 | ||||
|     // Save Mifare Ultralight specific data
 | ||||
|     do { | ||||
|         // strlen("Signature: ") = 11
 | ||||
|         string_right(mifare_ul_string, 11); | ||||
|         if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) { | ||||
|         if(!flipper_file_write_comment_cstr(file, "Mifare Ultralight specific data")) break; | ||||
|         if(!flipper_file_write_hex(file, "Signature", data->signature, sizeof(data->signature))) | ||||
|             break; | ||||
|         } | ||||
|         // strlen("Version: ") = 9
 | ||||
|         string_right(mifare_ul_string, 9); | ||||
|         if(!nfc_device_read_hex( | ||||
|                mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) { | ||||
|         if(!flipper_file_write_hex( | ||||
|                file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version))) | ||||
|             break; | ||||
|         } | ||||
|         string_strim(mifare_ul_string); | ||||
|         // Read counters and tearing flags
 | ||||
|         // Write conters and tearing flags data
 | ||||
|         bool counters_saved = true; | ||||
|         for(uint8_t i = 0; i < 3; i++) { | ||||
|             res = sscanf( | ||||
|                 string_get_cstr(mifare_ul_string), | ||||
|                 "Counter %hX: %lu Tearing flag %hX: %02hX", | ||||
|                 &cnt_num, | ||||
|                 &data->counter[i], | ||||
|                 &cnt_num, | ||||
|                 &tearing_tmp); | ||||
|             if(res != 4) { | ||||
|             string_printf(temp_str, "Counter %d", i); | ||||
|             if(!flipper_file_write_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) { | ||||
|                 counters_saved = false; | ||||
|                 break; | ||||
|             } | ||||
|             string_printf(temp_str, "Tearing %d", i); | ||||
|             if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) { | ||||
|                 counters_saved = false; | ||||
|                 break; | ||||
|             } | ||||
|             data->tearing[i] = tearing_tmp; | ||||
|             ws = string_search_char(mifare_ul_string, '\n'); | ||||
|             string_right(mifare_ul_string, ws + 1); | ||||
|         } | ||||
|         // Read data size
 | ||||
|         res = sscanf(string_get_cstr(mifare_ul_string), "Data size: %hu", &data->data_size); | ||||
|         if(res != 1) { | ||||
|             break; | ||||
|         } | ||||
|         ws = string_search_char(mifare_ul_string, '\n'); | ||||
|         string_right(mifare_ul_string, ws + 1); | ||||
|         // Read data
 | ||||
|         if(!counters_saved) break; | ||||
|         // Write pages data
 | ||||
|         uint32_t pages_total = data->data_size / 4; | ||||
|         if(!flipper_file_write_uint32(file, "Pages total", &pages_total, 1)) break; | ||||
|         bool pages_saved = true; | ||||
|         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; | ||||
|             } | ||||
|         } | ||||
|         parsed = true; | ||||
|     } while(0); | ||||
|         if(!pages_saved) break; | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     string_printf(bank_card_string, "AID len: %d, AID:", data->aid_len); | ||||
|     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)); | ||||
|     uint32_t data_temp = 0; | ||||
| 
 | ||||
|     do { | ||||
|         res = sscanf(string_get_cstr(bank_card_string), "AID len: %hu", &data->aid_len); | ||||
|         if(res != 1) { | ||||
|             break; | ||||
|         // Write Bank card specific data
 | ||||
|         if(!flipper_file_write_comment_cstr(file, "Bank card specific data")) 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
 | ||||
|         string_right(bank_card_string, 9); | ||||
|         size_t ws = string_search_char(bank_card_string, ':'); | ||||
|         string_right(bank_card_string, ws + 1); | ||||
|         if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) { | ||||
|             break; | ||||
|         if(data->country_code) { | ||||
|             data_temp = data->country_code; | ||||
|             if(!flipper_file_write_uint32(file, "Country code", &data_temp, 1)) break; | ||||
|         } | ||||
|         res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name); | ||||
|         if(res != 1) { | ||||
|             break; | ||||
|         if(data->currency_code) { | ||||
|             data_temp = data->currency_code; | ||||
|             if(!flipper_file_write_uint32(file, "Currency code", &data_temp, 1)) break; | ||||
|         } | ||||
|         ws = string_search_char(bank_card_string, '\n'); | ||||
|         string_right(bank_card_string, ws + 1); | ||||
|         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); | ||||
|         saved = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| @ -297,58 +228,49 @@ static bool nfc_device_save_file( | ||||
|     const char* extension) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     string_t dev_file_name; | ||||
|     string_init(dev_file_name); | ||||
|     bool saved = false; | ||||
|     FlipperFile* file = flipper_file_alloc(dev->storage); | ||||
|     NfcDeviceCommonData* data = &dev->dev_data.nfc_data; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     uint16_t string_len = 0; | ||||
| 
 | ||||
|     do { | ||||
|         // Create nfc directory if necessary
 | ||||
|         if(!file_worker_mkdir(file_worker, nfc_app_folder)) { | ||||
|             break; | ||||
|         }; | ||||
|         if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break; | ||||
|         // First remove nfc device file if it was saved
 | ||||
|         string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension); | ||||
|         if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) { | ||||
|             break; | ||||
|         }; | ||||
|         string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); | ||||
|         // Open file
 | ||||
|         if(!file_worker_open( | ||||
|                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { | ||||
|         if(!flipper_file_open_always(file, string_get_cstr(temp_str))) break; | ||||
|         // 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; | ||||
|         } | ||||
|         // Prepare and write format name on 1st line
 | ||||
|         string_len = nfc_device_prepare_format_string(dev, temp_str); | ||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { | ||||
|         nfc_device_prepare_format_string(dev, temp_str); | ||||
|         if(!flipper_file_write_string(file, "Device type", temp_str)) break; | ||||
|         // Write UID, ATQA, SAK
 | ||||
|         if(!flipper_file_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) | ||||
|             break; | ||||
|         } | ||||
|         // Prepare and write UID data on 2nd line
 | ||||
|         string_len = nfc_device_prepare_uid_string(dev, temp_str); | ||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { | ||||
|             break; | ||||
|         } | ||||
|         if(!flipper_file_write_hex(file, "UID", data->uid, data->uid_len)) break; | ||||
|         if(!flipper_file_write_hex(file, "ATQA", data->atqa, 2)) break; | ||||
|         if(!flipper_file_write_hex(file, "SAK", &data->sak, 1)) break; | ||||
|         // Save more data if necessary
 | ||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|             string_len = nfc_device_prepare_mifare_ul_string(dev, temp_str); | ||||
|             if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_save_mifare_ul_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|             string_len = nfc_device_prepare_bank_card_string(dev, temp_str); | ||||
|             if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_save_bank_card_data(file, dev)) break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     if(!saved) { | ||||
|         dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file"); | ||||
|     } | ||||
|     string_clear(temp_str); | ||||
|     string_clear(dev_file_name); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
| 
 | ||||
|     return true; | ||||
|     flipper_file_close(file); | ||||
|     flipper_file_free(file); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) { | ||||
|     string_t temp_string; | ||||
|     string_init(temp_string); | ||||
| static bool nfc_device_load_data(NfcDevice* dev, string_t path) { | ||||
|     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 { | ||||
|         // Check existance of shadow file
 | ||||
|         size_t ext_start = string_search_str(path, nfc_app_extension); | ||||
|         string_set_n(temp_string, path, 0, ext_start); | ||||
|         string_cat_printf(temp_string, "%s", nfc_app_shadow_extension); | ||||
|         if(!file_worker_is_file_exist( | ||||
|                file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) { | ||||
|             break; | ||||
|         } | ||||
|         string_set_n(temp_str, path, 0, ext_start); | ||||
|         string_cat_printf(temp_str, "%s", nfc_app_shadow_extension); | ||||
|         dev->shadow_file_exist = | ||||
|             storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK; | ||||
|         // Open shadow file if it exists. If not - open original
 | ||||
|         if(dev->shadow_file_exist) { | ||||
|             if(!file_worker_open( | ||||
|                    file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!flipper_file_open_existing(file, string_get_cstr(temp_str))) break; | ||||
|         } else { | ||||
|             if(!file_worker_open( | ||||
|                    file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!flipper_file_open_existing(file, string_get_cstr(path))) break; | ||||
|         } | ||||
| 
 | ||||
|         // Read and parse format from 1st line
 | ||||
|         if(!file_worker_read_until(file_worker, temp_string, '\n')) { | ||||
|             break; | ||||
|         } | ||||
|         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)) { | ||||
|         // Read and verify file header
 | ||||
|         uint32_t version = 0; | ||||
|         if(!flipper_file_read_header(file, temp_str, &version)) break; | ||||
|         if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) { | ||||
|             depricated_version = true; | ||||
|             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
 | ||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|             // Read until EOF
 | ||||
|             if(!file_worker_read_until(file_worker, temp_string, 0x05)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_parse_mifare_ul_string(dev, temp_string)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_load_mifare_ul_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|             // Read until EOF
 | ||||
|             if(!file_worker_read_until(file_worker, temp_string, 0x05)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_parse_bank_card_string(dev, temp_string)) { | ||||
|                 break; | ||||
|             } | ||||
|             if(!nfc_device_load_bank_card_data(file, dev)) break; | ||||
|         } | ||||
|         parsed = true; | ||||
|     } while(0); | ||||
|     } while(false); | ||||
| 
 | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| @ -434,19 +347,16 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) { | ||||
|     furi_assert(dev); | ||||
|     furi_assert(file_path); | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     // Load device data
 | ||||
|     string_t 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) { | ||||
|         // Set device name
 | ||||
|         path_extract_filename_no_ext(file_path, path); | ||||
|         nfc_device_set_name(dev, string_get_cstr(path)); | ||||
|     } | ||||
|     string_clear(path); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
| 
 | ||||
|     return dev_load; | ||||
| } | ||||
| @ -454,10 +364,9 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) { | ||||
| bool nfc_file_select(NfcDevice* dev) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     // Input events and views are managed by file_select
 | ||||
|     bool res = file_worker_file_select( | ||||
|         file_worker, | ||||
|     bool res = dialog_file_select_show( | ||||
|         dev->dialogs, | ||||
|         nfc_app_folder, | ||||
|         nfc_app_extension, | ||||
|         dev->file_name, | ||||
| @ -465,18 +374,14 @@ bool nfc_file_select(NfcDevice* dev) { | ||||
|         dev->dev_name); | ||||
|     if(res) { | ||||
|         string_t dev_str; | ||||
| 
 | ||||
|         // Get key file path
 | ||||
|         string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension); | ||||
| 
 | ||||
|         res = nfc_device_load_data(file_worker, dev_str, dev); | ||||
|         res = nfc_device_load_data(dev, dev_str); | ||||
|         if(res) { | ||||
|             nfc_device_set_name(dev, dev->file_name); | ||||
|         } | ||||
|         string_clear(dev_str); | ||||
|     } | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| @ -491,61 +396,48 @@ void nfc_device_clear(NfcDevice* dev) { | ||||
| bool nfc_device_delete(NfcDevice* dev) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     bool result = true; | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     bool deleted = false; | ||||
|     string_t file_path; | ||||
|     string_init(file_path); | ||||
| 
 | ||||
|     do { | ||||
|         // Delete original file
 | ||||
|         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))) { | ||||
|             result = false; | ||||
|             break; | ||||
|         } | ||||
|         if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; | ||||
|         // Delete shadow file if it exists
 | ||||
|         if(dev->shadow_file_exist) { | ||||
|             string_clean(file_path); | ||||
|             string_printf( | ||||
|                 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))) { | ||||
|                 result = false; | ||||
|                 break; | ||||
|             } | ||||
|             if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break; | ||||
|         } | ||||
|         deleted = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     if(!deleted) { | ||||
|         dialog_message_show_storage_error(dev->dialogs, "Can not remove file"); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(file_path); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     return result; | ||||
|     return deleted; | ||||
| } | ||||
| 
 | ||||
| bool nfc_device_restore(NfcDevice* dev) { | ||||
|     furi_assert(dev); | ||||
|     furi_assert(dev->shadow_file_exist); | ||||
| 
 | ||||
|     bool result = true; | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     bool restored = false; | ||||
|     string_t path; | ||||
| 
 | ||||
|     do { | ||||
|         string_init_printf( | ||||
|             path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension); | ||||
|         if(!file_worker_remove(file_worker, string_get_cstr(path))) { | ||||
|             result = false; | ||||
|             break; | ||||
|         } | ||||
|         if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break; | ||||
|         dev->shadow_file_exist = false; | ||||
|         string_clean(path); | ||||
|         string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension); | ||||
|         if(!nfc_device_load_data(file_worker, path, dev)) { | ||||
|             result = false; | ||||
|             break; | ||||
|         } | ||||
|         if(!nfc_device_load_data(dev, path)) break; | ||||
|         restored = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     string_clear(path); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     return result; | ||||
|     return restored; | ||||
| } | ||||
|  | ||||
| @ -2,6 +2,8 @@ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <storage/storage.h> | ||||
| #include <dialogs/dialogs.h> | ||||
| 
 | ||||
| #include "mifare_ultralight.h" | ||||
| 
 | ||||
| @ -57,6 +59,8 @@ typedef struct { | ||||
| } NfcDeviceData; | ||||
| 
 | ||||
| typedef struct { | ||||
|     Storage* storage; | ||||
|     DialogsApp* dialogs; | ||||
|     NfcDeviceData dev_data; | ||||
|     char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; | ||||
|     char file_name[NFC_FILE_NAME_MAX_LEN]; | ||||
| @ -64,6 +68,10 @@ typedef struct { | ||||
|     bool shadow_file_exist; | ||||
| } NfcDevice; | ||||
| 
 | ||||
| NfcDevice* nfc_device_alloc(); | ||||
| 
 | ||||
| void nfc_device_free(NfcDevice* nfc_dev); | ||||
| 
 | ||||
| void nfc_device_set_name(NfcDevice* dev, const char* 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; | ||||
|     NotificationApp* notifications; | ||||
|     SceneManager* scene_manager; | ||||
|     NfcDevice dev; | ||||
|     NfcDevice* dev; | ||||
|     NfcDeviceCommonData dev_edit_data; | ||||
| 
 | ||||
|     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/mifare_ultralight.h" | ||||
| 
 | ||||
| #define NFC_WORKER_TAG "nfc worker" | ||||
| #define TAG "NfcWorker" | ||||
| 
 | ||||
| /***************************** NFC Worker API *******************************/ | ||||
| 
 | ||||
| NfcWorker* nfc_worker_alloc() { | ||||
|     NfcWorker* nfc_worker = furi_alloc(sizeof(NfcWorker)); | ||||
|     // 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->callback = NULL; | ||||
|     nfc_worker->context = NULL; | ||||
| @ -144,7 +144,7 @@ void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||
|     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; | ||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||
|         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); | ||||
|     } | ||||
| @ -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.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); | ||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 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(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 FURI_LOG_I( | ||||
|                     NFC_WORKER_TAG, "Select PPSE response received. Start parsing response"); | ||||
|                 FURI_LOG_I(TAG, "Select PPSE response received. Start parsing response"); | ||||
|                 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
 | ||||
|                     result->emv_data.aid_len = 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; | ||||
|                 } 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(); | ||||
|                     continue; | ||||
|                 } | ||||
|             } else { | ||||
|                 // 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(); | ||||
|             } | ||||
|         } else { | ||||
|             // 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(); | ||||
|         } | ||||
|         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.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); | ||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 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(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 FURI_LOG_I( | ||||
|                     NFC_WORKER_TAG, "Select PPSE response received. Start parsing response"); | ||||
|                 FURI_LOG_I(TAG, "Select PPSE response received. Start parsing response"); | ||||
|                 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 { | ||||
|                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application"); | ||||
|                     FURI_LOG_E(TAG, "Can't find pay application"); | ||||
|                     furi_hal_nfc_deactivate(); | ||||
|                     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); | ||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, "Error during application selection request: %d", err); | ||||
|                     FURI_LOG_E(TAG, "Error during application selection request: %d", err); | ||||
|                     furi_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 FURI_LOG_I( | ||||
|                     NFC_WORKER_TAG, | ||||
|                     "Select application response received. Start parsing response"); | ||||
|                 FURI_LOG_I(TAG, "Select application response received. Start parsing response"); | ||||
|                 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)); | ||||
|                 } 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 { | ||||
|                     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(); | ||||
|                     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); | ||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, "Error during Get Processing Options command: %d", err); | ||||
|                     FURI_LOG_E(TAG, "Error during Get Processing Options command: %d", err); | ||||
|                     furi_hal_nfc_deactivate(); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { | ||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Card number parsed"); | ||||
|                     FURI_LOG_I(TAG, "Card number parsed"); | ||||
|                     result->emv_data.number_len = emv_app.card_number_len; | ||||
|                     memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); | ||||
|                     // 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); | ||||
|                             if(err != ERR_NONE) { | ||||
|                                 FURI_LOG_E( | ||||
|                                     NFC_WORKER_TAG, | ||||
|                                     TAG, | ||||
|                                     "Error reading application sfi %d, record %d", | ||||
|                                     sfi, | ||||
|                                     record); | ||||
| @ -321,7 +317,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                         } | ||||
|                     } | ||||
|                     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; | ||||
|                         memcpy( | ||||
|                             result->emv_data.number, | ||||
| @ -343,18 +339,18 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                         } | ||||
|                         break; | ||||
|                     } 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(); | ||||
|                 } | ||||
|             } else { | ||||
|                 // 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(); | ||||
|             } | ||||
|         } else { | ||||
|             // 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(); | ||||
|         } | ||||
|         osDelay(20); | ||||
| @ -416,63 +412,63 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateEmulateApdu) { | ||||
|         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
 | ||||
|             err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); | ||||
|             if(err == ERR_NONE) { | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received Select PPSE"); | ||||
|                 FURI_LOG_I(TAG, "Received Select PPSE"); | ||||
|             } 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(); | ||||
|                 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); | ||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|             if(err == ERR_NONE) { | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received Select APP"); | ||||
|                 FURI_LOG_I(TAG, "Received Select APP"); | ||||
|             } 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(); | ||||
|                 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); | ||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|             if(err == ERR_NONE) { | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Received PDOL"); | ||||
|                 FURI_LOG_I(TAG, "Received PDOL"); | ||||
|             } 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(); | ||||
|                 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); | ||||
|             err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|             if(err == ERR_NONE) { | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Transive PDOL ANS"); | ||||
|                 FURI_LOG_I(TAG, "Transive PDOL ANS"); | ||||
|             } 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(); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             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 { | ||||
|                 FURI_LOG_I(NFC_WORKER_TAG, "Correct debug message received"); | ||||
|                 FURI_LOG_I(TAG, "Correct debug message received"); | ||||
|                 tx_len = sizeof(debug_tx); | ||||
|                 err = furi_hal_nfc_data_exchange( | ||||
|                     (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false); | ||||
|                 if(err == ERR_NONE) { | ||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Transive Debug message"); | ||||
|                     FURI_LOG_I(TAG, "Transive Debug message"); | ||||
|                 } | ||||
|             } | ||||
|             furi_hal_nfc_deactivate(); | ||||
|         } else { | ||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find reader"); | ||||
|             FURI_LOG_W(TAG, "Can't find reader"); | ||||
|         } | ||||
|         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.selRes.sak)) { | ||||
|                 // 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); | ||||
|                 err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||
|                 if(err == ERR_NONE) { | ||||
|                     mf_ul_parse_get_version_response(rx_buff, &mf_ul_read); | ||||
|                     FURI_LOG_I( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         TAG, | ||||
|                         "Mifare Ultralight Type: %d, Pages: %d", | ||||
|                         mf_ul_read.type, | ||||
|                         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); | ||||
|                     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)); | ||||
|                     } else { | ||||
|                         mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read); | ||||
|                     } | ||||
|                 } else if(err == ERR_TIMEOUT) { | ||||
|                     FURI_LOG_W( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         TAG, | ||||
|                         "Card doesn't respond to GET VERSION command. Setting default read parameters"); | ||||
|                     err = ERR_NONE; | ||||
|                     mf_ul_set_default_version(&mf_ul_read); | ||||
|                     // Reinit device
 | ||||
|                     furi_hal_nfc_deactivate(); | ||||
|                     if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { | ||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); | ||||
|                         FURI_LOG_E(TAG, "Lost connection. Restarting search"); | ||||
|                         continue; | ||||
|                     } | ||||
|                 } else { | ||||
|                     FURI_LOG_E( | ||||
|                         NFC_WORKER_TAG, | ||||
|                         "Error getting Mifare Ultralight version. Error code: %d", | ||||
|                         err); | ||||
|                         TAG, "Error getting Mifare Ultralight version. Error code: %d", err); | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 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); | ||||
|                     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; | ||||
|                     } else { | ||||
|                         mf_ul_parse_fast_read_response( | ||||
|                             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++) { | ||||
|                         tx_len = mf_ul_prepare_read_cnt(tx_buff, i); | ||||
|                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||
|                             FURI_LOG_W(NFC_WORKER_TAG, "Failed reading Counter %d", i); | ||||
|                             FURI_LOG_W(TAG, "Failed reading Counter %d", i); | ||||
|                             mf_ul_read.data.counter[i] = 0; | ||||
|                         } else { | ||||
|                             mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     FURI_LOG_I(NFC_WORKER_TAG, "Checking tearing flags ..."); | ||||
|                     FURI_LOG_I(TAG, "Checking tearing flags ..."); | ||||
|                     for(uint8_t i = 0; i < 3; i++) { | ||||
|                         tx_len = mf_ul_prepare_check_tearing(tx_buff, i); | ||||
|                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||
|                             FURI_LOG_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; | ||||
|                         } else { | ||||
|                             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 { | ||||
|                     // READ card with READ command (4 pages at a time)
 | ||||
|                     for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { | ||||
|                         FURI_LOG_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); | ||||
|                         if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { | ||||
|                             FURI_LOG_E( | ||||
|                                 NFC_WORKER_TAG, "Read pages %d - %d failed", page, page + 3); | ||||
|                             FURI_LOG_E(TAG, "Read pages %d - %d failed", page, page + 3); | ||||
|                             continue; | ||||
|                         } else { | ||||
|                             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; | ||||
|             } else { | ||||
|                 FURI_LOG_W(NFC_WORKER_TAG, "Tag does not support Mifare Ultralight"); | ||||
|                 FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight"); | ||||
|             } | ||||
|         } else { | ||||
|             FURI_LOG_W(NFC_WORKER_TAG, "Can't find any tags"); | ||||
|             FURI_LOG_W(TAG, "Can't find any tags"); | ||||
|         } | ||||
|         osDelay(100); | ||||
|     } | ||||
| @ -627,7 +620,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||
|                data->nfc_data.sak, | ||||
|                true, | ||||
|                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)) { | ||||
|                 // Data exchange loop
 | ||||
|                 while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { | ||||
| @ -639,17 +632,17 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||
|                         if(err == ERR_NONE) { | ||||
|                             continue; | ||||
|                         } else { | ||||
|                             FURI_LOG_E(NFC_WORKER_TAG, "Communication error: %d", err); | ||||
|                             FURI_LOG_E(TAG, "Communication error: %d", err); | ||||
|                             break; | ||||
|                         } | ||||
|                     } 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(); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } 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(); | ||||
|             } | ||||
|         } | ||||
| @ -660,7 +653,7 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||
|                 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(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     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, | ||||
|             "Run compatible app", | ||||
| @ -48,9 +48,9 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|         if(event.event == SubmenuIndexRunApp) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); | ||||
|             if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { | ||||
|             if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { | ||||
|                 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); | ||||
|             } | ||||
|             return true; | ||||
| @ -66,7 +66,7 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|             return true; | ||||
|         } else if(event.event == 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); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -12,14 +12,14 @@ void nfc_scene_delete_on_enter(void* context) { | ||||
| 
 | ||||
|     // Setup Custom Widget view
 | ||||
|     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_button_element( | ||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); | ||||
|     char uid_str[32]; | ||||
|     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; | ||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; | ||||
|     if(data->uid_len == 4) { | ||||
|         snprintf( | ||||
|             uid_str, | ||||
| @ -73,7 +73,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { | ||||
|         if(event.event == GuiButtonTypeLeft) { | ||||
|             return scene_manager_previous_scene(nfc->scene_manager); | ||||
|         } 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); | ||||
|             } else { | ||||
|                 scene_manager_search_and_switch_to_previous_scene( | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include "../helpers/nfc_emv_parser.h" | ||||
| 
 | ||||
| #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
 | ||||
|     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( | ||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); | ||||
|     char uid_str[32]; | ||||
|     NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data; | ||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; | ||||
|     if(data->uid_len == 4) { | ||||
|         snprintf( | ||||
|             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); | ||||
| 
 | ||||
|     // Setup Data View
 | ||||
|     if(nfc->dev.format == NfcDeviceSaveFormatUid) { | ||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||
|         DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|         dialog_ex_set_left_button_text(dialog_ex, "Back"); | ||||
|         dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); | ||||
|         dialog_ex_set_context(dialog_ex, nfc); | ||||
|         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); | ||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { | ||||
|         MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data; | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|         MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||
|         TextBox* text_box = nfc->text_box; | ||||
|         text_box_set_context(text_box, nfc); | ||||
|         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]); | ||||
|         } | ||||
|         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { | ||||
|         NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|         NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|         BankCard* bank_card = nfc->bank_card; | ||||
|         bank_card_set_name(bank_card, emv_data->name); | ||||
|         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); | ||||
| @ -116,12 +117,29 @@ void nfc_scene_device_info_on_enter(void* context) { | ||||
|         if(emv_data->exp_mon) { | ||||
|             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) { | ||||
|             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) { | ||||
|             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); | ||||
|     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)) { | ||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||
|         } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { | ||||
|             if(nfc->dev.format == NfcDeviceSaveFormatUid) { | ||||
|             if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||
|                 scene_manager_set_scene_state( | ||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||
|                 consumed = true; | ||||
|             } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { | ||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|                 scene_manager_set_scene_state( | ||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||
|                 consumed = true; | ||||
|             } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { | ||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|                 scene_manager_set_scene_state( | ||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||
|                 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
 | ||||
|     widget_clear(nfc->widget); | ||||
| 
 | ||||
|     if(nfc->dev.format == NfcDeviceSaveFormatUid) { | ||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||
|         // Clear Dialog
 | ||||
|         DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|         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_result_callback(dialog_ex, NULL); | ||||
|         dialog_ex_set_context(dialog_ex, NULL); | ||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|         // Clear TextBox
 | ||||
|         text_box_clean(nfc->text_box); | ||||
|         string_clean(nfc->text_box_store); | ||||
|     } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) { | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|         // Clear Bank Card
 | ||||
|         bank_card_clear(nfc->bank_card); | ||||
|     } | ||||
|  | ||||
| @ -11,7 +11,7 @@ void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { | ||||
|     // Setup and start worker
 | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||
|     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev.dev_data, NULL, nfc); | ||||
|     nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     if(strcmp(nfc->dev.dev_name, "")) { | ||||
|         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); | ||||
|     if(strcmp(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_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, | ||||
|         NfcWorkerStateEmulateMifareUl, | ||||
|         &nfc->dev.dev_data, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_emulate_mifare_ul_worker_callback, | ||||
|         nfc); | ||||
| } | ||||
| @ -45,7 +45,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event | ||||
|            NFC_MF_UL_DATA_CHANGED) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 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; | ||||
|     } | ||||
|  | ||||
| @ -5,10 +5,10 @@ void nfc_scene_emulate_uid_on_enter(void* context) { | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     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, "")) { | ||||
|         nfc_text_store_set(nfc, "%s", nfc->dev.dev_name); | ||||
|     if(strcmp(nfc->dev->dev_name, "")) { | ||||
|         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); | ||||
|     } else if(data->uid_len == 4) { | ||||
|         nfc_text_store_set( | ||||
|             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
 | ||||
| 
 | ||||
|     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) { | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| void nfc_scene_file_select_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     // Process file_select return
 | ||||
|     if(nfc_file_select(&nfc->dev)) { | ||||
|     if(nfc_file_select(nfc->dev)) { | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); | ||||
|     } else { | ||||
|         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) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave); | ||||
|             nfc->dev.format = NfcDeviceSaveFormatMifareUl; | ||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareUl; | ||||
|             // Clear device name
 | ||||
|             nfc_device_set_name(&nfc->dev, ""); | ||||
|             nfc_device_set_name(nfc->dev, ""); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|  | ||||
| @ -18,7 +18,7 @@ void nfc_scene_read_card_on_enter(void* context) { | ||||
|     // Start worker
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||
|     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) { | ||||
|  | ||||
| @ -15,7 +15,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { | ||||
|     notification_message(nfc->notifications, &sequence_success); | ||||
| 
 | ||||
|     // 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; | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||
|     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); | ||||
|         } else if(event.event == DialogExResultRight) { | ||||
|             // Clear device name
 | ||||
|             nfc_device_set_name(&nfc->dev, ""); | ||||
|             nfc_device_set_name(nfc->dev, ""); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -20,7 +20,7 @@ void nfc_scene_read_emv_app_on_enter(void* context) { | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, | ||||
|         NfcWorkerStateReadEMVApp, | ||||
|         &nfc->dev.dev_data, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_read_emv_app_worker_callback, | ||||
|         nfc); | ||||
| } | ||||
|  | ||||
| @ -13,8 +13,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; | ||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; | ||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||
|     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|     DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||
|     dialog_ex_set_right_button_text(dialog_ex, "Run app"); | ||||
| @ -23,7 +23,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { | ||||
|     // Display UID and AID
 | ||||
|     string_t 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) { | ||||
|         for(uint8_t i = 0; i < emv_data->aid_len; 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); | ||||
|     // 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
 | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, | ||||
|         NfcWorkerStateReadEMV, | ||||
|         &nfc->dev.dev_data, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_read_emv_data_worker_callback, | ||||
|         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) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data; | ||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data; | ||||
|     NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|     NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||
| 
 | ||||
|     // Setup Custom Widget view
 | ||||
|     // Add frame
 | ||||
| @ -34,7 +34,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | ||||
|         nfc); | ||||
|     // Add card name
 | ||||
|     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
 | ||||
|     string_t 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_init(country_name); | ||||
|     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_init_printf(disp_country, "Reg:%s", country_name); | ||||
|         widget_add_string_element( | ||||
| @ -61,7 +61,8 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { | ||||
|     string_t currency_name; | ||||
|     string_init(currency_name); | ||||
|     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_init_printf(disp_currency, "Cur:%s", currency_name); | ||||
|         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); | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             // Clear device name
 | ||||
|             nfc_device_set_name(&nfc->dev, ""); | ||||
|             nfc->dev.format = NfcDeviceSaveFormatBankCard; | ||||
|             nfc_device_set_name(nfc->dev, ""); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatBankCard; | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -20,7 +20,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) { | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, | ||||
|         NfcWorkerStateReadMifareUl, | ||||
|         &nfc->dev.dev_data, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_read_mifare_ul_worker_callback, | ||||
|         nfc); | ||||
| } | ||||
|  | ||||
| @ -27,7 +27,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | ||||
|     notification_message(nfc->notifications, &sequence_success); | ||||
| 
 | ||||
|     // 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; | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||
|     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); | ||||
| 
 | ||||
|     // 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; | ||||
|     text_box_set_context(text_box, nfc); | ||||
|     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
 | ||||
|     TextInput* text_input = nfc->text_input; | ||||
|     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)); | ||||
|         dev_name_empty = true; | ||||
|     } 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_result_callback( | ||||
| @ -37,14 +37,14 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { | ||||
|             if(strcmp(nfc->dev.dev_name, "")) { | ||||
|                 nfc_device_delete(&nfc->dev); | ||||
|             if(strcmp(nfc->dev->dev_name, "")) { | ||||
|                 nfc_device_delete(nfc->dev); | ||||
|             } | ||||
|             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); | ||||
|             if(nfc_device_save(&nfc->dev, nfc->text_store)) { | ||||
|             strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); | ||||
|             if(nfc_device_save(nfc->dev, nfc->text_store)) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); | ||||
|                 return true; | ||||
|             } else { | ||||
|  | ||||
| @ -18,7 +18,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
| 
 | ||||
|     if(nfc->dev.format != NfcDeviceSaveFormatBankCard) { | ||||
|     if(nfc->dev->format != NfcDeviceSaveFormatBankCard) { | ||||
|         submenu_add_item( | ||||
|             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_set_selected_item( | ||||
|         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, | ||||
|             "Restore original", | ||||
| @ -49,7 +49,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); | ||||
|         if(event.event == SubmenuIndexEmulate) { | ||||
|             if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) { | ||||
|             if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); | ||||
|             } else { | ||||
|                 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); | ||||
|             consumed = true; | ||||
|         } 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( | ||||
|                     nfc->scene_manager, NfcSceneStart); | ||||
|             } else { | ||||
|  | ||||
| @ -19,7 +19,7 @@ void nfc_scene_set_atqa_on_enter(void* context) { | ||||
|         nfc_scene_set_atqa_byte_input_callback, | ||||
|         NULL, | ||||
|         nfc, | ||||
|         nfc->dev.dev_data.nfc_data.atqa, | ||||
|         nfc->dev->dev_data.nfc_data.atqa, | ||||
|         2); | ||||
|     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, | ||||
|         NULL, | ||||
|         nfc, | ||||
|         &nfc->dev.dev_data.nfc_data.sak, | ||||
|         &nfc->dev->dev_data.nfc_data.sak, | ||||
|         1); | ||||
|     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; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
|     // Clear device name
 | ||||
|     nfc_device_set_name(&nfc->dev, ""); | ||||
|     nfc_device_set_name(nfc->dev, ""); | ||||
|     submenu_add_item( | ||||
|         submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); | ||||
|     submenu_add_item( | ||||
| @ -28,13 +28,13 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexNFCA7) { | ||||
|             nfc->dev.dev_data.nfc_data.uid_len = 7; | ||||
|             nfc->dev.format = NfcDeviceSaveFormatUid; | ||||
|             nfc->dev->dev_data.nfc_data.uid_len = 7; | ||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); | ||||
|             return true; | ||||
|         } else if(event.event == SubmenuIndexNFCA4) { | ||||
|             nfc->dev.dev_data.nfc_data.uid_len = 4; | ||||
|             nfc->dev.format = NfcDeviceSaveFormatUid; | ||||
|             nfc->dev->dev_data.nfc_data.uid_len = 4; | ||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
| @ -14,7 +14,7 @@ void nfc_scene_set_uid_on_enter(void* context) { | ||||
|     // Setup view
 | ||||
|     ByteInput* byte_input = nfc->byte_input; | ||||
|     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, | ||||
|         nfc_scene_set_uid_byte_input_callback, | ||||
|  | ||||
| @ -34,7 +34,7 @@ void nfc_scene_start_on_enter(void* context) { | ||||
|     submenu_set_selected_item( | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     string_t country_name; | ||||
|     string_init(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); | ||||
|     widget_add_string_element( | ||||
|         bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, 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); | ||||
|     string_t currency_name; | ||||
|     string_init(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); | ||||
|     widget_add_string_element( | ||||
|         bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, 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_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-app.h" | ||||
| 
 | ||||
| #define TAG "NotificationSrv" | ||||
| 
 | ||||
| static const uint8_t minimal_delay = 100; | ||||
| 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")); | ||||
|     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 = | ||||
|         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) { | ||||
|         FURI_LOG_I("notification", "load success"); | ||||
|         FURI_LOG_I(TAG, "load success"); | ||||
| 
 | ||||
|         if(settings.version != NOTIFICATION_SETTINGS_VERSION) { | ||||
|             FURI_LOG_E( | ||||
|                 "notification", | ||||
|                 "version(%d != %d) mismatch", | ||||
|                 settings.version, | ||||
|                 NOTIFICATION_SETTINGS_VERSION); | ||||
|                 TAG, "version(%d != %d) mismatch", settings.version, NOTIFICATION_SETTINGS_VERSION); | ||||
|         } else { | ||||
|             osKernelLock(); | ||||
|             memcpy(&app->settings, &settings, settings_size); | ||||
|             osKernelUnlock(); | ||||
|         } | ||||
|     } 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); | ||||
| @ -356,7 +355,7 @@ static bool notification_save_settings(NotificationApp* app) { | ||||
|     File* file = storage_file_alloc(furi_record_open("storage")); | ||||
|     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(); | ||||
|     memcpy(&settings, &app->settings, settings_size); | ||||
| @ -374,9 +373,9 @@ static bool notification_save_settings(NotificationApp* app) { | ||||
|     } | ||||
| 
 | ||||
|     if(fs_result) { | ||||
|         FURI_LOG_I("notification", "save success"); | ||||
|         FURI_LOG_I(TAG, "save success"); | ||||
|     } 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); | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| #include <cmsis_os2.h> | ||||
| #include <portmacro.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include <cli/cli.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| @ -16,14 +17,12 @@ | ||||
| #include <m-string.h> | ||||
| #include <m-dict.h> | ||||
| 
 | ||||
| #define RPC_TAG "RPC" | ||||
| #define TAG "RpcSrv" | ||||
| 
 | ||||
| #define RPC_EVENT_NEW_DATA (1 << 0) | ||||
| #define RPC_EVENT_DISCONNECT (1 << 1) | ||||
| #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) | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -53,6 +52,7 @@ static RpcSystemCallbacks rpc_systems[] = { | ||||
| 
 | ||||
| struct RpcSession { | ||||
|     RpcSendBytesCallback send_bytes_callback; | ||||
|     RpcBufferIsEmptyCallback buffer_is_empty_callback; | ||||
|     RpcSessionClosedCallback closed_callback; | ||||
|     void* context; | ||||
|     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; | ||||
|         string_cat_printf(str, "\tlist_response {\r\n"); | ||||
|         rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count); | ||||
|         break; | ||||
|     } | ||||
|     case PB_Main_gui_start_screen_stream_request_tag: | ||||
|         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: | ||||
|         string_cat_printf(str, "\tstop_screen_stream {\r\n"); | ||||
|         break; | ||||
|     case PB_Main_gui_screen_stream_frame_tag: | ||||
|         string_cat_printf(str, "\tscreen_stream_frame {\r\n"); | ||||
|     case PB_Main_gui_screen_frame_tag: | ||||
|         string_cat_printf(str, "\tscreen_frame {\r\n"); | ||||
|         break; | ||||
|     case PB_Main_gui_send_input_event_request_tag: | ||||
|         string_cat_printf(str, "\tsend_input_event {\r\n"); | ||||
| @ -280,6 +281,12 @@ void rpc_print_message(const PB_Main* message) { | ||||
|         string_cat_printf( | ||||
|             str, "\t\type: %d\r\n", message->content.gui_send_input_event_request.type); | ||||
|         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"); | ||||
|     printf("%s", string_get_cstr(str)); | ||||
| @ -292,7 +299,7 @@ static Rpc* rpc_alloc(void) { | ||||
|     rpc->busy_mutex = osMutexNew(NULL); | ||||
|     rpc->busy = false; | ||||
|     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->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); | ||||
| 
 | ||||
|         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 */ | ||||
| @ -365,6 +372,7 @@ static void rpc_free_session(RpcSession* session) { | ||||
|     session->context = NULL; | ||||
|     session->closed_callback = NULL; | ||||
|     session->send_bytes_callback = NULL; | ||||
|     session->buffer_is_empty_callback = NULL; | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 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.
 | ||||
|  * 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 | ||||
| @ -415,6 +435,12 @@ size_t | ||||
|     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) { | ||||
|     Rpc* rpc = istream->state; | ||||
|     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) { | ||||
|         bytes_received += | ||||
|             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) { | ||||
|             break; | ||||
|         } 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); | ||||
| #endif | ||||
| 
 | ||||
| @ -456,8 +487,8 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* message) { | ||||
|     RpcSession* session = &rpc->session; | ||||
|     pb_ostream_t ostream = PB_OSTREAM_SIZING; | ||||
| 
 | ||||
| #if DEBUG_PRINT | ||||
|     FURI_LOG_I(RPC_TAG, "OUTPUT:"); | ||||
| #if SRV_RPC_DEBUG | ||||
|     FURI_LOG_I(TAG, "OUTPUT:"); | ||||
|     rpc_print_message(message); | ||||
| #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); | ||||
| 
 | ||||
| #if DEBUG_PRINT | ||||
| #if SRV_RPC_DEBUG | ||||
|     rpc_print_data("OUTPUT", buffer, ostream.bytes_written); | ||||
| #endif | ||||
| 
 | ||||
| @ -510,12 +541,12 @@ int32_t rpc_srv(void* p) { | ||||
|             .callback = rpc_pb_stream_read, | ||||
|             .state = rpc, | ||||
|             .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 DEBUG_PRINT | ||||
|             FURI_LOG_I(RPC_TAG, "INPUT:"); | ||||
| #if SRV_RPC_DEBUG | ||||
|             FURI_LOG_I(TAG, "INPUT:"); | ||||
|             rpc_print_message(rpc->decoded_message); | ||||
| #endif | ||||
|             RpcHandler* handler = | ||||
| @ -524,20 +555,19 @@ int32_t rpc_srv(void* p) { | ||||
|             if(handler && handler->message_handler) { | ||||
|                 handler->message_handler(rpc->decoded_message, handler->context); | ||||
|             } else if(!handler && !rpc->session.terminate) { | ||||
|                 FURI_LOG_E( | ||||
|                     RPC_TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content); | ||||
|                 FURI_LOG_E(TAG, "Unhandled message, tag: %d", rpc->decoded_message->which_content); | ||||
|             } | ||||
|         } else { | ||||
|             xStreamBufferReset(rpc->stream); | ||||
|             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); | ||||
| 
 | ||||
|         if(rpc->session.terminate) { | ||||
|             FURI_LOG_D(RPC_TAG, "Session terminated"); | ||||
|             FURI_LOG_D(TAG, "Session terminated"); | ||||
|             osEventFlagsClear(rpc->events, RPC_EVENTS_ALL); | ||||
|             rpc_free_session(&rpc->session); | ||||
|             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 "cmsis_os.h" | ||||
| 
 | ||||
| #define RPC_BUFFER_SIZE (1024) | ||||
| #define RPC_MAX_MESSAGE_SIZE (1536) | ||||
| 
 | ||||
| /** Rpc interface. Used for opening session only. */ | ||||
| typedef struct Rpc Rpc; | ||||
| /** Rpc session interface */ | ||||
| @ -11,6 +14,8 @@ typedef struct RpcSession RpcSession; | ||||
| 
 | ||||
| /** Callback to send to client any data (e.g. response to command) */ | ||||
| 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
 | ||||
|  * is received. Any other actions lays on transport layer. | ||||
|  * 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); | ||||
| 
 | ||||
| /** 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
 | ||||
|  *  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 | ||||
|  */ | ||||
| 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 <furi.h> | ||||
| #include <rpc/rpc.h> | ||||
| #include <furi-hal-vcp.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     Cli* cli; | ||||
|     bool session_close_request; | ||||
| } 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) { | ||||
|     furi_assert(context); | ||||
| @ -50,7 +50,8 @@ void rpc_cli_command_start_session(Cli* cli, string_t args, void* context) { | ||||
|         } | ||||
| 
 | ||||
|         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/gui_i.h> | ||||
| 
 | ||||
| #define TAG "RpcGui" | ||||
| 
 | ||||
| typedef struct { | ||||
|     Rpc* rpc; | ||||
|     Gui* gui; | ||||
|     ViewPort* virtual_display_view_port; | ||||
|     uint8_t* virtual_display_buffer; | ||||
|     bool virtual_display_not_empty; | ||||
| } 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(size == 1024); | ||||
|     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)); | ||||
| 
 | ||||
|     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->content.gui_screen_stream_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size)); | ||||
|     uint8_t* buffer = frame->content.gui_screen_stream_frame.data->bytes; | ||||
|     uint16_t* frame_size_msg = &frame->content.gui_screen_stream_frame.data->size; | ||||
|     frame->content.gui_screen_frame.data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size)); | ||||
|     uint8_t* buffer = frame->content.gui_screen_frame.data->bytes; | ||||
|     uint16_t* frame_size_msg = &frame->content.gui_screen_frame.data->size; | ||||
|     *frame_size_msg = 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); | ||||
| 
 | ||||
|     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) { | ||||
| @ -45,9 +51,9 @@ void rpc_system_gui_stop_screen_stream_process(const PB_Main* request, void* con | ||||
|     furi_assert(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); | ||||
| 
 | ||||
|     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) { | ||||
| @ -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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|     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_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; | ||||
| } | ||||
| 
 | ||||
| @ -149,6 +246,15 @@ void rpc_system_gui_free(void* ctx) { | ||||
|     furi_assert(ctx); | ||||
|     RpcGuiSystem* rpc_gui = ctx; | ||||
|     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); | ||||
|     furi_record_close("gui"); | ||||
|     free(rpc_gui); | ||||
|  | ||||
| @ -463,3 +463,28 @@ bool storage_simply_mkdir(Storage* storage, const char* path) { | ||||
|     result = storage_common_mkdir(storage, path); | ||||
|     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 <storage/storage.h> | ||||
| 
 | ||||
| #define TAG "storage-test" | ||||
| #define TAG "StorageTest" | ||||
| #define BYTES_COUNT 16 | ||||
| #define TEST_STRING "TestDataStringProvidedByDiceRoll" | ||||
| #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); | ||||
| 
 | ||||
| /**
 | ||||
|  * @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 | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -10,7 +10,7 @@ typedef DIR SDDir; | ||||
| typedef FILINFO SDFileInfo; | ||||
| typedef FRESULT SDError; | ||||
| 
 | ||||
| #define TAG "storage-ext" | ||||
| #define TAG "StorageExt" | ||||
| #define STORAGE_PATH "/ext" | ||||
| /********************* Definitions ********************/ | ||||
| 
 | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| #include <lfs.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #define TAG "storage-int" | ||||
| #define TAG "StorageInt" | ||||
| #define STORAGE_PATH "/int" | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|     if(furi_hal_flash_erase(page, 1)) { | ||||
|     if(furi_hal_flash_erase(page)) { | ||||
|         return 0; | ||||
|     } else { | ||||
|         return -1; | ||||
|  | ||||
| @ -145,7 +145,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() { | ||||
|     SubGhzFrequencyAnalyzerWorker* instance = furi_alloc(sizeof(SubGhzFrequencyAnalyzerWorker)); | ||||
| 
 | ||||
|     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_context(instance->thread, instance); | ||||
|     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) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     char buffer_str[16]; | ||||
|     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 frequency_str; | ||||
|     string_t modulation_str; | ||||
|     string_t text; | ||||
| 
 | ||||
|     string_init(frequency_str); | ||||
|     string_init(modulation_str); | ||||
|     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); | ||||
|     widget_add_string_multiline_element( | ||||
|         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); | ||||
| 
 | ||||
|     string_clear(frequency_str); | ||||
|     string_clear(modulation_str); | ||||
|     string_clear(text); | ||||
| 
 | ||||
|     widget_add_button_element( | ||||
| @ -50,7 +50,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { | ||||
|     SubGhz* subghz = context; | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         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)) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); | ||||
|             } else { | ||||
|  | ||||
| @ -6,27 +6,19 @@ | ||||
| static void subghz_scene_read_raw_update_statusbar(void* context) { | ||||
|     furi_assert(context); | ||||
|     SubGhz* subghz = context; | ||||
|     char frequency_str[20]; | ||||
|     char preset_str[10]; | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
|     string_t frequency_str; | ||||
|     string_t modulation_str; | ||||
| 
 | ||||
|     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) { | ||||
| @ -70,7 +62,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; | ||||
|             subghz_protocol_raw_save_to_file_stop( | ||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
| 
 | ||||
|             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) { | ||||
|                 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( | ||||
|                 (SubGhzProtocolRAW*)subghz->txrx->protocol_result); | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
| 
 | ||||
|             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) { | ||||
|                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); | ||||
|             } else { | ||||
|                 subghz_get_preset_name(subghz, subghz->error_str); | ||||
|                 if(subghz_protocol_raw_save_to_file_init( | ||||
|                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result, | ||||
|                        "Raw_temp", | ||||
|                        subghz->txrx->frequency, | ||||
|                        subghz->txrx->preset)) { | ||||
|                        string_get_cstr(subghz->error_str))) { | ||||
|                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || | ||||
|                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { | ||||
|                         subghz_begin(subghz, subghz->txrx->preset); | ||||
|                         subghz_rx(subghz, subghz->txrx->frequency); | ||||
|                     } | ||||
|                     subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||
|                     subghz->state_notifications = SubGhzNotificationStateRX; | ||||
|                 } else { | ||||
|                     string_set(subghz->error_str, "No SD card"); | ||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||
| @ -127,14 +120,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|             break; | ||||
|         case SubghzCustomEventViewReadRAWMore: | ||||
|             if(strcmp( | ||||
|                    subghz_protocol_get_last_file_name( | ||||
|                    subghz_protocol_raw_get_last_file_name( | ||||
|                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result), | ||||
|                    "")) { | ||||
|                 strlcpy( | ||||
|                     subghz->file_name, | ||||
|                     subghz_protocol_get_last_file_name( | ||||
|                     subghz_protocol_raw_get_last_file_name( | ||||
|                         (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)) + | ||||
|                         1); | ||||
|                 //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->file_name, | ||||
|                     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)); | ||||
|                 string_clear(temp_str); | ||||
| 
 | ||||
| @ -159,7 +152,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeTick) { | ||||
|         switch(subghz->state_notifications) { | ||||
|         case NOTIFICATION_RX_STATE: | ||||
|         case SubGhzNotificationStateRX: | ||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||
|             subghz_read_raw_update_sample_write( | ||||
|                 subghz->subghz_read_raw, | ||||
| @ -182,7 +175,7 @@ void subghz_scene_read_raw_on_exit(void* context) { | ||||
|         subghz_rx_end(subghz); | ||||
|         subghz_sleep(subghz); | ||||
|     }; | ||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
| 
 | ||||
|     //Сallback restoration
 | ||||
|     subghz_worker_set_pair_callback( | ||||
|  | ||||
| @ -3,33 +3,29 @@ | ||||
| 
 | ||||
| static void subghz_scene_receiver_update_statusbar(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
|     char frequency_str[20]; | ||||
|     char preset_str[10]; | ||||
|     string_t history_stat_str; | ||||
|     string_init(history_stat_str); | ||||
|     if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) { | ||||
|         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); | ||||
|         } | ||||
|         string_t frequency_str; | ||||
|         string_t modulation_str; | ||||
| 
 | ||||
|         string_init(frequency_str); | ||||
|         string_init(modulation_str); | ||||
| 
 | ||||
|         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str); | ||||
| 
 | ||||
|         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 { | ||||
|         subghz_receiver_add_data_statusbar( | ||||
|             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", ""); | ||||
|         subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|         subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|     } | ||||
|     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_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) { | ||||
|         subghz_rx_end(subghz); | ||||
|     }; | ||||
| @ -104,7 +100,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||
|         switch(event.event) { | ||||
|         case SubghzCustomEventViewReceverBack: | ||||
|             // Stop CC1101 Rx
 | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||
|                 subghz_rx_end(subghz); | ||||
|                 subghz_sleep(subghz); | ||||
| @ -125,7 +121,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||
|             return true; | ||||
|             break; | ||||
|         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); | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig); | ||||
|             return true; | ||||
| @ -140,7 +136,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { | ||||
|         } | ||||
| 
 | ||||
|         switch(subghz->state_notifications) { | ||||
|         case NOTIFICATION_RX_STATE: | ||||
|         case SubGhzNotificationStateRX: | ||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||
|             break; | ||||
|         default: | ||||
|  | ||||
| @ -40,35 +40,42 @@ void subghz_scene_receiver_info_on_enter(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     if(subghz_scene_receiver_info_update_parser(subghz)) { | ||||
|         char buffer_str[16]; | ||||
|         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 frequency_str; | ||||
|         string_t modulation_str; | ||||
|         string_t text; | ||||
| 
 | ||||
|         string_init(frequency_str); | ||||
|         string_init(modulation_str); | ||||
|         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); | ||||
|         widget_add_string_multiline_element( | ||||
|             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text)); | ||||
| 
 | ||||
|         string_clear(frequency_str); | ||||
|         string_clear(modulation_str); | ||||
|         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")) { | ||||
|             widget_add_button_element( | ||||
|                 subghz->widget, | ||||
| @ -112,13 +119,13 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) | ||||
|                 if(!subghz_tx_start(subghz)) { | ||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||
|                 } else { | ||||
|                     subghz->state_notifications = NOTIFICATION_TX_STATE; | ||||
|                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) { | ||||
|             //CC1101 Stop Tx -> Start RX
 | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||
|                 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) { | ||||
|                 subghz->txrx->hopper_state = SubGhzHopperStateRunnig; | ||||
|             } | ||||
|             subghz->state_notifications = NOTIFICATION_RX_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateRX; | ||||
|             return true; | ||||
|         } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) { | ||||
|             //CC1101 Stop RX -> Save
 | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             if(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)) { | ||||
|                 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")) { | ||||
|                 subghz_file_name_clear(subghz); | ||||
|                 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); | ||||
|         } | ||||
|         switch(subghz->state_notifications) { | ||||
|         case NOTIFICATION_TX_STATE: | ||||
|         case SubGhzNotificationStateTX: | ||||
|             notification_message(subghz->notifications, &sequence_blink_red_10); | ||||
|             break; | ||||
|         case NOTIFICATION_RX_STATE: | ||||
|         case SubGhzNotificationStateRX: | ||||
|             notification_message(subghz->notifications, &sequence_blink_blue_10); | ||||
|             break; | ||||
|         default: | ||||
|  | ||||
| @ -19,7 +19,7 @@ void subghz_scene_save_name_on_enter(void* context) { | ||||
|         set_random_name(subghz->file_name, sizeof(subghz->file_name)); | ||||
|         dev_name_empty = true; | ||||
|     } 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) == | ||||
|            SubghzCustomEventManagerSet) { | ||||
|             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) { | ||||
|     SubGhz* subghz = context; | ||||
|     if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) { | ||||
|         subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|     if(subghz->state_notifications == SubGhzNotificationStateStarting) { | ||||
|         subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|     } | ||||
|     submenu_add_item( | ||||
|         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) { | ||||
|         string_t key_str; | ||||
|         string_t frequency_str; | ||||
|         string_t modulation_str; | ||||
| 
 | ||||
|         string_init(key_str); | ||||
|         char frequency_str[10]; | ||||
|         char preset_str[6]; | ||||
|         string_init(frequency_str); | ||||
|         string_init(modulation_str); | ||||
|         uint8_t show_button = 0; | ||||
|         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 { | ||||
|             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->subghz_transmitter, | ||||
|             string_get_cstr(key_str), | ||||
|             frequency_str, | ||||
|             preset_str, | ||||
|             string_get_cstr(frequency_str), | ||||
|             string_get_cstr(modulation_str), | ||||
|             show_button); | ||||
| 
 | ||||
|         string_clear(frequency_str); | ||||
|         string_clear(modulation_str); | ||||
|         string_clear(key_str); | ||||
| 
 | ||||
|         return true; | ||||
| @ -67,7 +58,7 @@ void subghz_scene_transmitter_on_enter(void* context) { | ||||
|     subghz_transmitter_set_callback( | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| @ -75,7 +66,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
|     SubGhz* subghz = context; | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubghzCustomEventViewTransmitterSendStart) { | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { | ||||
|                 subghz_rx_end(subghz); | ||||
|             } | ||||
| @ -84,20 +75,20 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
|                 if(!subghz_tx_start(subghz)) { | ||||
|                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); | ||||
|                 } else { | ||||
|                     subghz->state_notifications = NOTIFICATION_TX_STATE; | ||||
|                     subghz->state_notifications = SubGhzNotificationStateTX; | ||||
|                     subghz_scene_transmitter_update_data_show(subghz); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } else if(event.event == SubghzCustomEventViewTransmitterSendStop) { | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||
|                 subghz_tx_stop(subghz); | ||||
|                 subghz_sleep(subghz); | ||||
|             } | ||||
|             return true; | ||||
|         } else if(event.event == SubghzCustomEventViewTransmitterBack) { | ||||
|             subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 subghz->scene_manager, SubGhzSceneStart); | ||||
|             return true; | ||||
| @ -106,7 +97,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); | ||||
|         } | ||||
|     } 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); | ||||
|         } | ||||
|         return true; | ||||
| @ -117,5 +108,5 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { | ||||
| void subghz_scene_transmitter_on_exit(void* context) { | ||||
|     SubGhz* subghz = context; | ||||
| 
 | ||||
|     subghz->state_notifications = NOTIFICATION_IDLE_STATE; | ||||
|     subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| #include "subghz_i.h" | ||||
| #include <lib/toolbox/path.h> | ||||
| 
 | ||||
| const char* const subghz_frequencies_text[] = { | ||||
|     "300.00", | ||||
| @ -119,6 +120,9 @@ SubGhz* subghz_alloc() { | ||||
|     view_dispatcher_add_view( | ||||
|         subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget)); | ||||
| 
 | ||||
|     //Dialog
 | ||||
|     subghz->dialogs = furi_record_open("dialogs"); | ||||
| 
 | ||||
|     // Transmitter
 | ||||
|     subghz->subghz_transmitter = subghz_transmitter_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -224,6 +228,9 @@ void subghz_free(SubGhz* subghz) { | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget); | ||||
|     widget_free(subghz->widget); | ||||
| 
 | ||||
|     //Dialog
 | ||||
|     furi_record_close("dialogs"); | ||||
| 
 | ||||
|     // Transmitter
 | ||||
|     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter); | ||||
|     subghz_transmitter_free(subghz->subghz_transmitter); | ||||
| @ -280,6 +287,14 @@ int32_t subghz_app(void* p) { | ||||
| 
 | ||||
|     // Check argument and run corresponding scene
 | ||||
|     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); | ||||
|     } else { | ||||
|         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart); | ||||
|  | ||||
| @ -6,10 +6,74 @@ | ||||
| #include <input/input.h> | ||||
| #include <gui/elements.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include "file-worker.h" | ||||
| #include <lib/flipper_file/flipper_file.h> | ||||
| #include "../notification/notification.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) { | ||||
|     furi_assert(subghz); | ||||
|     furi_hal_subghz_reset(); | ||||
| @ -79,17 +143,6 @@ void subghz_sleep(SubGhz* subghz) { | ||||
|     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) { | ||||
|     furi_assert(subghz); | ||||
| 
 | ||||
| @ -144,66 +197,78 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | ||||
|     furi_assert(subghz); | ||||
|     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
 | ||||
|     bool loaded = false; | ||||
|     string_t path; | ||||
|     string_init_set_str(path, file_path); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     int res = 0; | ||||
|     int data = 0; | ||||
|     uint32_t version; | ||||
| 
 | ||||
|     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; | ||||
|         } | ||||
| 
 | ||||
|         // Read and parse frequency from 1st line
 | ||||
|         if(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||
|         if(((!strcmp(string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) || | ||||
|             (!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; | ||||
|         } | ||||
|         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(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||
|         if(!flipper_file_read_uint32( | ||||
|                flipper_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Frequency"); | ||||
|             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(!file_worker_read_until(file_worker, temp_str, '\n')) { | ||||
|         if(!flipper_file_read_string(flipper_file, "Preset", temp_str)) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Preset"); | ||||
|             break; | ||||
|         } | ||||
|         // strlen("Protocol: ") = 10
 | ||||
|         string_right(temp_str, 10); | ||||
|         if(!subghz_set_pteset(subghz, string_get_cstr(temp_str))) { | ||||
|             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_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str)); | ||||
|         if(subghz->txrx->protocol_result == NULL) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "This type of protocol was not found"); | ||||
|             break; | ||||
|         } | ||||
|         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; | ||||
|         } | ||||
|         loaded = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     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(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; | ||||
| } | ||||
| @ -211,23 +276,22 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { | ||||
| bool subghz_get_next_name_file(SubGhz* subghz) { | ||||
|     furi_assert(subghz); | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     Storage* storage = furi_record_open("storage"); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     bool res = false; | ||||
| 
 | ||||
|     if(strcmp(subghz->file_name, "")) { | ||||
|         //get the name of the next free file
 | ||||
|         file_worker_get_next_filename( | ||||
|             file_worker, SUBGHZ_RAW_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str); | ||||
|         storage_get_next_filename( | ||||
|             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))); | ||||
|         res = true; | ||||
|     } | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     furi_record_close("storage"); | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| @ -236,7 +300,8 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | ||||
|     furi_assert(subghz); | ||||
|     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_init(dev_file_name); | ||||
|     string_t temp_str; | ||||
| @ -244,43 +309,71 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | ||||
|     bool saved = false; | ||||
| 
 | ||||
|     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
 | ||||
|         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; | ||||
|         } | ||||
|         // 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; | ||||
|         } | ||||
| 
 | ||||
|         // First remove subghz device file if it was saved
 | ||||
|         string_printf( | ||||
|             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; | ||||
|         } | ||||
| 
 | ||||
|         // Open file
 | ||||
|         if(!file_worker_open( | ||||
|                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) { | ||||
|         if(!flipper_file_open_always(flipper_file, string_get_cstr(dev_file_name))) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to open file for write: %s", dev_file_name); | ||||
|             break; | ||||
|         } | ||||
|         //Get string frequency preset protocol
 | ||||
|         subghz_frequency_preset_to_str(subghz, temp_str); | ||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { | ||||
| 
 | ||||
|         if(!flipper_file_write_header_cstr( | ||||
|                flipper_file, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add header"); | ||||
|             break; | ||||
|         } | ||||
|         //Get string save
 | ||||
|         subghz->txrx->protocol_result->to_save_string(subghz->txrx->protocol_result, temp_str); | ||||
|         // Prepare and write data to file
 | ||||
|         if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) { | ||||
| 
 | ||||
|         if(!flipper_file_write_uint32( | ||||
|                flipper_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) { | ||||
|             FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Frequency"); | ||||
|             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; | ||||
|     } while(0); | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
|     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; | ||||
| } | ||||
| @ -288,17 +381,12 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) { | ||||
| bool subghz_load_protocol_from_file(SubGhz* subghz) { | ||||
|     furi_assert(subghz); | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     string_t protocol_file_name; | ||||
|     string_init(protocol_file_name); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     int sscanf_res = 0; | ||||
|     int data = 0; | ||||
|     string_t file_name; | ||||
|     string_init(file_name); | ||||
| 
 | ||||
|     // Input events and views are managed by file_select
 | ||||
|     bool res = file_worker_file_select( | ||||
|         file_worker, | ||||
|     bool res = dialog_file_select_show( | ||||
|         subghz->dialogs, | ||||
|         SUBGHZ_APP_PATH_FOLDER, | ||||
|         SUBGHZ_APP_EXTENSION, | ||||
|         subghz->file_name, | ||||
| @ -306,87 +394,24 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | ||||
|         NULL); | ||||
| 
 | ||||
|     if(res) { | ||||
|         // Get key file path
 | ||||
|         string_printf( | ||||
|             protocol_file_name, | ||||
|             "%s/%s%s", | ||||
|             SUBGHZ_APP_PATH_FOLDER, | ||||
|             subghz->file_name, | ||||
|             SUBGHZ_APP_EXTENSION); | ||||
|     } else { | ||||
|         string_clear(temp_str); | ||||
|         string_clear(protocol_file_name); | ||||
|             file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); | ||||
| 
 | ||||
|         file_worker_close(file_worker); | ||||
|         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"); | ||||
|         res = subghz_key_load(subghz, string_get_cstr(file_name)); | ||||
|     } | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
|     string_clear(protocol_file_name); | ||||
| 
 | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     string_clear(file_name); | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| bool subghz_rename_file(SubGhz* subghz) { | ||||
|     furi_assert(subghz); | ||||
|     bool ret = false; | ||||
|     bool ret = true; | ||||
|     string_t old_path; | ||||
|     string_t new_path; | ||||
| 
 | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     Storage* storage = furi_record_open("storage"); | ||||
| 
 | ||||
|     string_init_printf( | ||||
|         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( | ||||
|         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(new_path); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     furi_record_close("storage"); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool subghz_delete_file(SubGhz* subghz) { | ||||
|     furi_assert(subghz); | ||||
| 
 | ||||
|     bool result = true; | ||||
|     FileWorker* file_worker = file_worker_alloc(false); | ||||
|     Storage* storage = furi_record_open("storage"); | ||||
|     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 { | ||||
|         // 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); | ||||
|     subghz_file_name_clear(subghz); | ||||
| 
 | ||||
|     string_clear(file_path); | ||||
|     file_worker_close(file_worker); | ||||
|     file_worker_free(file_worker); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -13,6 +13,7 @@ | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| #include <gui/gui.h> | ||||
| #include <dialogs/dialogs.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <notification/notification-messages.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| @ -33,11 +34,6 @@ | ||||
| 
 | ||||
| #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 uint32_t subghz_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_frequencies_433_92; | ||||
| 
 | ||||
| /** SubGhzNotification state */ | ||||
| typedef enum { | ||||
|     SubGhzNotificationStateStarting, | ||||
|     SubGhzNotificationStateIDLE, | ||||
|     SubGhzNotificationStateTX, | ||||
|     SubGhzNotificationStateRX, | ||||
| } SubGhzNotificationState; | ||||
| 
 | ||||
| /** SubGhzTxRx state */ | ||||
| typedef enum { | ||||
|     SubGhzTxRxStateIDLE, | ||||
| @ -101,9 +105,10 @@ struct SubGhz { | ||||
|     Popup* popup; | ||||
|     TextInput* text_input; | ||||
|     Widget* widget; | ||||
|     DialogsApp* dialogs; | ||||
|     char file_name[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||
|     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1]; | ||||
|     uint8_t state_notifications; | ||||
|     SubGhzNotificationState state_notifications; | ||||
| 
 | ||||
|     SubghzReceiver* subghz_receiver; | ||||
|     SubghzTransmitter* subghz_transmitter; | ||||
| @ -133,6 +138,9 @@ typedef enum { | ||||
|     SubGhzViewTestPacket, | ||||
| } 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); | ||||
| uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | ||||
| void subghz_rx_end(SubGhz* subghz); | ||||
|  | ||||
| @ -8,6 +8,8 @@ | ||||
| #include <notification/notification-messages.h> | ||||
| #include <lib/subghz/protocols/subghz_protocol_princeton.h> | ||||
| 
 | ||||
| #define TAG "SubGhzTestStatic" | ||||
| 
 | ||||
| typedef enum { | ||||
|     SubghzTestStaticStatusIDLE, | ||||
|     SubghzTestStaticStatusTX, | ||||
| @ -99,7 +101,7 @@ bool subghz_test_static_input(InputEvent* event, void* context) { | ||||
|                     } else { | ||||
|                         notification_message_block(notification, &sequence_set_red_255); | ||||
| 
 | ||||
|                         FURI_LOG_I("SubghzTestStatic", "TX Start"); | ||||
|                         FURI_LOG_I(TAG, "TX Start"); | ||||
| 
 | ||||
|                         subghz_encoder_princeton_set( | ||||
|                             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) { | ||||
|                     if(instance->satus_tx == SubghzTestStaticStatusTX) { | ||||
|                         FURI_LOG_I("SubghzTestStatic", "TX Stop"); | ||||
|                         FURI_LOG_I(TAG, "TX Stop"); | ||||
|                         subghz_encoder_princeton_print_log(instance->encoder); | ||||
|                         furi_hal_subghz_stop_async_tx(); | ||||
|                         notification_message(notification, &sequence_reset_red); | ||||
|  | ||||
| @ -29,7 +29,7 @@ static RpcSession* session = NULL; | ||||
| static StreamBufferHandle_t output_stream = NULL; | ||||
| static uint32_t command_id = 0; | ||||
| 
 | ||||
| #define TEST_RPC_TAG "TEST_RPC" | ||||
| #define TAG "UnitTestsRpc" | ||||
| #define MAX_RECEIVE_OUTPUT_TIMEOUT 3000 | ||||
| #define MAX_NAME_LENGTH 255 | ||||
| #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"); | ||||
|     furi_record_close("storage"); | ||||
|     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 { | ||||
|         MU_RUN_SUITE(test_rpc_storage); | ||||
|     } | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| #include <cli/cli.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| #define TESTS_TAG "UNIT_TESTS" | ||||
| #define TAG "UnitTests" | ||||
| 
 | ||||
| int run_minunit(); | ||||
| 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
 | ||||
|     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); | ||||
|     } else { | ||||
|         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(); | ||||
|         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) { | ||||
|             delay(200); /* wait for tested services and apps to deallocate */ | ||||
|             uint32_t heap_after = memmgr_get_free_heap(); | ||||
|             notification_message(notification, &sequence_success); | ||||
|             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 { | ||||
|                 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 { | ||||
|             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 */ | ||||
|     /* *< Application Errors */ | ||||
|     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; | ||||
| 
 | ||||
| /* Struct definitions */ | ||||
| @ -76,18 +79,20 @@ typedef struct _PB_Main { | ||||
|         PB_StopSession stop_session; | ||||
|         PB_Gui_StartScreenStreamRequest gui_start_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_Storage_StatRequest storage_stat_request; | ||||
|         PB_Storage_StatResponse storage_stat_response; | ||||
|         PB_Gui_StartVirtualDisplayRequest gui_start_virtual_display_request; | ||||
|         PB_Gui_StopVirtualDisplayRequest gui_stop_virtual_display_request; | ||||
|     } content;  | ||||
| } PB_Main; | ||||
| 
 | ||||
| 
 | ||||
| /* Helper constants for enums */ | ||||
| #define _PB_CommandStatus_MIN PB_CommandStatus_OK | ||||
| #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY | ||||
| #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_STORAGE_DIR_NOT_EMPTY+1)) | ||||
| #define _PB_CommandStatus_MAX PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED | ||||
| #define _PB_CommandStatus_ARRAYSIZE ((PB_CommandStatus)(PB_CommandStatus_ERROR_VIRTUAL_DISPLAY_NOT_STARTED+1)) | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| @ -124,10 +129,12 @@ extern "C" { | ||||
| #define PB_Main_stop_session_tag                 19 | ||||
| #define PB_Main_gui_start_screen_stream_request_tag 20 | ||||
| #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_storage_stat_request_tag         24 | ||||
| #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 */ | ||||
| #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,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_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,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_DEFAULT NULL | ||||
| #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_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_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_storage_stat_request_MSGTYPE PB_Storage_StatRequest | ||||
| #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_StopSession_msg; | ||||
| @ -203,9 +214,9 @@ extern const pb_msgdesc_t PB_Main_msg; | ||||
| /* Maximum encoded size of messages (where known) */ | ||||
| #define PB_Empty_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)) | ||||
| 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 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
|  | ||||
| @ -6,18 +6,24 @@ | ||||
| #error Regenerate this file with the current version of nanopb generator. | ||||
| #endif | ||||
| 
 | ||||
| PB_BIND(PB_Gui_ScreenFrame, PB_Gui_ScreenFrame, AUTO) | ||||
| 
 | ||||
| 
 | ||||
| PB_BIND(PB_Gui_StartScreenStreamRequest, PB_Gui_StartScreenStreamRequest, 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_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; | ||||
| 
 | ||||
| /* Struct definitions */ | ||||
| typedef struct _PB_Gui_ScreenStreamFrame {  | ||||
| typedef struct _PB_Gui_ScreenFrame {  | ||||
|     pb_bytes_array_t *data;  | ||||
| } PB_Gui_ScreenStreamFrame; | ||||
| } PB_Gui_ScreenFrame; | ||||
| 
 | ||||
| typedef struct _PB_Gui_StartScreenStreamRequest {  | ||||
|     char dummy_field; | ||||
| } PB_Gui_StartScreenStreamRequest; | ||||
| 
 | ||||
| typedef struct _PB_Gui_StartVirtualDisplayRequest {  | ||||
|     char dummy_field; | ||||
| } PB_Gui_StartVirtualDisplayRequest; | ||||
| 
 | ||||
| typedef struct _PB_Gui_StopScreenStreamRequest {  | ||||
|     char dummy_field; | ||||
| } PB_Gui_StopScreenStreamRequest; | ||||
| 
 | ||||
| typedef struct _PB_Gui_StopVirtualDisplayRequest {  | ||||
|     char dummy_field; | ||||
| } PB_Gui_StopVirtualDisplayRequest; | ||||
| 
 | ||||
| typedef struct _PB_Gui_SendInputEventRequest {  | ||||
|     PB_Gui_InputKey key;  | ||||
|     PB_Gui_InputType type;  | ||||
| @ -61,21 +69,30 @@ extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Initializer values for message structs */ | ||||
| #define PB_Gui_ScreenFrame_init_default          {NULL} | ||||
| #define PB_Gui_StartScreenStreamRequest_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_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_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_StartVirtualDisplayRequest_init_zero {0} | ||||
| #define PB_Gui_StopVirtualDisplayRequest_init_zero {0} | ||||
| 
 | ||||
| /* 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_type_tag    2 | ||||
| 
 | ||||
| /* 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_CALLBACK NULL | ||||
| @ -86,33 +103,44 @@ extern "C" { | ||||
| #define PB_Gui_StopScreenStreamRequest_CALLBACK 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) \ | ||||
| X(a, STATIC,   SINGULAR, UENUM,    key,               1) \ | ||||
| X(a, STATIC,   SINGULAR, UENUM,    type,              2) | ||||
| #define PB_Gui_SendInputEventRequest_CALLBACK 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_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_StartVirtualDisplayRequest_msg; | ||||
| extern const pb_msgdesc_t PB_Gui_StopVirtualDisplayRequest_msg; | ||||
| 
 | ||||
| /* 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_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_StartVirtualDisplayRequest_fields &PB_Gui_StartVirtualDisplayRequest_msg | ||||
| #define PB_Gui_StopVirtualDisplayRequest_fields &PB_Gui_StopVirtualDisplayRequest_msg | ||||
| 
 | ||||
| /* 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_StartScreenStreamRequest_size     0 | ||||
| #define PB_Gui_StartVirtualDisplayRequest_size   0 | ||||
| #define PB_Gui_StopScreenStreamRequest_size      0 | ||||
| #define PB_Gui_StopVirtualDisplayRequest_size    0 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } /* extern "C" */ | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 0e6d374ab1a12f95a3cd04444376a261e7252db4 | ||||
| Subproject commit 6be7def6087c4d277386381ff2792fa622933668 | ||||
| @ -1,148 +1,151 @@ | ||||
| A00000000305076010 VISA ELO Credit | ||||
| A0000000031010 VISA Debit/Credit (Classic) | ||||
| A000000003101001 VISA Credit | ||||
| A000000003101002 VISA Debit | ||||
| A0000000032010 VISA Electron | ||||
| A0000000032020 VISA | ||||
| A0000000033010 VISA Interlink | ||||
| A0000000034010 VISA Specific | ||||
| A0000000035010 VISA Specific | ||||
| A0000000036010 Domestic Visa Cash | ||||
| A0000000036020 International Visa Cash | ||||
| A0000000038002 VISA Auth EMV-CAP (DPA) | ||||
| A0000000038010 VISA Plus | ||||
| A0000000039010 VISA Loyalty | ||||
| A000000003999910 VISA Proprietary ATM | ||||
| A00000000401 MasterCard PayPass | ||||
| A0000000041010 MasterCard Global | ||||
| A00000000410101213 MasterCard Credit | ||||
| A00000000410101215 MasterCard Credit | ||||
| A0000000042010 MasterCard Specific | ||||
| A0000000043010 MasterCard Specific | ||||
| A0000000043060 Maestro (Debit) | ||||
| A000000004306001 Maestro (Debit) | ||||
| A0000000044010 MasterCard Specific | ||||
| A0000000045010 MasterCard Specific | ||||
| A0000000046000 Cirrus | ||||
| A0000000048002 SecureCode EMV-CAP | ||||
| A0000000049999 MasterCard PayPass | ||||
| A0000000050001 Maestro UK | ||||
| A0000000050002 Solo | ||||
| A00000002401 Self Service | ||||
| A000000025 American Express | ||||
| A0000000250000 American Express | ||||
| A00000002501 American Express | ||||
| A000000025010402 American Express | ||||
| A000000025010701 ExpressPay | ||||
| A000000025010801 American Express | ||||
| A0000000291010 Link / American Express | ||||
| A0000000421010 Cartes Bancaire EMV Card | ||||
| A0000000426010 Apple Pay | ||||
| A00000006510 JCB | ||||
| A0000000651010 JCB J Smart Credit | ||||
| A00000006900 Moneo | ||||
| A000000077010000021000000000003B Visa AEPN | ||||
| A000000098 Debit Card | ||||
| A0000000980848 Debit Card | ||||
| A0000001211010 Dankort VISA GEM Vision | ||||
| A0000001410001 PagoBANCOMAT | ||||
| A0000001523010 Discover, Pulse D Pas | ||||
| A0000001524010 Discover | ||||
| A0000001544442 Banricompras Debito | ||||
| A000000172950001 BAROC Taiwan | ||||
| A0000002281010 SPAN (M/Chip) | ||||
| A0000002282010 SPAN (VIS) | ||||
| A0000002771010 INTERAC | ||||
| A00000031510100528 Currence PuC | ||||
| A0000003156020 Chipknip | ||||
| A0000003591010028001 Girocard EAPS | ||||
| A0000003710001 InterSwitch Verve Card | ||||
| A0000004540010 Etranzact Genesis Card | ||||
| A0000004540011 Etranzact Genesis Card 2 | ||||
| A0000004766C GOOGLE_PAYMENT | ||||
| A0000005241010 RuPay | ||||
| A0000006723010 TROY chip credit card | ||||
| A0000006723020 TROY chip debit card | ||||
| A0000007705850 XTRAPOWER | ||||
| B012345678 Maestro TEST | ||||
| D27600002545500100 Girocard | ||||
| D5780000021010 Bankaxept | ||||
| F0000000030001 BRADESCO | ||||
| A000000003000000 (VISA) Card Manager | ||||
| A000000003534441 Schlumberger SD | ||||
| A0000000035350 Security Domain | ||||
| A000000003535041 Security Domain | ||||
| A0000000040000 MasterCard Card Manager | ||||
| A000000018434D Gemplus card manager | ||||
| A000000018434D00 Gemplus Security Domain | ||||
| A0000000960200 Proton WISD | ||||
| A0000001510000 Global Platform SD | ||||
| A00000015153504341534400 CASD_AID | ||||
| A000000476A010 GSD_MANAGER_AID | ||||
| A000000476A110 GSD_MANAGER_AID | ||||
| 315041592E5359532E4444463031 Visa PSE  | ||||
| 325041592E5359532E4444463031 Visa PPSE | ||||
| A0000000042203 MasterCard Specific | ||||
| A0000000045555 APDULogger | ||||
| A0000000090001FF44FF1289 Orange | ||||
| A0000000101030 Maestro-CH | ||||
| A00000001800 Gemplus | ||||
| A0000000181001 gemplus util packages | ||||
| A000000025010104 American Express | ||||
| A00000002949034010100001 HSBC | ||||
| A00000002949282010100000 Barclay | ||||
| A00000005945430100 Girocard Electronic Cash | ||||
| A0000000980840 Visa Common Debit | ||||
| A0000001570010 AMEX | ||||
| A0000001570020 MasterCard | ||||
| A0000001570021 Maestro | ||||
| A0000001570022 Maestro | ||||
| A0000001570023 CASH | ||||
| A0000001570030 VISA | ||||
| A0000001570031 VISA | ||||
| A0000001570040 JCB | ||||
| A0000001570050 Postcard | ||||
| A0000001570051 Postcard | ||||
| A0000001570100 MCard | ||||
| A0000001570104 MyOne | ||||
| A000000157010C WIRCard | ||||
| A000000157010D Power Card | ||||
| A0000001574443 DINERS CLUB | ||||
| A0000001574444 Supercard Plus | ||||
| A00000022820101010 SPAN | ||||
| A000000308000010000100 ID-ONE PIV BIO | ||||
| A0000003241010 Discover Zip | ||||
| A000000333010101 UnionPay Debit | ||||
| A000000333010102 UnionPay Credit | ||||
| A000000333010103 UnionPay Quasi Credit | ||||
| A000000333010106 UnionPay Electronic Cash | ||||
| A000000333010108 U.S. UnionPay Common Debit | ||||
| A000000337102000 Classic | ||||
| A000000337101001 Prepaye Online | ||||
| A000000337102001 Prepaye Possibile Offiline | ||||
| A000000337601001 Porte Monnaie Electronique | ||||
| A0000006581010 MIR Credit | ||||
| A0000006581011 MIR Credit | ||||
| A0000006582010 MIR Debit | ||||
| D040000001000002 Paylife Quick IEP | ||||
| D040000002000002 RFU | ||||
| D040000003000002 POS | ||||
| D040000004000002 ATM | ||||
| D04000000B000002 Retail | ||||
| D04000000C000002 Bank_Data | ||||
| D04000000D000002 Shopping | ||||
| D040000013000001 DF_UNI_Kepler1 | ||||
| D040000013000001 DF_Schüler1 | ||||
| D040000013000002 DF_UNI_Kepler2 | ||||
| D040000013000002 DF_Schüler2 | ||||
| D040000014000001 DF_Mensa | ||||
| D040000015000001 DF_UNI_Ausweis | ||||
| D040000015000001 DF_Ausweis | ||||
| D0400000190001 EMV ATM Maestro | ||||
| D0400000190002 EMV POS Maestro | ||||
| D0400000190003 EMV ATM MasterCard | ||||
| D0400000190004 EMV POS MasterCard | ||||
| D276000025 Girocard | ||||
| D27600002547410100 Girocard ATM | ||||
| D7560000010101 Reka Card | ||||
| D7560000300101 M Budget | ||||
| Filetype: Flipper EMV resources | ||||
| Version: 1 | ||||
| # EMV Application ID code: Application ID name | ||||
| A00000000305076010: VISA ELO Credit | ||||
| A0000000031010: VISA Debit/Credit (Classic) | ||||
| A000000003101001: VISA Credit | ||||
| A000000003101002: VISA Debit | ||||
| A0000000032010: VISA Electron | ||||
| A0000000032020: VISA | ||||
| A0000000033010: VISA Interlink | ||||
| A0000000034010: VISA Specific | ||||
| A0000000035010: VISA Specific | ||||
| A0000000036010: Domestic Visa Cash | ||||
| A0000000036020: International Visa Cash | ||||
| A0000000038002: VISA Auth EMV-CAP (DPA) | ||||
| A0000000038010: VISA Plus | ||||
| A0000000039010: VISA Loyalty | ||||
| A000000003999910: VISA Proprietary ATM | ||||
| A00000000401: MasterCard PayPass | ||||
| A0000000041010: MasterCard Global | ||||
| A00000000410101213: MasterCard Credit | ||||
| A00000000410101215: MasterCard Credit | ||||
| A0000000042010: MasterCard Specific | ||||
| A0000000043010: MasterCard Specific | ||||
| A0000000043060: Maestro (Debit) | ||||
| A000000004306001: Maestro (Debit) | ||||
| A0000000044010: MasterCard Specific | ||||
| A0000000045010: MasterCard Specific | ||||
| A0000000046000: Cirrus | ||||
| A0000000048002: SecureCode EMV-CAP | ||||
| A0000000049999: MasterCard PayPass | ||||
| A0000000050001: Maestro UK | ||||
| A0000000050002: Solo | ||||
| A00000002401: Self Service | ||||
| A000000025: American Express | ||||
| A0000000250000: American Express | ||||
| A00000002501: American Express | ||||
| A000000025010402: American Express | ||||
| A000000025010701: ExpressPay | ||||
| A000000025010801: American Express | ||||
| A0000000291010: Link / American Express | ||||
| A0000000421010: Cartes Bancaire EMV Card | ||||
| A0000000426010: Apple Pay | ||||
| A00000006510: JCB | ||||
| A0000000651010: JCB J Smart Credit | ||||
| A00000006900: Moneo | ||||
| A000000077010000021000000000003B: Visa AEPN | ||||
| A000000098: Debit Card | ||||
| A0000000980848: Debit Card | ||||
| A0000001211010: Dankort VISA GEM Vision | ||||
| A0000001410001: PagoBANCOMAT | ||||
| A0000001523010: Discover, Pulse D Pas | ||||
| A0000001524010: Discover | ||||
| A0000001544442: Banricompras Debito | ||||
| A000000172950001: BAROC Taiwan | ||||
| A0000002281010: SPAN (M/Chip) | ||||
| A0000002282010: SPAN (VIS) | ||||
| A0000002771010: INTERAC | ||||
| A00000031510100528: Currence PuC | ||||
| A0000003156020: Chipknip | ||||
| A0000003591010028001: Girocard EAPS | ||||
| A0000003710001: InterSwitch Verve Card | ||||
| A0000004540010: Etranzact Genesis Card | ||||
| A0000004540011: Etranzact Genesis Card 2 | ||||
| A0000004766C: GOOGLE_PAYMENT | ||||
| A0000005241010: RuPay | ||||
| A0000006723010: TROY chip credit card | ||||
| A0000006723020: TROY chip debit card | ||||
| A0000007705850: XTRAPOWER | ||||
| B012345678: Maestro TEST | ||||
| D27600002545500100: Girocard | ||||
| D5780000021010: Bankaxept | ||||
| F0000000030001: BRADESCO | ||||
| A000000003000000: (VISA) Card Manager | ||||
| A000000003534441: Schlumberger SD | ||||
| A0000000035350: Security Domain | ||||
| A000000003535041: Security Domain | ||||
| A0000000040000: MasterCard Card Manager | ||||
| A000000018434D: Gemplus card manager | ||||
| A000000018434D00: Gemplus Security Domain | ||||
| A0000000960200: Proton WISD | ||||
| A0000001510000: Global Platform SD | ||||
| A00000015153504341534400: CASD_AID | ||||
| A000000476A010: GSD_MANAGER_AID | ||||
| A000000476A110: GSD_MANAGER_AID | ||||
| 315041592E5359532E4444463031: Visa PSE  | ||||
| 325041592E5359532E4444463031: Visa PPSE | ||||
| A0000000042203: MasterCard Specific | ||||
| A0000000045555: APDULogger | ||||
| A0000000090001FF44FF1289: Orange | ||||
| A0000000101030: Maestro-CH | ||||
| A00000001800: Gemplus | ||||
| A0000000181001: gemplus util packages | ||||
| A000000025010104: American Express | ||||
| A00000002949034010100001: HSBC | ||||
| A00000002949282010100000: Barclay | ||||
| A00000005945430100: Girocard Electronic Cash | ||||
| A0000000980840: Visa Common Debit | ||||
| A0000001570010: AMEX | ||||
| A0000001570020: MasterCard | ||||
| A0000001570021: Maestro | ||||
| A0000001570022: Maestro | ||||
| A0000001570023: CASH | ||||
| A0000001570030: VISA | ||||
| A0000001570031: VISA | ||||
| A0000001570040: JCB | ||||
| A0000001570050: Postcard | ||||
| A0000001570051: Postcard | ||||
| A0000001570100: MCard | ||||
| A0000001570104: MyOne | ||||
| A000000157010C: WIRCard | ||||
| A000000157010D: Power Card | ||||
| A0000001574443: DINERS CLUB | ||||
| A0000001574444: Supercard Plus | ||||
| A00000022820101010: SPAN | ||||
| A000000308000010000100: ID-ONE PIV BIO | ||||
| A0000003241010: Discover Zip | ||||
| A000000333010101: UnionPay Debit | ||||
| A000000333010102: UnionPay Credit | ||||
| A000000333010103: UnionPay Quasi Credit | ||||
| A000000333010106: UnionPay Electronic Cash | ||||
| A000000333010108: U.S. UnionPay Common Debit | ||||
| A000000337102000: Classic | ||||
| A000000337101001: Prepaye Online | ||||
| A000000337102001: Prepaye Possibile Offiline | ||||
| A000000337601001: Porte Monnaie Electronique | ||||
| A0000006581010: MIR Credit | ||||
| A0000006581011: MIR Credit | ||||
| A0000006582010: MIR Debit | ||||
| D040000001000002: Paylife Quick IEP | ||||
| D040000002000002: RFU | ||||
| D040000003000002: POS | ||||
| D040000004000002: ATM | ||||
| D04000000B000002: Retail | ||||
| D04000000C000002: Bank_Data | ||||
| D04000000D000002: Shopping | ||||
| D040000013000001: DF_UNI_Kepler1 | ||||
| D040000013000001: DF_Schüler1 | ||||
| D040000013000002: DF_UNI_Kepler2 | ||||
| D040000013000002: DF_Schüler2 | ||||
| D040000014000001: DF_Mensa | ||||
| D040000015000001: DF_UNI_Ausweis | ||||
| D040000015000001: DF_Ausweis | ||||
| D0400000190001: EMV ATM Maestro | ||||
| D0400000190002: EMV POS Maestro | ||||
| D0400000190003: EMV ATM MasterCard | ||||
| D0400000190004: EMV POS MasterCard | ||||
| D276000025: Girocard | ||||
| D27600002547410100: Girocard ATM | ||||
| D7560000010101: Reka Card | ||||
| D7560000300101: M Budget | ||||
| @ -1,249 +1,252 @@ | ||||
| 0004 AFG | ||||
| 0008 ALB | ||||
| 0010 ATA | ||||
| 0012 DZA | ||||
| 0016 ASM | ||||
| 0020 AND | ||||
| 0024 AGO | ||||
| 0028 ATG | ||||
| 0031 AZE | ||||
| 0032 ARG | ||||
| 0036 AUS | ||||
| 0040 AUT | ||||
| 0044 BHS | ||||
| 0048 BHR | ||||
| 0050 BGD | ||||
| 0051 ARM | ||||
| 0052 BRB | ||||
| 0056 BEL | ||||
| 0060 BMU | ||||
| 0064 BTN | ||||
| 0068 BOL | ||||
| 0070 BIH | ||||
| 0072 BWA | ||||
| 0074 BVT | ||||
| 0076 BRA | ||||
| 0084 BLZ | ||||
| 0086 IOT | ||||
| 0090 SLB | ||||
| 0092 VGB | ||||
| 0096 BRN | ||||
| 0100 BGR | ||||
| 0104 MMR | ||||
| 0108 BDI | ||||
| 0112 BLR | ||||
| 0116 KHM | ||||
| 0120 CMR | ||||
| 0124 CAN | ||||
| 0132 CPV | ||||
| 0136 CYM | ||||
| 0140 CAF | ||||
| 0144 LKA | ||||
| 0148 TCD | ||||
| 0152 CHL | ||||
| 0156 CHN | ||||
| 0158 TWN | ||||
| 0162 CXR | ||||
| 0166 CCK | ||||
| 0170 COL | ||||
| 0174 COM | ||||
| 0175 MYT | ||||
| 0178 COG | ||||
| 0180 COD | ||||
| 0184 COK | ||||
| 0188 CRI | ||||
| 0191 HRV | ||||
| 0192 CUB | ||||
| 0196 CYP | ||||
| 0203 CZE | ||||
| 0204 BEN | ||||
| 0208 DNK | ||||
| 0212 DMA | ||||
| 0214 DOM | ||||
| 0218 ECU | ||||
| 0222 SLV | ||||
| 0226 GNQ | ||||
| 0231 ETH | ||||
| 0232 ERI | ||||
| 0233 EST | ||||
| 0234 FRO | ||||
| 0238 FLK | ||||
| 0239 SGS | ||||
| 0242 FJI | ||||
| 0246 FIN | ||||
| 0248 ALA | ||||
| 0250 FRA | ||||
| 0254 GUF | ||||
| 0258 PYF | ||||
| 0260 ATF | ||||
| 0262 DJI | ||||
| 0266 GAB | ||||
| 0268 GEO | ||||
| 0270 GMB | ||||
| 0275 PSE | ||||
| 0276 DEU | ||||
| 0288 GHA | ||||
| 0292 GIB | ||||
| 0296 KIR | ||||
| 0300 GRC | ||||
| 0304 GRL | ||||
| 0308 GRD | ||||
| 0312 GLP | ||||
| 0316 GUM | ||||
| 0320 GTM | ||||
| 0324 GIN | ||||
| 0328 GUY | ||||
| 0332 HTI | ||||
| 0334 HMD | ||||
| 0336 VAT | ||||
| 0340 HND | ||||
| 0344 HKG | ||||
| 0348 HUN | ||||
| 0352 ISL | ||||
| 0356 IND | ||||
| 0360 IDN | ||||
| 0364 IRN | ||||
| 0368 IRQ | ||||
| 0372 IRL | ||||
| 0376 ISR | ||||
| 0380 ITA | ||||
| 0384 CIV | ||||
| 0388 JAM | ||||
| 0392 JPN | ||||
| 0398 KAZ | ||||
| 0400 JOR | ||||
| 0404 KEN | ||||
| 0408 PRK | ||||
| 0410 KOR | ||||
| 0414 KWT | ||||
| 0417 KGZ | ||||
| 0418 LAO | ||||
| 0422 LBN | ||||
| 0426 LSO | ||||
| 0428 LVA | ||||
| 0430 LBR | ||||
| 0434 LBY | ||||
| 0438 LIE | ||||
| 0440 LTU | ||||
| 0442 LUX | ||||
| 0446 MAC | ||||
| 0450 MDG | ||||
| 0454 MWI | ||||
| 0458 MYS | ||||
| 0462 MDV | ||||
| 0466 MLI | ||||
| 0470 MLT | ||||
| 0474 MTQ | ||||
| 0478 MRT | ||||
| 0480 MUS | ||||
| 0484 MEX | ||||
| 0492 MCO | ||||
| 0496 MNG | ||||
| 0498 MDA | ||||
| 0499 MNE | ||||
| 0500 MSR | ||||
| 0504 MAR | ||||
| 0508 MOZ | ||||
| 0512 OMN | ||||
| 0516 NAM | ||||
| 0520 NRU | ||||
| 0524 NPL | ||||
| 0528 NLD | ||||
| 0531 CUW | ||||
| 0533 ABW | ||||
| 0534 SXM | ||||
| 0535 BES | ||||
| 0540 NCL | ||||
| 0548 VUT | ||||
| 0554 NZL | ||||
| 0558 NIC | ||||
| 0562 NER | ||||
| 0566 NGA | ||||
| 0570 NIU | ||||
| 0574 NFK | ||||
| 0578 NOR | ||||
| 0580 MNP | ||||
| 0581 UMI | ||||
| 0583 FSM | ||||
| 0584 MHL | ||||
| 0585 PLW | ||||
| 0586 PAK | ||||
| 0591 PAN | ||||
| 0598 PNG | ||||
| 0600 PRY | ||||
| 0604 PER | ||||
| 0608 PHL | ||||
| 0612 PCN | ||||
| 0616 POL | ||||
| 0620 PRT | ||||
| 0624 GNB | ||||
| 0626 TLS | ||||
| 0630 PRI | ||||
| 0634 QAT | ||||
| 0638 REU | ||||
| 0642 ROU | ||||
| 0643 RUS | ||||
| 0646 RWA | ||||
| 0652 BLM | ||||
| 0654 SHN | ||||
| 0659 KNA | ||||
| 0660 AIA | ||||
| 0662 LCA | ||||
| 0663 MAF | ||||
| 0666 SPM | ||||
| 0670 VCT | ||||
| 0674 SMR | ||||
| 0678 STP | ||||
| 0682 SAU | ||||
| 0686 SEN | ||||
| 0688 SRB | ||||
| 0690 SYC | ||||
| 0694 SLE | ||||
| 0702 SGP | ||||
| 0703 SVK | ||||
| 0704 VNM | ||||
| 0705 SVN | ||||
| 0706 SOM | ||||
| 0710 ZAF | ||||
| 0716 ZWE | ||||
| 0724 ESP | ||||
| 0728 SSD | ||||
| 0729 SDN | ||||
| 0732 ESH | ||||
| 0740 SUR | ||||
| 0744 SJM | ||||
| 0748 SWZ | ||||
| 0752 SWE | ||||
| 0756 CHE | ||||
| 0760 SYR | ||||
| 0762 TJK | ||||
| 0764 THA | ||||
| 0768 TGO | ||||
| 0772 TKL | ||||
| 0776 TON | ||||
| 0780 TTO | ||||
| 0784 ARE | ||||
| 0788 TUN | ||||
| 0792 TUR | ||||
| 0795 TKM | ||||
| 0796 TCA | ||||
| 0798 TUV | ||||
| 0800 UGA | ||||
| 0804 UKR | ||||
| 0807 MKD | ||||
| 0818 EGY | ||||
| 0826 GBR | ||||
| 0831 GGY | ||||
| 0832 JEY | ||||
| 0833 IMN | ||||
| 0834 TZA | ||||
| 0840 USA | ||||
| 0850 VIR | ||||
| 0854 BFA | ||||
| 0858 URY | ||||
| 0860 UZB | ||||
| 0862 VEN | ||||
| 0876 WLF | ||||
| 0882 WSM | ||||
| 0887 YEM | ||||
| 0894 ZMB | ||||
| Filetype: Flipper EMV resources | ||||
| Version: 1 | ||||
| # EMV country code: country name | ||||
| 0004: AFG | ||||
| 0008: ALB | ||||
| 0010: ATA | ||||
| 0012: DZA | ||||
| 0016: ASM | ||||
| 0020: AND | ||||
| 0024: AGO | ||||
| 0028: ATG | ||||
| 0031: AZE | ||||
| 0032: ARG | ||||
| 0036: AUS | ||||
| 0040: AUT | ||||
| 0044: BHS | ||||
| 0048: BHR | ||||
| 0050: BGD | ||||
| 0051: ARM | ||||
| 0052: BRB | ||||
| 0056: BEL | ||||
| 0060: BMU | ||||
| 0064: BTN | ||||
| 0068: BOL | ||||
| 0070: BIH | ||||
| 0072: BWA | ||||
| 0074: BVT | ||||
| 0076: BRA | ||||
| 0084: BLZ | ||||
| 0086: IOT | ||||
| 0090: SLB | ||||
| 0092: VGB | ||||
| 0096: BRN | ||||
| 0100: BGR | ||||
| 0104: MMR | ||||
| 0108: BDI | ||||
| 0112: BLR | ||||
| 0116: KHM | ||||
| 0120: CMR | ||||
| 0124: CAN | ||||
| 0132: CPV | ||||
| 0136: CYM | ||||
| 0140: CAF | ||||
| 0144: LKA | ||||
| 0148: TCD | ||||
| 0152: CHL | ||||
| 0156: CHN | ||||
| 0158: TWN | ||||
| 0162: CXR | ||||
| 0166: CCK | ||||
| 0170: COL | ||||
| 0174: COM | ||||
| 0175: MYT | ||||
| 0178: COG | ||||
| 0180: COD | ||||
| 0184: COK | ||||
| 0188: CRI | ||||
| 0191: HRV | ||||
| 0192: CUB | ||||
| 0196: CYP | ||||
| 0203: CZE | ||||
| 0204: BEN | ||||
| 0208: DNK | ||||
| 0212: DMA | ||||
| 0214: DOM | ||||
| 0218: ECU | ||||
| 0222: SLV | ||||
| 0226: GNQ | ||||
| 0231: ETH | ||||
| 0232: ERI | ||||
| 0233: EST | ||||
| 0234: FRO | ||||
| 0238: FLK | ||||
| 0239: SGS | ||||
| 0242: FJI | ||||
| 0246: FIN | ||||
| 0248: ALA | ||||
| 0250: FRA | ||||
| 0254: GUF | ||||
| 0258: PYF | ||||
| 0260: ATF | ||||
| 0262: DJI | ||||
| 0266: GAB | ||||
| 0268: GEO | ||||
| 0270: GMB | ||||
| 0275: PSE | ||||
| 0276: DEU | ||||
| 0288: GHA | ||||
| 0292: GIB | ||||
| 0296: KIR | ||||
| 0300: GRC | ||||
| 0304: GRL | ||||
| 0308: GRD | ||||
| 0312: GLP | ||||
| 0316: GUM | ||||
| 0320: GTM | ||||
| 0324: GIN | ||||
| 0328: GUY | ||||
| 0332: HTI | ||||
| 0334: HMD | ||||
| 0336: VAT | ||||
| 0340: HND | ||||
| 0344: HKG | ||||
| 0348: HUN | ||||
| 0352: ISL | ||||
| 0356: IND | ||||
| 0360: IDN | ||||
| 0364: IRN | ||||
| 0368: IRQ | ||||
| 0372: IRL | ||||
| 0376: ISR | ||||
| 0380: ITA | ||||
| 0384: CIV | ||||
| 0388: JAM | ||||
| 0392: JPN | ||||
| 0398: KAZ | ||||
| 0400: JOR | ||||
| 0404: KEN | ||||
| 0408: PRK | ||||
| 0410: KOR | ||||
| 0414: KWT | ||||
| 0417: KGZ | ||||
| 0418: LAO | ||||
| 0422: LBN | ||||
| 0426: LSO | ||||
| 0428: LVA | ||||
| 0430: LBR | ||||
| 0434: LBY | ||||
| 0438: LIE | ||||
| 0440: LTU | ||||
| 0442: LUX | ||||
| 0446: MAC | ||||
| 0450: MDG | ||||
| 0454: MWI | ||||
| 0458: MYS | ||||
| 0462: MDV | ||||
| 0466: MLI | ||||
| 0470: MLT | ||||
| 0474: MTQ | ||||
| 0478: MRT | ||||
| 0480: MUS | ||||
| 0484: MEX | ||||
| 0492: MCO | ||||
| 0496: MNG | ||||
| 0498: MDA | ||||
| 0499: MNE | ||||
| 0500: MSR | ||||
| 0504: MAR | ||||
| 0508: MOZ | ||||
| 0512: OMN | ||||
| 0516: NAM | ||||
| 0520: NRU | ||||
| 0524: NPL | ||||
| 0528: NLD | ||||
| 0531: CUW | ||||
| 0533: ABW | ||||
| 0534: SXM | ||||
| 0535: BES | ||||
| 0540: NCL | ||||
| 0548: VUT | ||||
| 0554: NZL | ||||
| 0558: NIC | ||||
| 0562: NER | ||||
| 0566: NGA | ||||
| 0570: NIU | ||||
| 0574: NFK | ||||
| 0578: NOR | ||||
| 0580: MNP | ||||
| 0581: UMI | ||||
| 0583: FSM | ||||
| 0584: MHL | ||||
| 0585: PLW | ||||
| 0586: PAK | ||||
| 0591: PAN | ||||
| 0598: PNG | ||||
| 0600: PRY | ||||
| 0604: PER | ||||
| 0608: PHL | ||||
| 0612: PCN | ||||
| 0616: POL | ||||
| 0620: PRT | ||||
| 0624: GNB | ||||
| 0626: TLS | ||||
| 0630: PRI | ||||
| 0634: QAT | ||||
| 0638: REU | ||||
| 0642: ROU | ||||
| 0643: RUS | ||||
| 0646: RWA | ||||
| 0652: BLM | ||||
| 0654: SHN | ||||
| 0659: KNA | ||||
| 0660: AIA | ||||
| 0662: LCA | ||||
| 0663: MAF | ||||
| 0666: SPM | ||||
| 0670: VCT | ||||
| 0674: SMR | ||||
| 0678: STP | ||||
| 0682: SAU | ||||
| 0686: SEN | ||||
| 0688: SRB | ||||
| 0690: SYC | ||||
| 0694: SLE | ||||
| 0702: SGP | ||||
| 0703: SVK | ||||
| 0704: VNM | ||||
| 0705: SVN | ||||
| 0706: SOM | ||||
| 0710: ZAF | ||||
| 0716: ZWE | ||||
| 0724: ESP | ||||
| 0728: SSD | ||||
| 0729: SDN | ||||
| 0732: ESH | ||||
| 0740: SUR | ||||
| 0744: SJM | ||||
| 0748: SWZ | ||||
| 0752: SWE | ||||
| 0756: CHE | ||||
| 0760: SYR | ||||
| 0762: TJK | ||||
| 0764: THA | ||||
| 0768: TGO | ||||
| 0772: TKL | ||||
| 0776: TON | ||||
| 0780: TTO | ||||
| 0784: ARE | ||||
| 0788: TUN | ||||
| 0792: TUR | ||||
| 0795: TKM | ||||
| 0796: TCA | ||||
| 0798: TUV | ||||
| 0800: UGA | ||||
| 0804: UKR | ||||
| 0807: MKD | ||||
| 0818: EGY | ||||
| 0826: GBR | ||||
| 0831: GGY | ||||
| 0832: JEY | ||||
| 0833: IMN | ||||
| 0834: TZA | ||||
| 0840: USA | ||||
| 0850: VIR | ||||
| 0854: BFA | ||||
| 0858: URY | ||||
| 0860: UZB | ||||
| 0862: VEN | ||||
| 0876: WLF | ||||
| 0882: WSM | ||||
| 0887: YEM | ||||
| 0894: ZMB | ||||
| @ -1,168 +1,171 @@ | ||||
| 0997 USN | ||||
| 0994 XSU | ||||
| 0990 CLF | ||||
| 0986 BRL | ||||
| 0985 PLN | ||||
| 0984 BOV | ||||
| 0981 GEL | ||||
| 0980 UAH | ||||
| 0979 MXV | ||||
| 0978 EUR | ||||
| 0977 BAM | ||||
| 0976 CDF | ||||
| 0975 BGN | ||||
| 0973 AOA | ||||
| 0972 TJS | ||||
| 0971 AFN | ||||
| 0970 COU | ||||
| 0969 MGA | ||||
| 0968 SRD | ||||
| 0967 ZMW | ||||
| 0965 XUA | ||||
| 0960 XDR | ||||
| 0953 XPF | ||||
| 0952 XOF | ||||
| 0951 XCD | ||||
| 0950 XAF | ||||
| 0949 TRY | ||||
| 0948 CHW | ||||
| 0947 CHE | ||||
| 0946 RON | ||||
| 0944 AZN | ||||
| 0943 MZN | ||||
| 0941 RSD | ||||
| 0940 UYI | ||||
| 0938 SDG | ||||
| 0937 VEF | ||||
| 0936 GHS | ||||
| 0934 TMT | ||||
| 0933 BYN | ||||
| 0932 ZWL | ||||
| 0931 CUC | ||||
| 0930 STN | ||||
| 0929 MRU | ||||
| 0901 TWD | ||||
| 0886 YER | ||||
| 0882 WST | ||||
| 0860 UZS | ||||
| 0858 UYU | ||||
| 0840 USD | ||||
| 0834 TZS | ||||
| 0826 GBP | ||||
| 0818 EGP | ||||
| 0807 MKD | ||||
| 0800 UGX | ||||
| 0788 TND | ||||
| 0784 AED | ||||
| 0780 TTD | ||||
| 0776 TOP | ||||
| 0764 THB | ||||
| 0760 SYP | ||||
| 0756 CHF | ||||
| 0752 SEK | ||||
| 0748 SZL | ||||
| 0728 SSP | ||||
| 0710 ZAR | ||||
| 0706 SOS | ||||
| 0704 VND | ||||
| 0702 SGD | ||||
| 0694 SLL | ||||
| 0690 SCR | ||||
| 0682 SAR | ||||
| 0654 SHP | ||||
| 0646 RWF | ||||
| 0643 RUB | ||||
| 0634 QAR | ||||
| 0608 PHP | ||||
| 0604 PEN | ||||
| 0600 PYG | ||||
| 0598 PGK | ||||
| 0590 PAB | ||||
| 0586 PKR | ||||
| 0578 NOK | ||||
| 0566 NGN | ||||
| 0558 NIO | ||||
| 0554 NZD | ||||
| 0548 VUV | ||||
| 0533 AWG | ||||
| 0532 ANG | ||||
| 0524 NPR | ||||
| 0516 NAD | ||||
| 0512 OMR | ||||
| 0504 MAD | ||||
| 0498 MDL | ||||
| 0496 MNT | ||||
| 0484 MXN | ||||
| 0480 MUR | ||||
| 0462 MVR | ||||
| 0458 MYR | ||||
| 0454 MWK | ||||
| 0446 MOP | ||||
| 0434 LYD | ||||
| 0430 LRD | ||||
| 0426 LSL | ||||
| 0422 LBP | ||||
| 0418 LAK | ||||
| 0417 KGS | ||||
| 0414 KWD | ||||
| 0410 KRW | ||||
| 0408 KPW | ||||
| 0404 KES | ||||
| 0400 JOD | ||||
| 0398 KZT | ||||
| 0392 JPY | ||||
| 0388 JMD | ||||
| 0376 ILS | ||||
| 0368 IQD | ||||
| 0364 IRR | ||||
| 0360 IDR | ||||
| 0356 INR | ||||
| 0352 ISK | ||||
| 0348 HUF | ||||
| 0344 HKD | ||||
| 0340 HNL | ||||
| 0332 HTG | ||||
| 0328 GYD | ||||
| 0324 GNF | ||||
| 0320 GTQ | ||||
| 0292 GIP | ||||
| 0270 GMD | ||||
| 0262 DJF | ||||
| 0242 FJD | ||||
| 0238 FKP | ||||
| 0232 ERN | ||||
| 0230 ETB | ||||
| 0222 SVC | ||||
| 0214 DOP | ||||
| 0208 DKK | ||||
| 0203 CZK | ||||
| 0192 CUP | ||||
| 0191 HRK | ||||
| 0188 CRC | ||||
| 0174 KMF | ||||
| 0170 COP | ||||
| 0156 CNY | ||||
| 0152 CLP | ||||
| 0144 LKR | ||||
| 0136 KYD | ||||
| 0132 CVE | ||||
| 0124 CAD | ||||
| 0116 KHR | ||||
| 0108 BIF | ||||
| 0104 MMK | ||||
| 0096 BND | ||||
| 0090 SBD | ||||
| 0084 BZD | ||||
| 0072 BWP | ||||
| 0068 BOB | ||||
| 0064 BTN | ||||
| 0060 BMD | ||||
| 0052 BBD | ||||
| 0051 AMD | ||||
| 0050 BDT | ||||
| 0048 BHD | ||||
| 0044 BSD | ||||
| 0036 AUD | ||||
| 0032 ARS | ||||
| 0012 DZD | ||||
| 0008 ALL | ||||
| Filetype: Flipper EMV resources | ||||
| Version: 1 | ||||
| # EMV currency code: currency name | ||||
| 0997: USN | ||||
| 0994: XSU | ||||
| 0990: CLF | ||||
| 0986: BRL | ||||
| 0985: PLN | ||||
| 0984: BOV | ||||
| 0981: GEL | ||||
| 0980: UAH | ||||
| 0979: MXV | ||||
| 0978: EUR | ||||
| 0977: BAM | ||||
| 0976: CDF | ||||
| 0975: BGN | ||||
| 0973: AOA | ||||
| 0972: TJS | ||||
| 0971: AFN | ||||
| 0970: COU | ||||
| 0969: MGA | ||||
| 0968: SRD | ||||
| 0967: ZMW | ||||
| 0965: XUA | ||||
| 0960: XDR | ||||
| 0953: XPF | ||||
| 0952: XOF | ||||
| 0951: XCD | ||||
| 0950: XAF | ||||
| 0949: TRY | ||||
| 0948: CHW | ||||
| 0947: CHE | ||||
| 0946: RON | ||||
| 0944: AZN | ||||
| 0943: MZN | ||||
| 0941: RSD | ||||
| 0940: UYI | ||||
| 0938: SDG | ||||
| 0937: VEF | ||||
| 0936: GHS | ||||
| 0934: TMT | ||||
| 0933: BYN | ||||
| 0932: ZWL | ||||
| 0931: CUC | ||||
| 0930: STN | ||||
| 0929: MRU | ||||
| 0901: TWD | ||||
| 0886: YER | ||||
| 0882: WST | ||||
| 0860: UZS | ||||
| 0858: UYU | ||||
| 0840: USD | ||||
| 0834: TZS | ||||
| 0826: GBP | ||||
| 0818: EGP | ||||
| 0807: MKD | ||||
| 0800: UGX | ||||
| 0788: TND | ||||
| 0784: AED | ||||
| 0780: TTD | ||||
| 0776: TOP | ||||
| 0764: THB | ||||
| 0760: SYP | ||||
| 0756: CHF | ||||
| 0752: SEK | ||||
| 0748: SZL | ||||
| 0728: SSP | ||||
| 0710: ZAR | ||||
| 0706: SOS | ||||
| 0704: VND | ||||
| 0702: SGD | ||||
| 0694: SLL | ||||
| 0690: SCR | ||||
| 0682: SAR | ||||
| 0654: SHP | ||||
| 0646: RWF | ||||
| 0643: RUB | ||||
| 0634: QAR | ||||
| 0608: PHP | ||||
| 0604: PEN | ||||
| 0600: PYG | ||||
| 0598: PGK | ||||
| 0590: PAB | ||||
| 0586: PKR | ||||
| 0578: NOK | ||||
| 0566: NGN | ||||
| 0558: NIO | ||||
| 0554: NZD | ||||
| 0548: VUV | ||||
| 0533: AWG | ||||
| 0532: ANG | ||||
| 0524: NPR | ||||
| 0516: NAD | ||||
| 0512: OMR | ||||
| 0504: MAD | ||||
| 0498: MDL | ||||
| 0496: MNT | ||||
| 0484: MXN | ||||
| 0480: MUR | ||||
| 0462: MVR | ||||
| 0458: MYR | ||||
| 0454: MWK | ||||
| 0446: MOP | ||||
| 0434: LYD | ||||
| 0430: LRD | ||||
| 0426: LSL | ||||
| 0422: LBP | ||||
| 0418: LAK | ||||
| 0417: KGS | ||||
| 0414: KWD | ||||
| 0410: KRW | ||||
| 0408: KPW | ||||
| 0404: KES | ||||
| 0400: JOD | ||||
| 0398: KZT | ||||
| 0392: JPY | ||||
| 0388: JMD | ||||
| 0376: ILS | ||||
| 0368: IQD | ||||
| 0364: IRR | ||||
| 0360: IDR | ||||
| 0356: INR | ||||
| 0352: ISK | ||||
| 0348: HUF | ||||
| 0344: HKD | ||||
| 0340: HNL | ||||
| 0332: HTG | ||||
| 0328: GYD | ||||
| 0324: GNF | ||||
| 0320: GTQ | ||||
| 0292: GIP | ||||
| 0270: GMD | ||||
| 0262: DJF | ||||
| 0242: FJD | ||||
| 0238: FKP | ||||
| 0232: ERN | ||||
| 0230: ETB | ||||
| 0222: SVC | ||||
| 0214: DOP | ||||
| 0208: DKK | ||||
| 0203: CZK | ||||
| 0192: CUP | ||||
| 0191: HRK | ||||
| 0188: CRC | ||||
| 0174: KMF | ||||
| 0170: COP | ||||
| 0156: CNY | ||||
| 0152: CLP | ||||
| 0144: LKR | ||||
| 0136: KYD | ||||
| 0132: CVE | ||||
| 0124: CAD | ||||
| 0116: KHR | ||||
| 0108: BIF | ||||
| 0104: MMK | ||||
| 0096: BND | ||||
| 0090: SBD | ||||
| 0084: BZD | ||||
| 0072: BWP | ||||
| 0068: BOB | ||||
| 0064: BTN | ||||
| 0060: BMD | ||||
| 0052: BBD | ||||
| 0051: AMD | ||||
| 0050: BDT | ||||
| 0048: BHD | ||||
| 0044: BSD | ||||
| 0036: AUD | ||||
| 0032: ARS | ||||
| 0012: DZD | ||||
| 0008: ALL | ||||
| @ -3,10 +3,12 @@ | ||||
| #include <furi.h> | ||||
| #include <furi-hal-version.h> | ||||
| 
 | ||||
| #define TAG "Flipper" | ||||
| 
 | ||||
| static void flipper_print_version(const char* target, const Version* version) { | ||||
|     if(version) { | ||||
|         FURI_LOG_I( | ||||
|             "FLIPPER", | ||||
|             TAG, | ||||
|             "\r\n\t%s version:\t%s\r\n" | ||||
|             "\tBuild date:\t\t%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_gitbranch(version)); | ||||
|     } 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(); | ||||
|     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++) { | ||||
|         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(); | ||||
| 
 | ||||
| @ -45,5 +47,5 @@ void flipper_init() { | ||||
|         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 | ||||
| #define TOSTRING(x) STRINGIFY(x) | ||||
| #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 */ | ||||
| 
 | ||||
| #define configENABLE_FPU                         1 | ||||
| #define configENABLE_MPU                         1 | ||||
| #define configENABLE_MPU                         0 | ||||
| 
 | ||||
| #define configUSE_PREEMPTION                     1 | ||||
| #define configSUPPORT_STATIC_ALLOCATION          0 | ||||
| @ -101,6 +101,9 @@ | ||||
| #define configTIMER_TASK_PRIORITY                ( 2 ) | ||||
| #define configTIMER_QUEUE_LENGTH                 32 | ||||
| #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
 | ||||
| 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 | ||||
|   *        HAL drivers code | ||||
|   */ | ||||
| /* #define USE_FULL_ASSERT    1U */ | ||||
| #define USE_FULL_ASSERT    1U | ||||
| 
 | ||||
| /* ################## SPI peripheral configuration ########################## */ | ||||
| 
 | ||||
| @ -329,17 +329,8 @@ | ||||
| 
 | ||||
| /* Exported macro ------------------------------------------------------------*/ | ||||
| #ifdef  USE_FULL_ASSERT | ||||
| /**
 | ||||
|   * @brief  The assert_param macro is used for function's parameters check. | ||||
|   * @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); | ||||
|   #define assert_param(expr) ((expr) ? (void)0U : assert_failed()) | ||||
|   void assert_failed(); | ||||
| #else | ||||
|   #define assert_param(expr) ((void)0U) | ||||
| #endif /* USE_FULL_ASSERT */ | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| #include "main.h" | ||||
| 
 | ||||
| #include "fatfs/fatfs.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| #include <flipper.h> | ||||
| 
 | ||||
| #define TAG "Main" | ||||
| 
 | ||||
| int main(void) { | ||||
|     // Initialize FURI layer
 | ||||
|     furi_init(); | ||||
| @ -16,13 +16,9 @@ int main(void) { | ||||
|     // Flipper FURI HAL
 | ||||
|     furi_hal_init(); | ||||
| 
 | ||||
|     // 3rd party
 | ||||
|     MX_FATFS_Init(); | ||||
|     FURI_LOG_I("HAL", "FATFS OK"); | ||||
| 
 | ||||
|     // CMSIS initialization
 | ||||
|     osKernelInitialize(); | ||||
|     FURI_LOG_I("HAL", "KERNEL OK"); | ||||
|     FURI_LOG_I(TAG, "KERNEL OK"); | ||||
| 
 | ||||
|     // Init flipper
 | ||||
|     flipper_init(); | ||||
| @ -47,9 +43,6 @@ void Error_Handler(void) { | ||||
|     * @retval None | ||||
|     */ | ||||
| void assert_failed(uint8_t *file, uint32_t line) { | ||||
|     /* USER CODE BEGIN 6 */ | ||||
|     /* 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 */ | ||||
|     furi_crash("HAL assert failed"); | ||||
| } | ||||
| #endif /* USE_FULL_ASSERT */ | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define BATTERY_SERVICE_TAG "battery service" | ||||
| #define TAG "BtBatterySvc" | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint16_t svc_handle; | ||||
| @ -23,7 +23,7 @@ void battery_svc_start() { | ||||
|     // Add Battery service
 | ||||
|     status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc->svc_handle); | ||||
|     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
 | ||||
|     status = aci_gatt_add_char(battery_svc->svc_handle, | ||||
| @ -37,7 +37,7 @@ void battery_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_CONSTANT, | ||||
|                                 &battery_svc->char_level_handle); | ||||
|     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
 | ||||
|         status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->char_level_handle); | ||||
|         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
 | ||||
|         status = aci_gatt_del_service(battery_svc->svc_handle); | ||||
|         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); | ||||
|         battery_svc = NULL; | ||||
| @ -65,14 +65,14 @@ bool battery_svc_update_level(uint8_t battery_charge) { | ||||
|         return false; | ||||
|     } | ||||
|     // 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, | ||||
|                                           battery_svc->char_level_handle, | ||||
|                                           0, | ||||
|                                           1, | ||||
|                                           &battery_charge); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| 
 | ||||
| #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_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_sem = osSemaphoreNew(1, 0, NULL); | ||||
|     // 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_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); | ||||
|     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
 | ||||
| @ -82,7 +82,7 @@ bool ble_app_init() { | ||||
|     }; | ||||
|     status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| @ -10,6 +10,8 @@ | ||||
| #include "app_debug.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)) | ||||
| 
 | ||||
| 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_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 { | ||||
|     osMutexId_t shci_mtx; | ||||
|     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_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) { | ||||
|     furi_assert(ble_glue); | ||||
|     furi_assert(callback); | ||||
| @ -50,7 +55,7 @@ void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback | ||||
| void ble_glue_init() { | ||||
|     ble_glue = furi_alloc(sizeof(BleGlue)); | ||||
|     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; | ||||
| 
 | ||||
|     // 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) { | ||||
|     switch (status) { | ||||
|     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); | ||||
|      | ||||
|     if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) { | ||||
|         if(ble_app_init()) { | ||||
|             FURI_LOG_I("Core2", "BLE stack started"); | ||||
|             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_LOG_I(TAG, "Fus started"); | ||||
|         ble_glue->status = BleGlueStatusFusStarted; | ||||
|         furi_hal_power_insomnia_exit(); | ||||
|     } 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(); | ||||
|     } 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; | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @ -8,17 +9,33 @@ extern "C" { | ||||
| 
 | ||||
| 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(); | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define DEV_INFO_SVC_TAG "dev info service" | ||||
| #define TAG "BtDevInfoSvc" | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint16_t service_handle; | ||||
| @ -29,7 +29,7 @@ void dev_info_svc_start() { | ||||
|     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); | ||||
|     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
 | ||||
| @ -45,7 +45,7 @@ void dev_info_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_CONSTANT, | ||||
|                                 &dev_info_svc->man_name_char_handle); | ||||
|     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; | ||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||
| @ -59,7 +59,7 @@ void dev_info_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_CONSTANT, | ||||
|                                 &dev_info_svc->serial_num_char_handle); | ||||
|     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; | ||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||
| @ -73,7 +73,7 @@ void dev_info_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_CONSTANT, | ||||
|                                 &dev_info_svc->firmware_rev_char_handle); | ||||
|     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; | ||||
|     status = aci_gatt_add_char(dev_info_svc->service_handle, | ||||
| @ -87,7 +87,7 @@ void dev_info_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_CONSTANT, | ||||
|                                 &dev_info_svc->software_rev_char_handle); | ||||
|     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
 | ||||
| @ -97,7 +97,7 @@ void dev_info_svc_start() { | ||||
|                                         strlen(dev_info_man_name), | ||||
|                                         (uint8_t*)dev_info_man_name); | ||||
|     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, | ||||
|                                         dev_info_svc->serial_num_char_handle, | ||||
| @ -105,7 +105,7 @@ void dev_info_svc_start() { | ||||
|                                         strlen(dev_info_serial_num), | ||||
|                                         (uint8_t*)dev_info_serial_num); | ||||
|     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, | ||||
|                                         dev_info_svc->firmware_rev_char_handle, | ||||
| @ -113,7 +113,7 @@ void dev_info_svc_start() { | ||||
|                                         strlen(dev_info_firmware_rev_num), | ||||
|                                         (uint8_t*)dev_info_firmware_rev_num); | ||||
|     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, | ||||
|                                         dev_info_svc->software_rev_char_handle, | ||||
| @ -121,7 +121,7 @@ void dev_info_svc_start() { | ||||
|                                         strlen(dev_info_software_rev_num), | ||||
|                                         (uint8_t*)dev_info_software_rev_num); | ||||
|     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
 | ||||
|         status = aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); | ||||
|         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); | ||||
|         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); | ||||
|         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); | ||||
|         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
 | ||||
|         status = aci_gatt_del_service(dev_info_svc->service_handle); | ||||
|         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); | ||||
|         dev_info_svc = NULL; | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
| 
 | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #define GAP_TAG "BLE" | ||||
| #define TAG "BtGap" | ||||
| 
 | ||||
| #define FAST_ADV_TIMEOUT 30000 | ||||
| #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) { | ||||
|                 gap->gap_svc.connection_handle = 0; | ||||
|                 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) { | ||||
|                 // Restart advertising
 | ||||
| @ -96,28 +96,28 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | ||||
|             meta_evt = (evt_le_meta_event*) event_pckt->data; | ||||
|             switch (meta_evt->subevent) { | ||||
|                 case EVT_LE_CONN_UPDATE_COMPLETE: | ||||
|                 FURI_LOG_D(GAP_TAG, "Connection update event"); | ||||
|                 FURI_LOG_D(TAG, "Connection update event"); | ||||
|                 break; | ||||
| 
 | ||||
|                 case EVT_LE_PHY_UPDATE_COMPLETE: | ||||
|                 evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data; | ||||
|                 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 { | ||||
|                     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); | ||||
|                 if(ret) { | ||||
|                     FURI_LOG_E(GAP_TAG, "Read PHY failed, status: %d", ret); | ||||
|                     FURI_LOG_E(TAG, "Read PHY failed, status: %d", ret); | ||||
|                 } 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; | ||||
| 
 | ||||
|                 case EVT_LE_CONN_COMPLETE: | ||||
|                 furi_hal_power_insomnia_enter(); | ||||
|                 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
 | ||||
|                 osTimerStop(gap->advertise_timer); | ||||
| @ -141,7 +141,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | ||||
|                 aci_gap_pairing_complete_event_rp0 *pairing_complete; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: | ||||
|                 FURI_LOG_I(GAP_TAG, "Limited discoverable event"); | ||||
|                 FURI_LOG_I(TAG, "Limited discoverable event"); | ||||
|                 break; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_PASS_KEY_REQUEST: | ||||
| @ -149,39 +149,39 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | ||||
|                 // Generate random PIN code
 | ||||
|                 uint32_t pin = rand() % 999999; | ||||
|                 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}; | ||||
|                 gap->on_event_cb(event, gap->context); | ||||
|             } | ||||
|                 break; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_AUTHORIZATION_REQUEST: | ||||
|                 FURI_LOG_I(GAP_TAG, "Authorization request event"); | ||||
|                 FURI_LOG_I(TAG, "Authorization request event"); | ||||
|                 break; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED: | ||||
|                 FURI_LOG_I(GAP_TAG, "Slave security initiated"); | ||||
|                 FURI_LOG_I(TAG, "Slave security initiated"); | ||||
|                 break; | ||||
| 
 | ||||
|             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); | ||||
|                 break; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_DEVICE_FOUND: | ||||
|                 FURI_LOG_I(GAP_TAG, "Device found event"); | ||||
|                 FURI_LOG_I(TAG, "Device found event"); | ||||
|                 break; | ||||
| 
 | ||||
|             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; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_KEYPRESS_NOTIFICATION: | ||||
|                 FURI_LOG_I(GAP_TAG, "Key press notification event"); | ||||
|                 FURI_LOG_I(TAG, "Key press notification event"); | ||||
|                 break; | ||||
| 
 | ||||
|             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_confirm_yesno(gap->gap_svc.connection_handle, 1); | ||||
|                 break; | ||||
| @ -189,17 +189,17 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt ) | ||||
|             case EVT_BLUE_GAP_PAIRING_CMPLT: | ||||
|                 pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data; | ||||
|                 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); | ||||
|                 } else { | ||||
|                     FURI_LOG_I(GAP_TAG, "Pairing complete"); | ||||
|                     FURI_LOG_I(TAG, "Pairing complete"); | ||||
|                     BleEvent event = {.type = BleEventTypeConnected}; | ||||
|                     gap->on_event_cb(event, gap->context); | ||||
|                 } | ||||
|                 break; | ||||
| 
 | ||||
|             case EVT_BLUE_GAP_PROCEDURE_COMPLETE: | ||||
|                 FURI_LOG_I(GAP_TAG, "Procedure complete event"); | ||||
|                 FURI_LOG_I(TAG, "Procedure complete event"); | ||||
|                 break; | ||||
|             } | ||||
|             default: | ||||
| @ -286,11 +286,11 @@ static void gap_init_svc(Gap* gap) { | ||||
|     // 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); | ||||
|     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); | ||||
|     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
 | ||||
|     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
 | ||||
|         status = aci_gap_set_non_discoverable(); | ||||
|         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
 | ||||
| @ -331,7 +331,7 @@ static void gap_advertise_start(GapState new_state) | ||||
|                                         strlen(name), (uint8_t*)name, | ||||
|                                         gap->gap_svc.adv_svc_uuid_len, gap->gap_svc.adv_svc_uuid, 0, 0); | ||||
|     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; | ||||
|     BleEvent event = {.type = BleEventTypeStartAdvertising}; | ||||
| @ -355,14 +355,14 @@ static void gap_advertise_stop() { | ||||
| } | ||||
| 
 | ||||
| void gap_start_advertising() { | ||||
|     FURI_LOG_I(GAP_TAG, "Start advertising"); | ||||
|     FURI_LOG_I(TAG, "Start advertising"); | ||||
|     gap->enable_adv = true; | ||||
|     GapCommand command = GapCommandAdvFast; | ||||
|     furi_check(osMessageQueuePut(gap->command_queue, &command, 0, 0) == osOK); | ||||
| } | ||||
| 
 | ||||
| void gap_stop_advertising() { | ||||
|     FURI_LOG_I(GAP_TAG, "Stop advertising"); | ||||
|     FURI_LOG_I(TAG, "Stop advertising"); | ||||
|     gap->enable_adv = false; | ||||
|     GapCommand command = GapCommandAdvStop; | ||||
|     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) { | ||||
|     if (ble_glue_get_status() != BleGlueStatusStarted) { | ||||
|     if (!ble_glue_is_radio_stack_ready()) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| @ -393,7 +393,7 @@ bool gap_init(BleEventCallback on_event_cb, void* context) { | ||||
|     gap->enable_adv = true; | ||||
| 
 | ||||
|     // Thread configuration
 | ||||
|     gap->thread_attr.name = "BLE advertising"; | ||||
|     gap->thread_attr.name = "BleGapWorker"; | ||||
|     gap->thread_attr.stack_size = 1024; | ||||
|     gap->thread_id = osThreadNew(gap_app, NULL, &gap->thread_attr); | ||||
| 
 | ||||
|  | ||||
| @ -4,22 +4,27 @@ | ||||
| 
 | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define SERIAL_SERVICE_TAG "serial service" | ||||
| #define TAG "BtSerialSvc" | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint16_t svc_handle; | ||||
|     uint16_t rx_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; | ||||
|     SerialSvcDataSentCallback on_sent_cb; | ||||
|     void* context; | ||||
| } 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 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_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) { | ||||
|     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) { | ||||
|                 // Descriptor handle
 | ||||
|                 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) { | ||||
|                 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) { | ||||
|                     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; | ||||
|             } | ||||
|         } 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) { | ||||
|                 serial_svc->on_sent_cb(serial_svc->context); | ||||
|             } | ||||
| @ -58,9 +73,9 @@ void serial_svc_start() { | ||||
|     SVCCTL_RegisterSvcHandler(serial_svc_event_handler); | ||||
| 
 | ||||
|     // 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) { | ||||
|         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
 | ||||
| @ -73,7 +88,7 @@ void serial_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_VARIABLE, | ||||
|                                 &serial_svc->rx_char_handle); | ||||
|     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
 | ||||
| @ -86,14 +101,47 @@ void serial_svc_start() { | ||||
|                                 CHAR_VALUE_LEN_VARIABLE, | ||||
|                                 &serial_svc->tx_char_handle); | ||||
|     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_sent_cb = on_sent_cb; | ||||
|     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() { | ||||
| @ -102,17 +150,23 @@ void serial_svc_stop() { | ||||
|         // Delete characteristics
 | ||||
|         status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle); | ||||
|         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); | ||||
|         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
 | ||||
|         status = aci_gatt_del_service(serial_svc->svc_handle); | ||||
|         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); | ||||
|         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) { | ||||
|         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, | ||||
|                                         serial_svc->tx_char_handle, | ||||
|                                         0, | ||||
|                                         data_len, | ||||
|                                         data); | ||||
|     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; | ||||
| } | ||||
|  | ||||
| @ -9,12 +9,14 @@ | ||||
| extern "C" { | ||||
| #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); | ||||
| 
 | ||||
| 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(); | ||||
| 
 | ||||
|  | ||||
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