Merge remote-tracking branch 'origin/dev' into release-candidate

This commit is contained in:
Aleksandr Kutuzov 2022-04-21 19:26:45 +03:00
commit 5435679420
No known key found for this signature in database
GPG Key ID: 0D0011717914BBCD
158 changed files with 2734 additions and 2226 deletions

View File

@ -76,8 +76,8 @@ jobs:
with: with:
run: | run: |
set -e set -e
make -C assets clean make assets_rebuild assets_manifest
make -C assets git diff --quiet || ( echo "Assets recompilation required."; exit 255 )
- name: 'Build the firmware in docker' - name: 'Build the firmware in docker'
uses: ./.github/actions/docker uses: ./.github/actions/docker
@ -117,7 +117,6 @@ jobs:
- name: 'Bundle resources' - name: 'Bundle resources'
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
run: | run: |
./scripts/assets.py manifest assets/resources
tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources
- name: 'Bundle core2 firmware' - name: 'Bundle core2 firmware'

View File

@ -51,6 +51,10 @@ flash: firmware_flash
debug: debug:
@$(MAKE) -C firmware -j$(NPROCS) debug @$(MAKE) -C firmware -j$(NPROCS) debug
.PHONY: debug_other
debug_other:
@$(MAKE) -C firmware -j$(NPROCS) debug_other
.PHONY: blackmagic .PHONY: blackmagic
blackmagic: blackmagic:
@$(MAKE) -C firmware -j$(NPROCS) blackmagic @$(MAKE) -C firmware -j$(NPROCS) blackmagic
@ -75,7 +79,6 @@ ifeq ($(FORCE), 1)
endif endif
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
.PHONY: updater .PHONY: updater
updater: updater:
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all
@ -88,10 +91,22 @@ updater_clean:
updater_debug: updater_debug:
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug
.PHONY: updater_package .PHONY: updater_package_bin
updater_package: firmware_all updater updater_package_bin: firmware_all updater
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)" @$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)"
.PHONY: updater_package
updater_package: firmware_all updater assets_manifest
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) -r $(PROJECT_ROOT)/assets/resources --bundlever "$(VERSION_STRING)"
.PHONY: assets_manifest
assets_manifest:
@$(MAKE) -C $(PROJECT_ROOT)/assets manifest
.PHONY: assets_rebuild
assets_rebuild:
@$(MAKE) -C $(PROJECT_ROOT)/assets clean all
.PHONY: flash_radio .PHONY: flash_radio
flash_radio: flash_radio:
@$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin
@ -110,8 +125,8 @@ flash_radio_fus:
.PHONY: flash_radio_fus_please_i_m_not_going_to_complain .PHONY: flash_radio_fus_please_i_m_not_going_to_complain
flash_radio_fus_please_i_m_not_going_to_complain: flash_radio_fus_please_i_m_not_going_to_complain:
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin
@$(PROJECT_ROOT)/scripts/ob.py set @$(PROJECT_ROOT)/scripts/ob.py set
.PHONY: lint .PHONY: lint

View File

@ -43,6 +43,7 @@ extern int32_t usb_test_app(void* p);
extern int32_t vibro_test_app(void* p); extern int32_t vibro_test_app(void* p);
extern int32_t bt_hid_app(void* p); extern int32_t bt_hid_app(void* p);
extern int32_t battery_test_app(void* p); extern int32_t battery_test_app(void* p);
extern int32_t text_box_test_app(void* p);
// Plugins // Plugins
extern int32_t music_player_app(void* p); extern int32_t music_player_app(void* p);
@ -304,6 +305,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
#ifdef APP_BATTERY_TEST #ifdef APP_BATTERY_TEST
{.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL}, {.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL},
#endif #endif
#ifdef APP_TEXT_BOX_TEST
{.app = text_box_test_app, .name = "Text Box Test", .stack_size = 1024, .icon = NULL},
#endif
}; };
const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS); const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS);

View File

@ -165,6 +165,12 @@ CFLAGS += -DAPP_DISPLAY_TEST
SRV_GUI = 1 SRV_GUI = 1
endif endif
APP_TEXT_BOX_TEST ?= 0
ifeq ($(APP_TEXT_BOX_TEST), 1)
CFLAGS += -DAPP_TEXT_BOX_TEST
SRV_GUI = 1
endif
APP_BATTERY_TEST ?= 0 APP_BATTERY_TEST ?= 0
ifeq ($(APP_BATTERY_TEST), 1) ifeq ($(APP_BATTERY_TEST), 1)
CFLAGS += -DAPP_BATTERY_TEST CFLAGS += -DAPP_BATTERY_TEST

View File

@ -391,14 +391,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
furi_assert(browser); furi_assert(browser);
furi_assert(name); furi_assert(name);
uint8_t browser_depth = 0; if(string_size(name) >= (MAX_NAME_LEN - 1)) {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
browser_depth = idx_last_array_size(model->idx_last);
return false;
});
if(browser_depth > BROWSER_DEPTH_MAX) {
return; return;
} }

View File

@ -4,7 +4,6 @@
#define TAB_RIGHT InputKeyRight //default tab swith direction #define TAB_RIGHT InputKeyRight //default tab swith direction
#define FILE_LIST_BUF_LEN 100 #define FILE_LIST_BUF_LEN 100
#define BROWSER_DEPTH_MAX 8
static const char* tab_default_paths[] = { static const char* tab_default_paths[] = {
[ArchiveTabFavorites] = "/any/favorites", [ArchiveTabFavorites] = "/any/favorites",

View File

@ -20,7 +20,7 @@ void archive_scene_delete_on_enter(void* context) {
ArchiveApp* app = (ArchiveApp*)context; ArchiveApp* app = (ArchiveApp*)context;
widget_add_button_element( widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", archive_scene_delete_widget_callback, app); app->widget, GuiButtonTypeLeft, "Cancel", archive_scene_delete_widget_callback, app);
widget_add_button_element( widget_add_button_element(
app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app);
@ -33,7 +33,8 @@ void archive_scene_delete_on_enter(void* context) {
char delete_str[64]; char delete_str[64];
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name); snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name);
widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); widget_add_text_box_element(
app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget);
} }

View File

@ -189,6 +189,8 @@ static void bt_cli_print_usage() {
} }
static void bt_cli(Cli* cli, string_t args, void* context) { static void bt_cli(Cli* cli, string_t args, void* context) {
furi_record_open("bt");
string_t cmd; string_t cmd;
string_init(cmd); string_init(cmd);
BtSettings bt_settings; BtSettings bt_settings;
@ -235,14 +237,13 @@ static void bt_cli(Cli* cli, string_t args, void* context) {
} }
string_clear(cmd); string_clear(cmd);
furi_record_close("bt");
} }
void bt_on_system_start() { void bt_on_system_start() {
#ifdef SRV_CLI #ifdef SRV_CLI
Cli* cli = furi_record_open("cli"); Cli* cli = furi_record_open("cli");
furi_record_open("bt");
cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL); cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL);
furi_record_close("bt");
furi_record_close("cli"); furi_record_close("cli");
#else #else
UNUSED(bt_cli); UNUSED(bt_cli);

View File

@ -320,7 +320,7 @@ int32_t bt_srv() {
Bt* bt = bt_alloc(); Bt* bt = bt_alloc();
// Read keys // Read keys
if(!bt_load_key_storage(bt)) { if(!bt_keys_storage_load(bt)) {
FURI_LOG_W(TAG, "Failed to load bonding keys"); FURI_LOG_W(TAG, "Failed to load bonding keys");
} }
@ -365,11 +365,11 @@ int32_t bt_srv() {
// Display PIN code // Display PIN code
bt_pin_code_show(bt, message.data.pin_code); bt_pin_code_show(bt, message.data.pin_code);
} else if(message.type == BtMessageTypeKeysStorageUpdated) { } else if(message.type == BtMessageTypeKeysStorageUpdated) {
bt_save_key_storage(bt); bt_keys_storage_save(bt);
} else if(message.type == BtMessageTypeSetProfile) { } else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message); bt_change_profile(bt, &message);
} else if(message.type == BtMessageTypeForgetBondedDevices) { } else if(message.type == BtMessageTypeForgetBondedDevices) {
bt_delete_key_storage(bt); bt_keys_storage_delete(bt);
} }
} }
return 0; return 0;

View File

@ -1,46 +1,47 @@
#include "bt_keys_storage.h" #include "bt_keys_storage.h"
#include <furi.h> #include <furi.h>
#include <file_worker.h> #include <lib/toolbox/saved_struct.h>
#define BT_KEYS_STORAGE_TAG "bt keys storage"
#define BT_KEYS_STORAGE_PATH "/int/bt.keys" #define BT_KEYS_STORAGE_PATH "/int/bt.keys"
#define BT_KEYS_STORAGE_VERSION (0)
#define BT_KEYS_STORAGE_MAGIC (0x18)
bool bt_load_key_storage(Bt* bt) { bool bt_keys_storage_load(Bt* bt) {
furi_assert(bt); furi_assert(bt);
bool file_loaded = false; bool file_loaded = false;
furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size);
FileWorker* file_worker = file_worker_alloc(true); furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size);
if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
furi_hal_bt_nvm_sram_sem_acquire(); furi_hal_bt_nvm_sram_sem_acquire();
if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { file_loaded = saved_struct_load(
file_loaded = true; BT_KEYS_STORAGE_PATH,
} bt->bt_keys_addr_start,
bt->bt_keys_size,
BT_KEYS_STORAGE_MAGIC,
BT_KEYS_STORAGE_VERSION);
furi_hal_bt_nvm_sram_sem_release(); furi_hal_bt_nvm_sram_sem_release();
}
file_worker_free(file_worker);
return file_loaded; return file_loaded;
} }
bool bt_save_key_storage(Bt* bt) { bool bt_keys_storage_save(Bt* bt) {
furi_assert(bt); furi_assert(bt);
furi_assert(bt->bt_keys_addr_start); furi_assert(bt->bt_keys_addr_start);
bool file_saved = false; bool file_saved = false;
FileWorker* file_worker = file_worker_alloc(true);
if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
furi_hal_bt_nvm_sram_sem_acquire(); furi_hal_bt_nvm_sram_sem_acquire();
if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { file_saved = saved_struct_save(
file_saved = true; BT_KEYS_STORAGE_PATH,
} bt->bt_keys_addr_start,
bt->bt_keys_size,
BT_KEYS_STORAGE_MAGIC,
BT_KEYS_STORAGE_VERSION);
furi_hal_bt_nvm_sram_sem_release(); furi_hal_bt_nvm_sram_sem_release();
}
file_worker_free(file_worker);
return file_saved; return file_saved;
} }
bool bt_delete_key_storage(Bt* bt) { bool bt_keys_storage_delete(Bt* bt) {
furi_assert(bt); furi_assert(bt);
bool delete_succeed = false; bool delete_succeed = false;
bool bt_is_active = furi_hal_bt_is_active(); bool bt_is_active = furi_hal_bt_is_active();

View File

@ -2,8 +2,8 @@
#include "bt_i.h" #include "bt_i.h"
bool bt_load_key_storage(Bt* bt); bool bt_keys_storage_load(Bt* bt);
bool bt_save_key_storage(Bt* bt); bool bt_keys_storage_save(Bt* bt);
bool bt_delete_key_storage(Bt* bt); bool bt_keys_storage_delete(Bt* bt);

View File

@ -1,50 +1,22 @@
#include "bt_settings.h" #include "bt_settings.h"
#include <furi.h>
#include <file_worker.h>
#define TAG "BtSettings" #include <furi.h>
#include <lib/toolbox/saved_struct.h>
#define BT_SETTINGS_PATH "/int/bt.settings" #define BT_SETTINGS_PATH "/int/bt.settings"
#define BT_SETTINGS_VERSION (0)
#define BT_SETTINGS_MAGIC (0x19)
bool bt_settings_load(BtSettings* bt_settings) { bool bt_settings_load(BtSettings* bt_settings) {
furi_assert(bt_settings); furi_assert(bt_settings);
bool file_loaded = false;
BtSettings settings = {};
FURI_LOG_I(TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); return saved_struct_load(
FileWorker* file_worker = file_worker_alloc(true); BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION);
if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
if(file_worker_read(file_worker, &settings, sizeof(settings))) {
file_loaded = true;
}
}
file_worker_free(file_worker);
if(file_loaded) {
FURI_LOG_I(TAG, "Settings load success");
if(settings.version != BT_SETTINGS_VERSION) {
FURI_LOG_E(TAG, "Settings version mismatch");
} else {
osKernelLock();
*bt_settings = settings;
osKernelUnlock();
}
} else {
FURI_LOG_E(TAG, "Settings load failed");
}
return file_loaded;
} }
bool bt_settings_save(BtSettings* bt_settings) { bool bt_settings_save(BtSettings* bt_settings) {
furi_assert(bt_settings); furi_assert(bt_settings);
bool result = false;
FileWorker* file_worker = file_worker_alloc(true); return saved_struct_save(
if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION);
if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) {
FURI_LOG_I(TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH);
result = true;
}
}
file_worker_free(file_worker);
return result;
} }

View File

@ -3,10 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define BT_SETTINGS_VERSION (0)
typedef struct { typedef struct {
uint8_t version;
bool enabled; bool enabled;
} BtSettings; } BtSettings;

View File

@ -0,0 +1,126 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <gui/elements.h>
#define TAG "TextBoxTest"
static void text_box_center_top_secondary_128x22(Canvas* canvas) {
canvas_draw_frame(canvas, 0, 0, 128, 22);
elements_text_box(canvas, 0, 0, 128, 22, AlignCenter, AlignTop, "secondary font test", false);
}
static void text_box_right_bottom_bold_128x22(Canvas* canvas) {
canvas_draw_frame(canvas, 0, 0, 128, 22);
elements_text_box(
canvas, 0, 0, 128, 22, AlignRight, AlignBottom, "\e#Bold font test\e#", false);
}
static void text_box_left_center_mixed_80x50(Canvas* canvas) {
canvas_draw_frame(canvas, 0, 0, 80, 50);
elements_text_box(
canvas,
0,
0,
80,
50,
AlignLeft,
AlignCenter,
"\e#Never\e# gonna give you up\n\e!Never\e! gonna let you down",
false);
}
static void text_box_center_center_secondary_110x44(Canvas* canvas) {
canvas_draw_frame(canvas, 4, 20, 110, 30);
elements_text_box(
canvas,
4,
20,
110,
30,
AlignCenter,
AlignCenter,
"Loooooooooooooo0000000ooong file name from happy 100500 Flipper 0wners",
true);
}
static void (*text_box_test_render[])(Canvas* canvas) = {
text_box_center_top_secondary_128x22,
text_box_right_bottom_bold_128x22,
text_box_left_center_mixed_80x50,
text_box_center_center_secondary_110x44,
};
typedef struct {
uint32_t idx;
} TextBoxTestState;
static void text_box_test_render_callback(Canvas* canvas, void* ctx) {
TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25);
canvas_clear(canvas);
text_box_test_render[state->idx](canvas);
release_mutex((ValueMutex*)ctx, state);
}
static void text_box_test_input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = ctx;
osMessageQueuePut(event_queue, input_event, 0, osWaitForever);
}
int32_t text_box_test_app(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(InputEvent), NULL);
furi_check(event_queue);
TextBoxTestState _state = {.idx = 0};
ValueMutex state_mutex;
if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) {
FURI_LOG_E(TAG, "Cannot create mutex");
return 0;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex);
view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
uint32_t test_renders_num = SIZEOF_ARRAY(text_box_test_render);
InputEvent event;
while(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK) {
TextBoxTestState* state = acquire_mutex_block(&state_mutex);
if(event.type == InputTypeShort) {
if(event.key == InputKeyRight) {
if(state->idx < test_renders_num - 1) {
state->idx++;
}
} else if(event.key == InputKeyLeft) {
if(state->idx > 0) {
state->idx--;
}
} else if(event.key == InputKeyBack) {
release_mutex(&state_mutex, state);
break;
}
}
release_mutex(&state_mutex, state);
view_port_update(view_port);
}
// remove & free all stuff created by app
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
osMessageQueueDelete(event_queue);
delete_mutex(&state_mutex);
furi_record_close("gui");
return 0;
}

View File

@ -161,8 +161,9 @@ void animation_manager_new_idle_process(AnimationManager* animation_manager) {
} }
/* reaction to animation_manager->interact_callback() */ /* reaction to animation_manager->interact_callback() */
void animation_manager_interact_process(AnimationManager* animation_manager) { bool animation_manager_interact_process(AnimationManager* animation_manager) {
furi_assert(animation_manager); furi_assert(animation_manager);
bool consumed = true;
if(animation_manager->levelup_pending) { if(animation_manager->levelup_pending) {
animation_manager->levelup_pending = false; animation_manager->levelup_pending = false;
@ -181,7 +182,11 @@ void animation_manager_interact_process(AnimationManager* animation_manager) {
if(!blocked) { if(!blocked) {
animation_manager_start_new_idle(animation_manager); animation_manager_start_new_idle(animation_manager);
} }
} else {
consumed = false;
} }
return consumed;
} }
static void animation_manager_start_new_idle(AnimationManager* animation_manager) { static void animation_manager_start_new_idle(AnimationManager* animation_manager) {

View File

@ -130,8 +130,9 @@ void animation_manager_set_interact_callback(
* set_new_idle_callback's call. * set_new_idle_callback's call.
* *
* @animation_manager instance * @animation_manager instance
* @return true if event was consumed
*/ */
void animation_manager_interact_process(AnimationManager* animation_manager); bool animation_manager_interact_process(AnimationManager* animation_manager);
/** Check if animation loaded /** Check if animation loaded
* *

View File

@ -117,6 +117,7 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) {
} }
void desktop_lock(Desktop* desktop) { void desktop_lock(Desktop* desktop) {
furi_hal_rtc_set_pin_fails(0);
desktop_auto_lock_inhibit(desktop); desktop_auto_lock_inhibit(desktop);
scene_manager_set_scene_state( scene_manager_set_scene_state(
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);

View File

@ -116,7 +116,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
} }
consumed = true; consumed = true;
break; break;
case DesktopAnimationEventCheckAnimation: case DesktopAnimationEventCheckAnimation:
animation_manager_check_blocking_process(desktop->animation_manager); animation_manager_check_blocking_process(desktop->animation_manager);
consumed = true; consumed = true;
@ -126,7 +125,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
break; break;
case DesktopAnimationEventInteractAnimation: case DesktopAnimationEventInteractAnimation:
animation_manager_interact_process(desktop->animation_manager); if(!animation_manager_interact_process(desktop->animation_manager)) {
LoaderStatus status = loader_start(desktop->loader, "Passport", NULL);
if(status != LoaderStatusOk) {
FURI_LOG_E(TAG, "loader_start failed: %d", status);
}
}
consumed = true; consumed = true;
break; break;
case DesktopLockedEventUpdate: case DesktopLockedEventUpdate:

View File

@ -6,7 +6,7 @@ typedef enum {
DesktopMainEventOpenFavorite, DesktopMainEventOpenFavorite,
DesktopMainEventOpenMenu, DesktopMainEventOpenMenu,
DesktopMainEventOpenDebug, DesktopMainEventOpenDebug,
DesktopMainEventRightShort, DesktopMainEventOpenPassport, /**< Broken, don't use it */
DesktopLockedEventUnlocked, DesktopLockedEventUnlocked,
DesktopLockedEventUpdate, DesktopLockedEventUpdate,

View File

@ -46,7 +46,7 @@ bool desktop_main_input(InputEvent* event, void* context) {
} else if(event->key == InputKeyLeft) { } else if(event->key == InputKeyLeft) {
main_view->callback(DesktopMainEventOpenFavorite, main_view->context); main_view->callback(DesktopMainEventOpenFavorite, main_view->context);
} else if(event->key == InputKeyRight) { } else if(event->key == InputKeyRight) {
main_view->callback(DesktopMainEventRightShort, main_view->context); main_view->callback(DesktopMainEventOpenPassport, main_view->context);
} }
} else if(event->type == InputTypeLong) { } else if(event->type == InputTypeLong) {
if(event->key == InputKeyDown) { if(event->key == InputKeyDown) {

View File

@ -197,7 +197,11 @@ static size_t
uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str));
uint8_t px_left = 0; uint8_t px_left = 0;
if(horizontal == AlignCenter) { if(horizontal == AlignCenter) {
px_left = canvas_width(canvas) - (x - len_px / 2); if(x > (canvas_width(canvas) / 2)) {
px_left = (canvas_width(canvas) - x) * 2;
} else {
px_left = x * 2;
}
} else if(horizontal == AlignLeft) { } else if(horizontal == AlignLeft) {
px_left = canvas_width(canvas) - x; px_left = canvas_width(canvas) - x;
} else if(horizontal == AlignRight) { } else if(horizontal == AlignRight) {
@ -208,13 +212,13 @@ static size_t
if(len_px > px_left) { if(len_px > px_left) {
uint8_t excess_symbols_approximately = uint8_t excess_symbols_approximately =
((float)len_px - px_left) / ((float)len_px / text_size); roundf((float)(len_px - px_left) / ((float)len_px / (float)text_size));
// reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long // reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long
if(excess_symbols_approximately > 0) {
excess_symbols_approximately = MAX(excess_symbols_approximately, 5); excess_symbols_approximately = MAX(excess_symbols_approximately, 5);
if(text_size > (excess_symbols_approximately + 5)) { result = text_size - excess_symbols_approximately - 1;
result = text_size - excess_symbols_approximately - 5;
} else { } else {
result = text_size - 1; result = text_size;
} }
} else { } else {
result = text_size; result = text_size;
@ -258,12 +262,17 @@ void elements_multiline_text_aligned(
if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) {
string_init_printf(line, "%.*s", chars_fit, start); string_init_printf(line, "%.*s", chars_fit, start);
} else if((y + font_height) > canvas_height(canvas)) {
string_init_printf(line, "%.*s...\n", chars_fit, start);
} else { } else {
string_init_printf(line, "%.*s-\n", chars_fit, start); string_init_printf(line, "%.*s-\n", chars_fit, start);
} }
canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line));
string_clear(line); string_clear(line);
y += font_height; y += font_height;
if(y > canvas_height(canvas)) {
break;
}
start += chars_fit; start += chars_fit;
start += start[0] == '\n' ? 1 : 0; start += start[0] == '\n' ? 1 : 0;
@ -547,7 +556,8 @@ void elements_text_box(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text) { const char* text,
bool strip_to_dots) {
furi_assert(canvas); furi_assert(canvas);
ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM];
@ -571,6 +581,7 @@ void elements_text_box(
uint8_t total_height_default = 0; uint8_t total_height_default = 0;
uint16_t i = 0; uint16_t i = 0;
bool full_text_processed = false; bool full_text_processed = false;
uint16_t dots_width = canvas_string_width(canvas, "...");
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
@ -663,7 +674,6 @@ void elements_text_box(
} }
// Set vertical alignment for all lines // Set vertical alignment for all lines
if(full_text_processed) {
if(total_height_default < height) { if(total_height_default < height) {
if(vertical == AlignTop) { if(vertical == AlignTop) {
line[0].y = y + line[0].height; line[0].y = y + line[0].height;
@ -688,7 +698,6 @@ void elements_text_box(
j = j % (line_num - 1) + 1; j = j % (line_num - 1) + 1;
} }
} }
}
// Draw line by line // Draw line by line
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
@ -733,6 +742,13 @@ void elements_text_box(
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
canvas_invert_color(canvas); canvas_invert_color(canvas);
} else { } else {
if((i == line_num - 1) && strip_to_dots) {
uint8_t next_symbol_width = canvas_glyph_width(canvas, line[i].text[j]);
if(line[i].x + next_symbol_width + dots_width > x + width) {
canvas_draw_str(canvas, line[i].x, line[i].y, "...");
break;
}
}
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
} }
line[i].x += canvas_glyph_width(canvas, line[i].text[j]); line[i].x += canvas_glyph_width(canvas, line[i].text[j]);

View File

@ -205,6 +205,7 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width);
* "\e#Bold text\e#" - bold font is used * "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used * "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background * "\e#Inversed text\e#" - white text on black background
* @param strip_to_dots Strip text to ... if does not fit to width
*/ */
void elements_text_box( void elements_text_box(
Canvas* canvas, Canvas* canvas,
@ -214,7 +215,8 @@ void elements_text_box(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text); const char* text,
bool strip_to_dots);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -314,6 +314,7 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) {
view_port_gui_set(view_port, gui); view_port_gui_set(view_port, gui);
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui); gui_update(gui);
} }
@ -322,7 +323,6 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
furi_assert(view_port); furi_assert(view_port);
gui_lock(gui); gui_lock(gui);
view_port_gui_set(view_port, NULL); view_port_gui_set(view_port, NULL);
ViewPortArray_it_t it; ViewPortArray_it_t it;
for(size_t i = 0; i < GuiLayerMAX; i++) { for(size_t i = 0; i < GuiLayerMAX; i++) {
@ -335,12 +335,13 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
} }
} }
} }
if(gui->ongoing_input_view_port == view_port) { if(gui->ongoing_input_view_port == view_port) {
gui->ongoing_input_view_port = NULL; gui->ongoing_input_view_port = NULL;
} }
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui);
} }
void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) { void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) {
@ -367,6 +368,9 @@ void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) {
// Return to the top // Return to the top
ViewPortArray_push_back(gui->layers[layer], view_port); ViewPortArray_push_back(gui->layers[layer], view_port);
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui);
} }
void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) {
@ -393,6 +397,9 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) {
// Return to the top // Return to the top
ViewPortArray_push_at(gui->layers[layer], 0, view_port); ViewPortArray_push_at(gui->layers[layer], 0, view_port);
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui);
} }
void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) {
@ -401,11 +408,11 @@ void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, vo
const CanvasCallbackPair p = {callback, context}; const CanvasCallbackPair p = {callback, context};
gui_lock(gui); gui_lock(gui);
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0); furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0);
CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p); CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p);
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui); gui_update(gui);
} }
@ -415,10 +422,8 @@ void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback,
const CanvasCallbackPair p = {callback, context}; const CanvasCallbackPair p = {callback, context};
gui_lock(gui); gui_lock(gui);
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1); furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1);
CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p); CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p);
gui_unlock(gui); gui_unlock(gui);
} }
@ -429,9 +434,12 @@ size_t gui_get_framebuffer_size(Gui* gui) {
void gui_set_lockdown(Gui* gui, bool lockdown) { void gui_set_lockdown(Gui* gui, bool lockdown) {
furi_assert(gui); furi_assert(gui);
gui_lock(gui); gui_lock(gui);
gui->lockdown = lockdown; gui->lockdown = lockdown;
gui_unlock(gui); gui_unlock(gui);
// Request redraw
gui_update(gui); gui_update(gui);
} }

7
applications/gui/modules/widget.c Executable file → Normal file
View File

@ -154,10 +154,11 @@ void widget_add_text_box_element(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text) { const char* text,
bool strip_to_dots) {
furi_assert(widget); furi_assert(widget);
WidgetElement* text_box_element = WidgetElement* text_box_element = widget_element_text_box_create(
widget_element_text_box_create(x, y, width, height, horizontal, vertical, text); x, y, width, height, horizontal, vertical, text, strip_to_dots);
widget_add_element(widget, text_box_element); widget_add_element(widget, text_box_element);
} }

View File

@ -92,6 +92,7 @@ void widget_add_string_element(
* "\e#Bold text\e#" - bold font is used * "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used * "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background * "\e#Inversed text\e#" - white text on black background
* @param strip_to_dots Strip text to ... if does not fit to width
*/ */
void widget_add_text_box_element( void widget_add_text_box_element(
Widget* widget, Widget* widget,
@ -101,7 +102,8 @@ void widget_add_text_box_element(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text); const char* text,
bool strip_to_dots);
/** Add Button Element /** Add Button Element
* *

View File

@ -60,7 +60,8 @@ WidgetElement* widget_element_text_box_create(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text); const char* text,
bool strip_to_dots);
/** Create button element */ /** Create button element */
WidgetElement* widget_element_button_create( WidgetElement* widget_element_button_create(

View File

@ -10,6 +10,7 @@ typedef struct {
Align horizontal; Align horizontal;
Align vertical; Align vertical;
string_t text; string_t text;
bool strip_to_dots;
} GuiTextBoxModel; } GuiTextBoxModel;
static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) { static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) {
@ -26,7 +27,8 @@ static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) {
model->height, model->height,
model->horizontal, model->horizontal,
model->vertical, model->vertical,
string_get_cstr(model->text)); string_get_cstr(model->text),
model->strip_to_dots);
} }
} }
@ -46,7 +48,8 @@ WidgetElement* widget_element_text_box_create(
uint8_t height, uint8_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text) { const char* text,
bool strip_to_dots) {
furi_assert(text); furi_assert(text);
// Allocate and init model // Allocate and init model
@ -58,6 +61,7 @@ WidgetElement* widget_element_text_box_create(
model->horizontal = horizontal; model->horizontal = horizontal;
model->vertical = vertical; model->vertical = vertical;
string_init_set_str(model->text, text); string_init_set_str(model->text, text);
model->strip_to_dots = strip_to_dots;
// Allocate and init Element // Allocate and init Element
WidgetElement* gui_string = malloc(sizeof(WidgetElement)); WidgetElement* gui_string = malloc(sizeof(WidgetElement));

View File

@ -21,7 +21,7 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) {
app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key));
widget_add_text_box_element( widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store()); widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false);
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app); widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);

View File

@ -9,7 +9,7 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) {
app->set_text_store("%s", ibutton_key_get_name_p(key)); app->set_text_store("%s", ibutton_key_get_name_p(key));
widget_add_text_box_element( widget_add_text_box_element(
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store()); widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store(), false);
switch(ibutton_key_get_type(key)) { switch(ibutton_key_get_type(key)) {
case iButtonKeyDS1990: case iButtonKeyDS1990:

View File

@ -49,12 +49,14 @@ int32_t InfraredApp::run(void* args) {
InfraredApp::InfraredApp() { InfraredApp::InfraredApp() {
furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size());
notification = static_cast<NotificationApp*>(furi_record_open("notification")); notification = static_cast<NotificationApp*>(furi_record_open("notification"));
dialogs = static_cast<DialogsApp*>(furi_record_open("dialogs"));
infrared_worker = infrared_worker_alloc(); infrared_worker = infrared_worker_alloc();
} }
InfraredApp::~InfraredApp() { InfraredApp::~InfraredApp() {
infrared_worker_free(infrared_worker); infrared_worker_free(infrared_worker);
furi_record_close("notification"); furi_record_close("notification");
furi_record_close("dialogs");
for(auto& [key, scene] : scenes) delete scene; for(auto& [key, scene] : scenes) delete scene;
} }
@ -248,6 +250,10 @@ void InfraredApp::notify_blink_green() {
notification_message(notification, &sequence); notification_message(notification, &sequence);
} }
DialogsApp* InfraredApp::get_dialogs() {
return dialogs;
}
void InfraredApp::notify_green_on() { void InfraredApp::notify_green_on() {
notification_message(notification, &sequence_set_only_green_255); notification_message(notification, &sequence_set_only_green_255);
} }

View File

@ -9,6 +9,7 @@
#include <forward_list> #include <forward_list>
#include <stdint.h> #include <stdint.h>
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
#include <dialogs/dialogs.h>
#include <infrared_worker.h> #include <infrared_worker.h>
#include "scene/infrared_app_scene.h" #include "scene/infrared_app_scene.h"
@ -228,6 +229,9 @@ public:
/** Blink green light */ /** Blink green light */
void notify_blink_green(); void notify_blink_green();
/** Get Dialogs instance */
DialogsApp* get_dialogs();
/** Text input callback /** Text input callback
* *
* @param context - context to pass to callback * @param context - context to pass to callback
@ -286,6 +290,8 @@ private:
/** Notification instance */ /** Notification instance */
NotificationApp* notification; NotificationApp* notification;
/** Dialogs instance */
DialogsApp* dialogs;
/** View manager instance */ /** View manager instance */
InfraredAppViewManager view_manager; InfraredAppViewManager view_manager;
/** Remote manager instance */ /** Remote manager instance */

View File

@ -5,7 +5,6 @@
#include <memory> #include <memory>
#include <m-string.h> #include <m-string.h>
#include <furi.h> #include <furi.h>
#include <file_worker_cpp.h>
void InfraredAppBruteForce::add_record(int index, const char* name) { void InfraredAppBruteForce::add_record(int index, const char* name) {
records[name].index = index; records[name].index = index;

View File

@ -1,4 +1,3 @@
#include <file_worker_cpp.h>
#include <flipper_format/flipper_format.h> #include <flipper_format/flipper_format.h>
#include "infrared_app_remote_manager.h" #include "infrared_app_remote_manager.h"
#include "infrared/helpers/infrared_parser.h" #include "infrared/helpers/infrared_parser.h"
@ -22,26 +21,34 @@ std::string InfraredAppRemoteManager::make_full_name(
} }
std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) { std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) {
bool exist = true; std::string result_name;
FileWorkerCpp file_worker; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
if(!file_worker.is_file_exist( FS_Error error = storage_common_stat(
make_full_name(InfraredApp::infrared_directory, name).c_str(), &exist)) { storage, make_full_name(InfraredApp::infrared_directory, name).c_str(), NULL);
return std::string();
} else if(!exist) {
return name;
}
if(error == FSE_NOT_EXIST) {
result_name = name;
} else if(error != FSE_OK) {
result_name = std::string();
} else {
/* if suggested name is occupied, try another one (name2, name3, etc) */ /* if suggested name is occupied, try another one (name2, name3, etc) */
uint32_t i = 1; uint32_t i = 1;
bool file_worker_result = false;
std::string new_name; std::string new_name;
do { do {
new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i)); new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i));
file_worker_result = file_worker.is_file_exist(new_name.c_str(), &exist); error = storage_common_stat(storage, new_name.c_str(), NULL);
} while(file_worker_result && exist); } while(error == FSE_OK);
return !exist ? name + std::to_string(i) : std::string(); if(error == FSE_NOT_EXIST) {
result_name = name + std::to_string(i);
} else {
result_name = std::string();
}
}
furi_record_close("storage");
return result_name;
} }
bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) {
@ -84,12 +91,14 @@ const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index)
} }
bool InfraredAppRemoteManager::delete_remote() { bool InfraredAppRemoteManager::delete_remote() {
bool result; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
FileWorkerCpp file_worker;
result = file_worker.remove(make_full_name(remote->path, remote->name).c_str());
FS_Error error =
storage_common_remove(storage, make_full_name(remote->path, remote->name).c_str());
reset_remote(); reset_remote();
return result;
furi_record_close("storage");
return (error == FSE_OK || error == FSE_NOT_EXIST);
} }
void InfraredAppRemoteManager::reset_remote() { void InfraredAppRemoteManager::reset_remote() {
@ -129,14 +138,15 @@ bool InfraredAppRemoteManager::rename_remote(const char* str) {
return false; return false;
} }
FileWorkerCpp file_worker; Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
std::string old_filename = make_full_name(remote->path, remote->name); std::string old_filename = make_full_name(remote->path, remote->name);
std::string new_filename = make_full_name(remote->path, new_name); std::string new_filename = make_full_name(remote->path, new_name);
bool result = file_worker.rename(old_filename.c_str(), new_filename.c_str()); FS_Error error = storage_common_rename(storage, old_filename.c_str(), new_filename.c_str());
remote->name = new_name; remote->name = new_name;
return result; furi_record_close("storage");
return (error == FSE_OK || error == FSE_EXIST);
} }
bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) { bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) {
@ -155,11 +165,10 @@ size_t InfraredAppRemoteManager::get_number_of_buttons() {
bool InfraredAppRemoteManager::store(void) { bool InfraredAppRemoteManager::store(void) {
bool result = false; bool result = false;
FileWorkerCpp file_worker;
if(!file_worker.mkdir(InfraredApp::infrared_directory)) return false;
Storage* storage = static_cast<Storage*>(furi_record_open("storage")); Storage* storage = static_cast<Storage*>(furi_record_open("storage"));
if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false;
FlipperFormat* ff = flipper_format_file_alloc(storage); FlipperFormat* ff = flipper_format_file_alloc(storage);
FURI_LOG_I( FURI_LOG_I(

View File

@ -23,9 +23,9 @@ void InfraredAppSceneEdit::on_enter(InfraredApp* app) {
InfraredAppViewManager* view_manager = app->get_view_manager(); InfraredAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Add Key", SubmenuIndexAddKey, submenu_callback, app); submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app);
submenu_add_item(submenu, "Rename Key", SubmenuIndexRenameKey, submenu_callback, app); submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app);
submenu_add_item(submenu, "Delete Key", SubmenuIndexDeleteKey, submenu_callback, app); submenu_add_item(submenu, "Delete Button", SubmenuIndexDeleteKey, submenu_callback, app);
submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app); submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app);
submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected); submenu_set_selected_item(submenu, submenu_item_selected);

View File

@ -51,7 +51,7 @@ void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) {
dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL); dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Back"); dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Delete"); dialog_ex_set_right_button_text(dialog_ex, "Delete");
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
dialog_ex_set_context(dialog_ex, app); dialog_ex_set_context(dialog_ex, app);

View File

@ -16,8 +16,9 @@ void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) {
Submenu* submenu = view_manager->get_submenu(); Submenu* submenu = view_manager->get_submenu();
int item_number = 0; int item_number = 0;
const char* header = const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ?
app->get_edit_action() == InfraredApp::EditAction::Rename ? "Rename key:" : "Delete key:"; "Rename Button:" :
"Delete Button:";
submenu_set_header(submenu, header); submenu_set_header(submenu, header);
auto remote_manager = app->get_remote_manager(); auto remote_manager = app->get_remote_manager();

View File

@ -14,7 +14,7 @@ void InfraredAppSceneEditRename::on_enter(InfraredApp* app) {
strncpy(buffer_str, button_name.c_str(), max_len); strncpy(buffer_str, button_name.c_str(), max_len);
buffer_str[max_len + 1] = 0; buffer_str[max_len + 1] = 0;
enter_name_length = max_len; enter_name_length = max_len;
text_input_set_header_text(text_input, "Name the key"); text_input_set_header_text(text_input, "Name the button");
} else { } else {
auto remote_name = remote_manager->get_remote_name(); auto remote_name = remote_manager->get_remote_name();
strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size());

View File

@ -20,7 +20,7 @@ void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) {
app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt);
} }
text_input_set_header_text(text_input, "Name the key"); text_input_set_header_text(text_input, "Name the button");
text_input_set_result_callback( text_input_set_result_callback(
text_input, text_input,
InfraredApp::text_input_callback, InfraredApp::text_input_callback,

View File

@ -1,5 +1,4 @@
#include <gui/modules/dialog_ex.h> #include <gui/modules/dialog_ex.h>
#include <file_worker_cpp.h>
#include <memory> #include <memory>
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
@ -88,13 +87,8 @@ bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent*
break; break;
case DialogExResultRight: { case DialogExResultRight: {
consumed = true; consumed = true;
FileWorkerCpp file_worker;
if(!button_pressed) { if(!button_pressed) {
if(file_worker.check_errors()) {
app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName);
} else {
app->switch_to_previous_scene();
}
} }
break; break;
} }

View File

@ -1,12 +1,10 @@
#include "../infrared_app.h" #include "../infrared_app.h"
#include "infrared/infrared_app_event.h" #include "infrared/infrared_app_event.h"
#include <text_store.h> #include <text_store.h>
#include <file_worker_cpp.h>
void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) {
furi_assert(app); furi_assert(app);
FileWorkerCpp file_worker;
bool result = false; bool result = false;
bool file_select_result; bool file_select_result;
auto remote_manager = app->get_remote_manager(); auto remote_manager = app->get_remote_manager();
@ -15,13 +13,15 @@ void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) {
last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; last_selected_remote.size() ? last_selected_remote.c_str() : nullptr;
auto filename_ts = auto filename_ts =
std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length); std::make_unique<TextStore>(InfraredAppRemoteManager::max_remote_name_length);
DialogsApp* dialogs = app->get_dialogs();
InfraredAppViewManager* view_manager = app->get_view_manager(); InfraredAppViewManager* view_manager = app->get_view_manager();
ButtonMenu* button_menu = view_manager->get_button_menu(); ButtonMenu* button_menu = view_manager->get_button_menu();
button_menu_reset(button_menu); button_menu_reset(button_menu);
view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu);
file_select_result = file_worker.file_select( file_select_result = dialog_file_select_show(
dialogs,
InfraredApp::infrared_directory, InfraredApp::infrared_directory,
InfraredApp::infrared_extension, InfraredApp::infrared_extension,
filename_ts->text, filename_ts->text,

View File

@ -92,7 +92,7 @@ const FlipperApplication* loader_find_application_by_name(const char* name) {
application = loader_find_application_by_name_in_list( application = loader_find_application_by_name_in_list(
name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT); name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT);
} }
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && !application) { if(!application) {
application = loader_find_application_by_name_in_list( application = loader_find_application_by_name_in_list(
name, FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT); name, FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT);
} }
@ -239,26 +239,11 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
event.type = LoaderEventTypeApplicationStarted; event.type = LoaderEventTypeApplicationStarted;
furi_pubsub_publish(loader_instance->pubsub, &event); furi_pubsub_publish(loader_instance->pubsub, &event);
furi_hal_power_insomnia_enter(); furi_hal_power_insomnia_enter();
// Snapshot current memory usage
instance->free_heap_size = memmgr_get_free_heap();
} else if(thread_state == FuriThreadStateStopped) { } else if(thread_state == FuriThreadStateStopped) {
/*
* Current Leak Sanitizer assumes that memory is allocated and freed
* inside one thread. Timers are allocated in one task, but freed in
* Timer-Task thread, and xTimerDelete() just put command to queue.
* To avoid some bad cases there are few fixes:
* 1) delay for Timer to process commands
* 2) there are 'heap diff' which shows difference in heap before task
* started and after task completed. In process of leakage monitoring
* both values should be taken into account.
*/
furi_hal_delay_ms(20);
int heap_diff = instance->free_heap_size - memmgr_get_free_heap();
FURI_LOG_I( FURI_LOG_I(
TAG, TAG,
"Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", "Application thread stopped. Free heap: %d. Thread allocation balance: %d.",
heap_diff, memmgr_get_free_heap(),
furi_thread_get_heap_size(instance->application_thread)); furi_thread_get_heap_size(instance->application_thread));
if(loader_instance->application_arguments) { if(loader_instance->application_arguments) {
@ -455,18 +440,17 @@ void loader_update_menu() {
} }
int32_t loader_srv(void* p) { int32_t loader_srv(void* p) {
FURI_LOG_I(TAG, "Starting"); FURI_LOG_I(TAG, "Executing system start hooks");
for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) {
FLIPPER_ON_SYSTEM_START[i]();
}
FURI_LOG_I(TAG, "Starting");
loader_instance = loader_alloc(); loader_instance = loader_alloc();
loader_build_menu(); loader_build_menu();
loader_build_submenu(); loader_build_submenu();
// Call on start hooks
for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) {
FLIPPER_ON_SYSTEM_START[i]();
}
FURI_LOG_I(TAG, "Started"); FURI_LOG_I(TAG, "Started");
furi_record_create("loader", loader_instance); furi_record_create("loader", loader_instance);

View File

@ -30,7 +30,6 @@ struct Loader {
Submenu* debug_menu; Submenu* debug_menu;
Submenu* settings_menu; Submenu* settings_menu;
size_t free_heap_size;
volatile uint8_t lock_count; volatile uint8_t lock_count;
FuriPubSub* pubsub; FuriPubSub* pubsub;

View File

@ -3,19 +3,19 @@
bool nfc_custom_event_callback(void* context, uint32_t event) { bool nfc_custom_event_callback(void* context, uint32_t event) {
furi_assert(context); furi_assert(context);
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
return scene_manager_handle_custom_event(nfc->scene_manager, event); return scene_manager_handle_custom_event(nfc->scene_manager, event);
} }
bool nfc_back_event_callback(void* context) { bool nfc_back_event_callback(void* context) {
furi_assert(context); furi_assert(context);
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
return scene_manager_handle_back_event(nfc->scene_manager); return scene_manager_handle_back_event(nfc->scene_manager);
} }
void nfc_tick_event_callback(void* context) { void nfc_tick_event_callback(void* context) {
furi_assert(context); furi_assert(context);
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
scene_manager_handle_tick_event(nfc->scene_manager); scene_manager_handle_tick_event(nfc->scene_manager);
} }
@ -169,12 +169,17 @@ int32_t nfc_app(void* p) {
char* args = p; char* args = p;
// Check argument and run corresponding scene // Check argument and run corresponding scene
if((*args != '\0') && nfc_device_load(nfc->dev, p)) { if((*args != '\0')) {
if(nfc_device_load(nfc->dev, p)) {
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
} else { } else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
} }
} else {
// Exit app
view_dispatcher_stop(nfc->view_dispatcher);
}
} else { } else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); scene_manager_next_scene(nfc->scene_manager, NfcSceneStart);
} }

View File

@ -16,40 +16,35 @@ static void nfc_cli_print_usage() {
} }
} }
void nfc_cli_detect(Cli* cli, string_t args) { static void nfc_cli_detect(Cli* cli, string_t args) {
// Check if nfc worker is not busy // Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) { if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n"); printf("Nfc is busy\r\n");
return; return;
} }
rfalNfcDevice* dev_list;
uint8_t dev_cnt = 0; FuriHalNfcDevData dev_data = {};
bool cmd_exit = false; bool cmd_exit = false;
furi_hal_nfc_exit_sleep(); furi_hal_nfc_exit_sleep();
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
while(!cmd_exit) { while(!cmd_exit) {
cmd_exit |= cli_cmd_interrupt_received(cli); cmd_exit |= cli_cmd_interrupt_received(cli);
cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true); if(furi_hal_nfc_detect(&dev_data, 400)) {
if(dev_cnt > 0) { printf("found: %s ", nfc_get_dev_type(dev_data.type));
printf("Found %d devices\r\n", dev_cnt); printf("UID length: %d, UID:", dev_data.uid_len);
for(uint8_t i = 0; i < dev_cnt; i++) { for(size_t i = 0; i < dev_data.uid_len; i++) {
printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type)); printf("%02X", dev_data.uid[i]);
if(dev_list[i].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
printf("type: %s, ", nfc_get_nfca_type(dev_list[i].dev.nfca.type));
}
printf("UID length: %d, UID:", dev_list[i].nfcidLen);
for(uint8_t j = 0; j < dev_list[i].nfcidLen; j++) {
printf("%02X", dev_list[i].nfcid[j]);
} }
printf("\r\n"); printf("\r\n");
break;
} }
} furi_hal_nfc_sleep();
osDelay(50); osDelay(50);
} }
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
} }
void nfc_cli_emulate(Cli* cli, string_t args) { static void nfc_cli_emulate(Cli* cli, string_t args) {
// Check if nfc worker is not busy // Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) { if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n"); printf("Nfc is busy\r\n");
@ -60,26 +55,25 @@ void nfc_cli_emulate(Cli* cli, string_t args) {
printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n"); printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
printf("Press Ctrl+C to abort\r\n"); printf("Press Ctrl+C to abort\r\n");
NfcDeviceCommonData params = { FuriHalNfcDevData params = {
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
.uid_len = 7, .uid_len = 7,
.atqa = {0x44, 0x00}, .atqa = {0x44, 0x00},
.sak = 0x00, .sak = 0x00,
.device = NfcDeviceNfca, .type = FuriHalNfcTypeA,
.protocol = NfcDeviceProtocolMifareUl,
}; };
while(!cli_cmd_interrupt_received(cli)) { while(!cli_cmd_interrupt_received(cli)) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
printf("Reader detected\r\n"); printf("Reader detected\r\n");
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
} }
osDelay(50); osDelay(50);
} }
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
} }
void nfc_cli_field(Cli* cli, string_t args) { static void nfc_cli_field(Cli* cli, string_t args) {
// Check if nfc worker is not busy // Check if nfc worker is not busy
if(furi_hal_nfc_is_busy()) { if(furi_hal_nfc_is_busy()) {
printf("Nfc is busy\r\n"); printf("Nfc is busy\r\n");
@ -97,7 +91,7 @@ void nfc_cli_field(Cli* cli, string_t args) {
} }
furi_hal_nfc_field_off(); furi_hal_nfc_field_off();
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
} }
static void nfc_cli(Cli* cli, string_t args, void* context) { static void nfc_cli(Cli* cli, string_t args, void* context) {

View File

@ -41,31 +41,31 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_str
static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
if(string_start_with_str_p(format_string, "UID")) { if(string_start_with_str_p(format_string, "UID")) {
dev->format = NfcDeviceSaveFormatUid; dev->format = NfcDeviceSaveFormatUid;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; dev->dev_data.protocol = NfcDeviceProtocolUnknown;
return true; return true;
} }
if(string_start_with_str_p(format_string, "Bank card")) { if(string_start_with_str_p(format_string, "Bank card")) {
dev->format = NfcDeviceSaveFormatBankCard; dev->format = NfcDeviceSaveFormatBankCard;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; dev->dev_data.protocol = NfcDeviceProtocolEMV;
return true; return true;
} }
// Check Mifare Ultralight types // Check Mifare Ultralight types
for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) { if(string_equal_str_p(format_string, nfc_mf_ul_type(type, true))) {
dev->format = NfcDeviceSaveFormatMifareUl; dev->format = NfcDeviceSaveFormatMifareUl;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; dev->dev_data.protocol = NfcDeviceProtocolMifareUl;
dev->dev_data.mf_ul_data.type = type; dev->dev_data.mf_ul_data.type = type;
return true; return true;
} }
} }
if(string_start_with_str_p(format_string, "Mifare Classic")) { if(string_start_with_str_p(format_string, "Mifare Classic")) {
dev->format = NfcDeviceSaveFormatMifareClassic; dev->format = NfcDeviceSaveFormatMifareClassic;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic; dev->dev_data.protocol = NfcDeviceProtocolMifareClassic;
return true; return true;
} }
if(string_start_with_str_p(format_string, "Mifare DESFire")) { if(string_start_with_str_p(format_string, "Mifare DESFire")) {
dev->format = NfcDeviceSaveFormatMifareDesfire; dev->format = NfcDeviceSaveFormatMifareDesfire;
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire; dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
return true; return true;
} }
return false; return false;
@ -73,7 +73,7 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_strin
static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false; bool saved = false;
MifareUlData* data = &dev->dev_data.mf_ul_data; MfUltralightData* data = &dev->dev_data.mf_ul_data;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -122,7 +122,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev)
bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false; bool parsed = false;
MifareUlData* data = &dev->dev_data.mf_ul_data; MfUltralightData* data = &dev->dev_data.mf_ul_data;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -548,7 +548,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
bool saved = false; bool saved = false;
NfcEmvData* data = &dev->dev_data.emv_data; EmvData* data = &dev->dev_data.emv_data;
uint32_t data_temp = 0; uint32_t data_temp = 0;
do { do {
@ -577,8 +577,8 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev)
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
bool parsed = false; bool parsed = false;
NfcEmvData* data = &dev->dev_data.emv_data; EmvData* data = &dev->dev_data.emv_data;
memset(data, 0, sizeof(NfcEmvData)); memset(data, 0, sizeof(EmvData));
uint32_t data_cnt = 0; uint32_t data_cnt = 0;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -700,7 +700,7 @@ static bool nfc_device_save_file(
bool saved = false; bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage); FlipperFormat* file = flipper_format_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data; FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -758,7 +758,7 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
static bool nfc_device_load_data(NfcDevice* dev, string_t path) { static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
bool parsed = false; bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage); FlipperFormat* file = flipper_format_file_alloc(dev->storage);
NfcDeviceCommonData* data = &dev->dev_data.nfc_data; FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
uint32_t data_cnt = 0; uint32_t data_cnt = 0;
string_t temp_str; string_t temp_str;
string_init(temp_str); string_init(temp_str);
@ -789,6 +789,7 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
if(!nfc_device_parse_format_string(dev, temp_str)) break; if(!nfc_device_parse_format_string(dev, temp_str)) break;
// Read and parse UID, ATQA and SAK // Read and parse UID, ATQA and SAK
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
if(!(data_cnt == 4 || data_cnt == 7)) break;
data->uid_len = data_cnt; data->uid_len = data_cnt;
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
@ -863,7 +864,7 @@ bool nfc_file_select(NfcDevice* dev) {
} }
void nfc_device_data_clear(NfcDeviceData* dev_data) { void nfc_device_data_clear(NfcDeviceData* dev_data) {
if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
mf_df_clear(&dev_data->mf_df_data); mf_df_clear(&dev_data->mf_df_data);
} }
} }

View File

@ -5,6 +5,8 @@
#include <storage/storage.h> #include <storage/storage.h>
#include <dialogs/dialogs.h> #include <dialogs/dialogs.h>
#include <furi_hal_nfc.h>
#include <lib/nfc_protocols/emv.h>
#include <lib/nfc_protocols/mifare_ultralight.h> #include <lib/nfc_protocols/mifare_ultralight.h>
#include <lib/nfc_protocols/mifare_classic.h> #include <lib/nfc_protocols/mifare_classic.h>
#include <lib/nfc_protocols/mifare_desfire.h> #include <lib/nfc_protocols/mifare_desfire.h>
@ -17,13 +19,6 @@
#define NFC_APP_EXTENSION ".nfc" #define NFC_APP_EXTENSION ".nfc"
#define NFC_APP_SHADOW_EXTENSION ".shd" #define NFC_APP_SHADOW_EXTENSION ".shd"
typedef enum {
NfcDeviceNfca,
NfcDeviceNfcb,
NfcDeviceNfcf,
NfcDeviceNfcv,
} NfcDeviceType;
typedef enum { typedef enum {
NfcDeviceProtocolUnknown, NfcDeviceProtocolUnknown,
NfcDeviceProtocolEMV, NfcDeviceProtocolEMV,
@ -40,38 +35,18 @@ typedef enum {
NfcDeviceSaveFormatMifareDesfire, NfcDeviceSaveFormatMifareDesfire,
} NfcDeviceSaveFormat; } NfcDeviceSaveFormat;
typedef struct {
uint8_t uid_len;
uint8_t uid[10];
uint8_t atqa[2];
uint8_t sak;
NfcDeviceType device;
NfcProtocol protocol;
} NfcDeviceCommonData;
typedef struct {
char name[32];
uint8_t aid[16];
uint16_t aid_len;
uint8_t number[10];
uint8_t number_len;
uint8_t exp_mon;
uint8_t exp_year;
uint16_t country_code;
uint16_t currency_code;
} NfcEmvData;
typedef struct { typedef struct {
uint8_t data[NFC_READER_DATA_MAX_SIZE]; uint8_t data[NFC_READER_DATA_MAX_SIZE];
uint16_t size; uint16_t size;
} NfcReaderRequestData; } NfcReaderRequestData;
typedef struct { typedef struct {
NfcDeviceCommonData nfc_data; FuriHalNfcDevData nfc_data;
NfcProtocol protocol;
NfcReaderRequestData reader_data; NfcReaderRequestData reader_data;
union { union {
NfcEmvData emv_data; EmvData emv_data;
MifareUlData mf_ul_data; MfUltralightData mf_ul_data;
MfClassicData mf_classic_data; MfClassicData mf_classic_data;
MifareDesfireData mf_df_data; MifareDesfireData mf_df_data;
}; };

View File

@ -40,7 +40,7 @@ struct Nfc {
NotificationApp* notifications; NotificationApp* notifications;
SceneManager* scene_manager; SceneManager* scene_manager;
NfcDevice* dev; NfcDevice* dev;
NfcDeviceCommonData dev_edit_data; FuriHalNfcDevData dev_edit_data;
char text_store[NFC_TEXT_STORE_SIZE + 1]; char text_store[NFC_TEXT_STORE_SIZE + 1];
string_t text_box_store; string_t text_box_store;

View File

@ -1,48 +1,14 @@
#include "nfc_types.h" #include "nfc_types.h"
const char* nfc_get_rfal_type(rfalNfcDevType type) { const char* nfc_get_dev_type(FuriHalNfcType type) {
if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { if(type == FuriHalNfcTypeA) {
return "NFC-A"; return "NFC-A";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) { } else if(type == FuriHalNfcTypeB) {
return "NFC-B"; return "NFC-B";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) { } else if(type == FuriHalNfcTypeF) {
return "NFC-F"; return "NFC-F";
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) { } else if(type == FuriHalNfcTypeV) {
return "NFC-V"; return "NFC-V";
} else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
return "NFC-ST25TB";
} else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) {
return "NFC-AP2P";
} else {
return "Unknown";
}
}
const char* nfc_get_dev_type(NfcDeviceType type) {
if(type == NfcDeviceNfca) {
return "NFC-A";
} else if(type == NfcDeviceNfcb) {
return "NFC-B";
} else if(type == NfcDeviceNfcf) {
return "NFC-F";
} else if(type == NfcDeviceNfcv) {
return "NFC-V";
} else {
return "Unknown";
}
}
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
if(type == RFAL_NFCA_T1T) {
return "T1T";
} else if(type == RFAL_NFCA_T2T) {
return "T2T";
} else if(type == RFAL_NFCA_T4T) {
return "T4T";
} else if(type == RFAL_NFCA_NFCDEP) {
return "NFCDEP";
} else if(type == RFAL_NFCA_T4T_NFCDEP) {
return "T4T_NFCDEP";
} else { } else {
return "Unknown"; return "Unknown";
} }

View File

@ -1,16 +1,8 @@
#pragma once #pragma once
#include "st_errno.h" #include "nfc_device.h"
#include "rfal_nfc.h"
#include <gui/view_dispatcher.h> const char* nfc_get_dev_type(FuriHalNfcType type);
#include "nfc_worker.h"
const char* nfc_get_rfal_type(rfalNfcDevType type);
const char* nfc_get_dev_type(NfcDeviceType type);
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type);
const char* nfc_guess_protocol(NfcProtocol protocol); const char* nfc_guess_protocol(NfcProtocol protocol);

View File

@ -2,7 +2,8 @@
#include <furi_hal.h> #include <furi_hal.h>
#include <lib/nfc_protocols/nfc_util.h> #include <lib/nfc_protocols/nfc_util.h>
#include <lib/nfc_protocols/emv_decoder.h> #include <lib/nfc_protocols/emv.h>
#include <lib/nfc_protocols/mifare_common.h>
#include <lib/nfc_protocols/mifare_ultralight.h> #include <lib/nfc_protocols/mifare_ultralight.h>
#include <lib/nfc_protocols/mifare_classic.h> #include <lib/nfc_protocols/mifare_classic.h>
#include <lib/nfc_protocols/mifare_desfire.h> #include <lib/nfc_protocols/mifare_desfire.h>
@ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) {
nfc_worker_emulate(nfc_worker); nfc_worker_emulate(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
nfc_worker_read_emv_app(nfc_worker); nfc_worker_read_emv_app(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadEMV) { } else if(nfc_worker->state == NfcWorkerStateReadEMVData) {
nfc_worker_read_emv(nfc_worker); nfc_worker_read_emv(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
nfc_worker_emulate_apdu(nfc_worker); nfc_worker_emulate_apdu(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) { } else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
nfc_worker_read_mifare_ul(nfc_worker); nfc_worker_read_mifare_ultralight(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
nfc_worker_emulate_mifare_ul(nfc_worker); nfc_worker_emulate_mifare_ul(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
nfc_worker_mifare_classic_dict_attack(nfc_worker); nfc_worker_mifare_classic_dict_attack(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
nfc_worker_read_mifare_desfire(nfc_worker); nfc_worker_read_mifare_desfire(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateField) {
nfc_worker_field(nfc_worker);
} }
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
furi_hal_power_insomnia_exit(); furi_hal_power_insomnia_exit();
@ -117,269 +116,114 @@ int32_t nfc_worker_task(void* context) {
} }
void nfc_worker_detect(NfcWorker* nfc_worker) { void nfc_worker_detect(NfcWorker* nfc_worker) {
rfalNfcDevice* dev_list;
rfalNfcDevice* dev;
uint8_t dev_cnt;
nfc_device_data_clear(nfc_worker->dev_data); nfc_device_data_clear(nfc_worker->dev_data);
NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data; NfcDeviceData* dev_data = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateDetect) { while(nfc_worker->state == NfcWorkerStateDetect) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { if(furi_hal_nfc_detect(nfc_data, 1000)) {
// Process first found device // Process first found device
dev = &dev_list[0]; if(nfc_data->type == FuriHalNfcTypeA) {
result->uid_len = dev->nfcidLen; if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
memcpy(result->uid, dev->nfcid, dev->nfcidLen); dev_data->protocol = NfcDeviceProtocolMifareUl;
if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
result->device = NfcDeviceNfca;
result->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
result->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
result->sak = dev->dev.nfca.selRes.sak;
if(mf_ul_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo,
dev->dev.nfca.sensRes.platformInfo,
dev->dev.nfca.selRes.sak)) {
result->protocol = NfcDeviceProtocolMifareUl;
} else if(mf_classic_check_card_type( } else if(mf_classic_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo, nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev->dev.nfca.sensRes.platformInfo, dev_data->protocol = NfcDeviceProtocolMifareClassic;
dev->dev.nfca.selRes.sak)) {
result->protocol = NfcDeviceProtocolMifareClassic;
} else if(mf_df_check_card_type( } else if(mf_df_check_card_type(
dev->dev.nfca.sensRes.anticollisionInfo, nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev->dev.nfca.sensRes.platformInfo, dev_data->protocol = NfcDeviceProtocolMifareDesfire;
dev->dev.nfca.selRes.sak)) { } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
result->protocol = NfcDeviceProtocolMifareDesfire; dev_data->protocol = NfcDeviceProtocolEMV;
} else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
result->protocol = NfcDeviceProtocolEMV;
} else { } else {
result->protocol = NfcDeviceProtocolUnknown; dev_data->protocol = NfcDeviceProtocolUnknown;
} }
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
result->device = NfcDeviceNfcb;
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
result->device = NfcDeviceNfcf;
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) {
result->device = NfcDeviceNfcv;
} }
// Notify caller and exit // Notify caller and exit
if(nfc_worker->callback) { if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
break; break;
} }
furi_hal_nfc_sleep();
osDelay(100); osDelay(100);
} }
} }
bool nfc_worker_emulate_uid_callback( void nfc_worker_emulate(NfcWorker* nfc_worker) {
uint8_t* buff_rx, FuriHalNfcTxRxContext tx_rx = {};
uint16_t buff_rx_len, FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
uint8_t* buff_tx,
uint16_t* buff_tx_len,
uint32_t* data_type,
void* context) {
furi_assert(context);
NfcWorker* nfc_worker = context;
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
reader_data->size = buff_rx_len / 8;
while(nfc_worker->state == NfcWorkerStateEmulate) {
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
reader_data->size = tx_rx.rx_bits / 8;
if(reader_data->size > 0) { if(reader_data->size > 0) {
memcpy(reader_data->data, buff_rx, reader_data->size); memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
if(nfc_worker->callback) { if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
} }
return true; } else {
FURI_LOG_E(TAG, "Failed to get reader commands");
}
} }
void nfc_worker_emulate(NfcWorker* nfc_worker) {
NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateEmulate) {
furi_hal_nfc_emulate_nfca(
data->uid,
data->uid_len,
data->atqa,
data->sak,
nfc_worker_emulate_uid_callback,
nfc_worker,
1000);
} }
} }
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
ReturnCode err; FuriHalNfcTxRxContext tx_rx = {};
rfalNfcDevice* dev_list;
EmvApplication emv_app = {}; EmvApplication emv_app = {};
uint8_t dev_cnt = 0;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
nfc_device_data_clear(result); nfc_device_data_clear(result);
while(nfc_worker->state == NfcWorkerStateReadEMVApp) { while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
memset(&emv_app, 0, sizeof(emv_app)); if(furi_hal_nfc_detect(nfc_data, 1000)) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
// Card was found. Check that it supports EMV // Card was found. Check that it supports EMV
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; result->protocol = NfcDeviceProtocolEMV;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; if(emv_search_application(&tx_rx, &emv_app)) {
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->nfc_data.protocol = NfcDeviceProtocolEMV;
FURI_LOG_D(TAG, "Send select PPSE command");
tx_len = emv_prepare_select_ppse(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Select PPSE responce parced");
// Notify caller and exit // Notify caller and exit
result->emv_data.aid_len = emv_app.aid_len; result->emv_data.aid_len = emv_app.aid_len;
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
if(nfc_worker->callback) { if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
break;
} else {
FURI_LOG_D(TAG, "Can't find pay application");
furi_hal_nfc_deactivate();
continue;
} }
} else { } else {
// Can't find EMV card
FURI_LOG_W(TAG, "Card doesn't support EMV"); FURI_LOG_W(TAG, "Card doesn't support EMV");
furi_hal_nfc_deactivate();
} }
} else { } else {
// Can't find EMV card
FURI_LOG_D(TAG, "Can't find any cards"); FURI_LOG_D(TAG, "Can't find any cards");
furi_hal_nfc_deactivate();
} }
furi_hal_nfc_sleep();
osDelay(20); osDelay(20);
} }
} }
void nfc_worker_read_emv(NfcWorker* nfc_worker) { void nfc_worker_read_emv(NfcWorker* nfc_worker) {
ReturnCode err; FuriHalNfcTxRxContext tx_rx = {};
rfalNfcDevice* dev_list;
EmvApplication emv_app = {}; EmvApplication emv_app = {};
uint8_t dev_cnt = 0;
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
nfc_device_data_clear(result); nfc_device_data_clear(result);
while(nfc_worker->state == NfcWorkerStateReadEMV) { while(nfc_worker->state == NfcWorkerStateReadEMVData) {
memset(&emv_app, 0, sizeof(emv_app)); if(furi_hal_nfc_detect(nfc_data, 1000)) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
// Card was found. Check that it supports EMV // Card was found. Check that it supports EMV
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; result->protocol = NfcDeviceProtocolEMV;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; if(emv_read_bank_card(&tx_rx, &emv_app)) {
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; result->emv_data.number_len = emv_app.card_number_len;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
memcpy( memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); result->emv_data.number, emv_app.card_number, result->emv_data.number_len);
result->nfc_data.protocol = NfcDeviceProtocolEMV;
FURI_LOG_D(TAG, "Send select PPSE command");
tx_len = emv_prepare_select_ppse(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Select PPSE responce parced");
result->emv_data.aid_len = emv_app.aid_len; result->emv_data.aid_len = emv_app.aid_len;
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
} else { if(emv_app.name_found) {
FURI_LOG_D(TAG, "Can't find pay application");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Starting application ...");
tx_len = emv_prepare_select_app(tx_buff, &emv_app);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during application selection request: %d", err);
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Select application response received. Start parsing response");
if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Card name: %s", emv_app.name);
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
} else if(emv_app.pdol.size > 0) {
FURI_LOG_D(TAG, "Can't find card name, but PDOL is present.");
} else {
FURI_LOG_D(TAG, "Can't find card name or PDOL");
furi_hal_nfc_deactivate();
continue;
} }
FURI_LOG_D(TAG, "Starting Get Processing Options command ...");
tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err);
furi_hal_nfc_deactivate();
continue;
}
if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) {
FURI_LOG_D(TAG, "Card number parsed");
result->emv_data.number_len = emv_app.card_number_len;
memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
// Notify caller and exit
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
}
break;
} else {
// Mastercard doesn't give PAN / card number as GPO response
// Iterate over all files found in application
bool pan_found = false;
for(uint8_t i = 0; (i < emv_app.afl.size) && !pan_found; i += 4) {
uint8_t sfi = emv_app.afl.data[i] >> 3;
uint8_t record_start = emv_app.afl.data[i + 1];
uint8_t record_end = emv_app.afl.data[i + 2];
// Iterate over all records in file
for(uint8_t record = record_start; record <= record_end; ++record) {
tx_len = emv_prepare_read_sfi_record(tx_buff, sfi, record);
err = furi_hal_nfc_data_exchange(
tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err != ERR_NONE) {
FURI_LOG_D(
TAG,
"Error reading application sfi %d, record %d",
sfi,
record);
}
if(emv_decode_read_sfi_record(rx_buff, *rx_len, &emv_app)) {
pan_found = true;
break;
}
}
}
if(pan_found) {
FURI_LOG_D(TAG, "Card PAN found");
result->emv_data.number_len = emv_app.card_number_len;
memcpy(
result->emv_data.number,
emv_app.card_number,
result->emv_data.number_len);
if(emv_app.exp_month) { if(emv_app.exp_month) {
result->emv_data.exp_mon = emv_app.exp_month; result->emv_data.exp_mon = emv_app.exp_month;
result->emv_data.exp_year = emv_app.exp_year; result->emv_data.exp_year = emv_app.exp_year;
@ -395,301 +239,102 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
break; break;
} else {
FURI_LOG_D(TAG, "Can't read card number");
}
furi_hal_nfc_deactivate();
} }
} else { } else {
// Can't find EMV card
FURI_LOG_W(TAG, "Card doesn't support EMV"); FURI_LOG_W(TAG, "Card doesn't support EMV");
furi_hal_nfc_deactivate();
} }
} else { } else {
// Can't find EMV card
FURI_LOG_D(TAG, "Can't find any cards"); FURI_LOG_D(TAG, "Can't find any cards");
furi_hal_nfc_deactivate();
} }
furi_hal_nfc_sleep();
osDelay(20); osDelay(20);
} }
} }
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
ReturnCode err; FuriHalNfcTxRxContext tx_rx = {};
uint8_t tx_buff[255] = {}; FuriHalNfcDevData params = {
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
NfcDeviceCommonData params = {
.uid = {0xCF, 0x72, 0xd4, 0x40}, .uid = {0xCF, 0x72, 0xd4, 0x40},
.uid_len = 4, .uid_len = 4,
.atqa = {0x00, 0x04}, .atqa = {0x00, 0x04},
.sak = 0x20, .sak = 0x20,
.device = NfcDeviceNfca, .type = FuriHalNfcTypeA,
.protocol = NfcDeviceProtocolEMV,
}; };
// Test RX data
const uint8_t debug_rx[] = {
0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
0x88, 0x00};
// Test TX data
const uint8_t debug_tx[] = {
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
0x00, 0x00};
while(nfc_worker->state == NfcWorkerStateEmulateApdu) { while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
FURI_LOG_D(TAG, "POS terminal detected"); FURI_LOG_D(TAG, "POS terminal detected");
// Read data from POS terminal if(emv_card_emulation(&tx_rx)) {
err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); FURI_LOG_D(TAG, "EMV card emulated");
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received Select PPSE");
} else {
FURI_LOG_D(TAG, "Error in 1st data exchange: select PPSE");
furi_hal_nfc_deactivate();
continue;
} }
FURI_LOG_D(TAG, "Transive SELECT PPSE ANS");
tx_len = emv_select_ppse_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received Select APP");
} else {
FURI_LOG_D(TAG, "Error in 2nd data exchange: select APP");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Transive SELECT APP ANS");
tx_len = emv_select_app_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Received PDOL");
} else {
FURI_LOG_D(TAG, "Error in 3rd data exchange: receive PDOL");
furi_hal_nfc_deactivate();
continue;
}
FURI_LOG_D(TAG, "Transive PDOL ANS");
tx_len = emv_get_proc_opt_ans(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Transive PDOL ANS");
} else {
FURI_LOG_D(TAG, "Error in 4rd data exchange: Transive PDOL ANS");
furi_hal_nfc_deactivate();
continue;
}
if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
FURI_LOG_D(TAG, "Failed long message test");
} else {
FURI_LOG_D(TAG, "Correct debug message received");
tx_len = sizeof(debug_tx);
err = furi_hal_nfc_data_exchange(
(uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
FURI_LOG_D(TAG, "Transive Debug message");
}
}
furi_hal_nfc_deactivate();
} else { } else {
FURI_LOG_D(TAG, "Can't find reader"); FURI_LOG_D(TAG, "Can't find reader");
} }
furi_hal_nfc_sleep();
osDelay(20); osDelay(20);
} }
} }
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
ReturnCode err; FuriHalNfcTxRxContext tx_rx = {};
rfalNfcDevice* dev_list; MfUltralightReader reader = {};
uint8_t dev_cnt = 0; MfUltralightData data = {};
uint8_t tx_buff[255] = {};
uint16_t tx_len = 0;
uint8_t* rx_buff;
uint16_t* rx_len;
MifareUlDevice mf_ul_read;
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
nfc_device_data_clear(result); FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateReadMifareUl) {
furi_hal_nfc_deactivate();
memset(&mf_ul_read, 0, sizeof(mf_ul_read));
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA &&
mf_ul_check_card_type(
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
dev_list[0].dev.nfca.sensRes.platformInfo,
dev_list[0].dev.nfca.selRes.sak)) {
// Get Mifare Ultralight version
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Reading tag version");
tx_len = mf_ul_prepare_get_version(tx_buff);
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
if(err == ERR_NONE) {
mf_ul_parse_get_version_response(rx_buff, &mf_ul_read);
FURI_LOG_D(
TAG,
"Mifare Ultralight Type: %d, Pages: %d",
mf_ul_read.data.type,
mf_ul_read.pages_to_read);
FURI_LOG_D(TAG, "Reading signature ...");
tx_len = mf_ul_prepare_read_signature(tx_buff);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Failed reading signature");
memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature));
} else {
mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read);
}
} else if(err == ERR_TIMEOUT) {
FURI_LOG_D(
TAG,
"Card doesn't respond to GET VERSION command. Setting default read parameters");
err = ERR_NONE;
mf_ul_set_default_version(&mf_ul_read);
// Reinit device
furi_hal_nfc_deactivate();
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
FURI_LOG_D(TAG, "Lost connection. Restarting search");
continue;
}
} else {
FURI_LOG_D(
TAG, "Error getting Mifare Ultralight version. Error code: %d", err);
continue;
}
if(mf_ul_read.support_fast_read) {
FURI_LOG_D(TAG, "Reading pages ...");
tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Failed reading pages");
continue;
} else {
mf_ul_parse_fast_read_response(
rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read);
}
FURI_LOG_D(TAG, "Reading 3 counters ...");
for(uint8_t i = 0; i < 3; i++) {
tx_len = mf_ul_prepare_read_cnt(tx_buff, i);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_W(TAG, "Failed reading Counter %d", i);
mf_ul_read.data.counter[i] = 0;
} else {
mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read);
}
}
FURI_LOG_D(TAG, "Checking tearing flags ...");
for(uint8_t i = 0; i < 3; i++) {
tx_len = mf_ul_prepare_check_tearing(tx_buff, i);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Error checking tearing flag %d", i);
mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
} else {
mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read);
}
}
} else {
// READ card with READ command (4 pages at a time)
for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) {
FURI_LOG_D(TAG, "Reading pages %d - %d ...", page, page + 3);
tx_len = mf_ul_prepare_read(tx_buff, page);
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
FURI_LOG_D(TAG, "Read pages %d - %d failed", page, page + 3);
continue;
} else {
mf_ul_parse_read_response(rx_buff, page, &mf_ul_read);
}
}
}
// Fill result data
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
result->nfc_data.protocol = NfcDeviceProtocolMifareUl;
memcpy(
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
result->mf_ul_data = mf_ul_read.data;
while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
if(furi_hal_nfc_detect(nfc_data, 300)) {
if(nfc_data->type == FuriHalNfcTypeA &&
mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading");
if(mf_ul_read_card(&tx_rx, &reader, &data)) {
result->protocol = NfcDeviceProtocolMifareUl;
result->mf_ul_data = data;
// Notify caller and exit // Notify caller and exit
if(nfc_worker->callback) { if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
break; break;
} else { } else {
FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight"); FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
}
} else {
FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
} }
} else { } else {
FURI_LOG_D(TAG, "Can't find any tags"); FURI_LOG_D(TAG, "Can't find any tags");
} }
furi_hal_nfc_sleep();
osDelay(100); osDelay(100);
} }
} }
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
MifareUlDevice mf_ul_emulate; MfUltralightEmulator emulator = {};
mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data); mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
furi_hal_nfc_emulate_nfca( furi_hal_nfc_emulate_nfca(
nfc_common->uid, nfc_data->uid,
nfc_common->uid_len, nfc_data->uid_len,
nfc_common->atqa, nfc_data->atqa,
nfc_common->sak, nfc_data->sak,
mf_ul_prepare_emulation_response, mf_ul_prepare_emulation_response,
&mf_ul_emulate, &emulator,
5000); 5000);
// Check if data was modified // Check if data was modified
if(mf_ul_emulate.data_changed) { if(emulator.data_changed) {
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; nfc_worker->dev_data->mf_ul_data = emulator.data;
if(nfc_worker->callback) { if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
} }
mf_ul_emulate.data_changed = false; emulator.data_changed = false;
} }
} }
} }
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
furi_assert(nfc_worker->callback); furi_assert(nfc_worker->callback);
rfalNfcDevice* dev_list;
rfalNfcDevice* dev;
NfcDeviceCommonData* nfc_common;
uint8_t dev_cnt = 0;
FuriHalNfcTxRxContext tx_rx_ctx = {}; FuriHalNfcTxRxContext tx_rx_ctx = {};
MfClassicAuthContext auth_ctx = {}; MfClassicAuthContext auth_ctx = {};
MfClassicReader reader = {}; MfClassicReader reader = {};
@ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
uint16_t curr_sector = 0; uint16_t curr_sector = 0;
uint8_t total_sectors = 0; uint8_t total_sectors = 0;
NfcWorkerEvent event; NfcWorkerEvent event;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
// Open dictionary // Open dictionary
nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage); nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
@ -710,14 +356,13 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
// Detect Mifare Classic card // Detect Mifare Classic card
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { if(furi_hal_nfc_detect(nfc_data, 300)) {
dev = &dev_list[0];
if(mf_classic_get_type( if(mf_classic_get_type(
dev->nfcid, nfc_data->uid,
dev->nfcidLen, nfc_data->uid_len,
dev->dev.nfca.sensRes.anticollisionInfo, nfc_data->atqa[0],
dev->dev.nfca.sensRes.platformInfo, nfc_data->atqa[1],
dev->dev.nfca.selRes.sak, nfc_data->sak,
&reader)) { &reader)) {
total_sectors = mf_classic_get_total_sectors_num(&reader); total_sectors = mf_classic_get_total_sectors_num(&reader);
if(reader.type == MfClassicType1k) { if(reader.type == MfClassicType1k) {
@ -745,7 +390,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector); mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
bool sector_key_found = false; bool sector_key_found = false;
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) { while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) { if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
if(!card_found_notified) { if(!card_found_notified) {
if(reader.type == MfClassicType1k) { if(reader.type == MfClassicType1k) {
@ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
uint8_t sectors_read = uint8_t sectors_read =
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
if(sectors_read) { if(sectors_read) {
dev = &dev_list[0];
nfc_common = &nfc_worker->dev_data->nfc_data;
nfc_common->uid_len = dev->dev.nfca.nfcId1Len;
nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
nfc_common->sak = dev->dev.nfca.selRes.sak;
nfc_common->protocol = NfcDeviceProtocolMifareClassic;
memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len);
event = NfcWorkerEventSuccess; event = NfcWorkerEventSuccess;
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
} else { } else {
event = NfcWorkerEventFail; event = NfcWorkerEventFail;
@ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
stream_free(nfc_worker->dict_stream); stream_free(nfc_worker->dict_stream);
} }
ReturnCode nfc_exchange_full(
uint8_t* tx_buff,
uint16_t tx_len,
uint8_t* rx_buff,
uint16_t rx_cap,
uint16_t* rx_len) {
ReturnCode err;
uint8_t* part_buff;
uint16_t* part_len;
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false);
if(*part_len > rx_cap) {
return ERR_OVERRUN;
}
memcpy(rx_buff, part_buff, *part_len);
*rx_len = *part_len;
while(err == ERR_NONE && rx_buff[0] == 0xAF) {
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false);
if(*part_len > rx_cap - *rx_len) {
return ERR_OVERRUN;
}
if(*part_len == 0) {
return ERR_PROTO;
}
memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1);
*rx_buff = *part_buff;
*rx_len += *part_len - 1;
}
return err;
}
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
ReturnCode err; ReturnCode err;
rfalNfcDevice* dev_list;
uint8_t dev_cnt = 0;
uint8_t tx_buff[64] = {}; uint8_t tx_buff[64] = {};
uint16_t tx_len = 0; uint16_t tx_len = 0;
uint8_t rx_buff[512] = {}; uint8_t rx_buff[512] = {};
@ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
NfcDeviceData* result = nfc_worker->dev_data; NfcDeviceData* result = nfc_worker->dev_data;
nfc_device_data_clear(result); nfc_device_data_clear(result);
MifareDesfireData* data = &result->mf_df_data; MifareDesfireData* data = &result->mf_df_data;
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
furi_hal_nfc_deactivate(); furi_hal_nfc_sleep();
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { if(!furi_hal_nfc_detect(nfc_data, 300)) {
osDelay(100); osDelay(100);
continue; continue;
} }
memset(data, 0, sizeof(MifareDesfireData)); memset(data, 0, sizeof(MifareDesfireData));
if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA || if(nfc_data->type != FuriHalNfcTypeA ||
!mf_df_check_card_type( !mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
dev_list[0].dev.nfca.sensRes.platformInfo,
dev_list[0].dev.nfca.selRes.sak)) {
FURI_LOG_D(TAG, "Tag is not DESFire"); FURI_LOG_D(TAG, "Tag is not DESFire");
osDelay(100); osDelay(100);
continue; continue;
@ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
FURI_LOG_D(TAG, "Found DESFire tag"); FURI_LOG_D(TAG, "Found DESFire tag");
// Fill non-DESFire result data result->protocol = NfcDeviceProtocolMifareDesfire;
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
result->nfc_data.device = NfcDeviceNfca;
result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
// Get DESFire version // Get DESFire version
tx_len = mf_df_prepare_get_version(tx_buff); tx_len = mf_df_prepare_get_version(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
continue; continue;
@ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
tx_len = mf_df_prepare_get_free_memory(tx_buff); tx_len = mf_df_prepare_get_free_memory(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err == ERR_NONE) { if(err == ERR_NONE) {
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
@ -935,7 +530,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
tx_len = mf_df_prepare_get_key_settings(tx_buff); tx_len = mf_df_prepare_get_key_settings(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
} else { } else {
@ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
&data->master_key_settings->key_version_head; &data->master_key_settings->key_version_head;
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue; continue;
@ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
tx_len = mf_df_prepare_get_application_ids(tx_buff); tx_len = mf_df_prepare_get_application_ids(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
} else { } else {
@ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
tx_len = mf_df_prepare_select_application(tx_buff, app->id); tx_len = mf_df_prepare_select_application(tx_buff, app->id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
continue; continue;
} }
tx_len = mf_df_prepare_get_key_settings(tx_buff); tx_len = mf_df_prepare_get_key_settings(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
} else { } else {
@ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(
tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
continue; continue;
@ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
} }
tx_len = mf_df_prepare_get_file_ids(tx_buff); tx_len = mf_df_prepare_get_file_ids(tx_buff);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
} else { } else {
@ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
for(MifareDesfireFile* file = app->file_head; file; file = file->next) { for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
continue; continue;
@ -1054,7 +652,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
break; break;
} }
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); err =
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
if(err != ERR_NONE) { if(err != ERR_NONE) {
FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
continue; continue;
@ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
break; break;
} }
} }
void nfc_worker_field(NfcWorker* nfc_worker) {
furi_hal_nfc_field_on();
while(nfc_worker->state == NfcWorkerStateField) {
osDelay(50);
}
furi_hal_nfc_field_off();
}

View File

@ -13,11 +13,11 @@ typedef enum {
NfcWorkerStateDetect, NfcWorkerStateDetect,
NfcWorkerStateEmulate, NfcWorkerStateEmulate,
NfcWorkerStateReadEMVApp, NfcWorkerStateReadEMVApp,
NfcWorkerStateReadEMV, NfcWorkerStateReadEMVData,
NfcWorkerStateEmulateApdu, NfcWorkerStateEmulateApdu,
NfcWorkerStateField, NfcWorkerStateField,
NfcWorkerStateReadMifareUl, NfcWorkerStateReadMifareUltralight,
NfcWorkerStateEmulateMifareUl, NfcWorkerStateEmulateMifareUltralight,
NfcWorkerStateReadMifareClassic, NfcWorkerStateReadMifareClassic,
NfcWorkerStateReadMifareDesfire, NfcWorkerStateReadMifareDesfire,
// Transition // Transition

View File

@ -4,19 +4,8 @@
#include "nfc_worker.h" #include "nfc_worker.h"
#include <furi.h> #include <furi.h>
#include <stdbool.h>
#include <lib/toolbox/stream/file_stream.h> #include <lib/toolbox/stream/file_stream.h>
#include <rfal_analogConfig.h>
#include <rfal_rf.h>
#include <rfal_nfc.h>
#include <rfal_nfca.h>
#include <rfal_nfcb.h>
#include <rfal_nfcf.h>
#include <rfal_nfcv.h>
#include <st25r3916.h>
#include <st25r3916_irq.h>
struct NfcWorker { struct NfcWorker {
FuriThread* thread; FuriThread* thread;
Storage* storage; Storage* storage;
@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker);
void nfc_worker_emulate(NfcWorker* nfc_worker); void nfc_worker_emulate(NfcWorker* nfc_worker);
void nfc_worker_field(NfcWorker* nfc_worker); void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker);
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);

View File

@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) { if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
submenu_add_item( submenu_add_item(
submenu, submenu,
"Run Compatible App", "Run Compatible App",
@ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
if(event.event == SubmenuIndexRunApp) { if(event.event == SubmenuIndexRunApp) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) { } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) { } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
} }
consumed = true; consumed = true;

View File

@ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start)
ADD_SCENE(nfc, read_card, ReadCard) ADD_SCENE(nfc, read_card, ReadCard)
ADD_SCENE(nfc, read_card_success, ReadCardSuccess) ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
ADD_SCENE(nfc, card_menu, CardMenu) ADD_SCENE(nfc, card_menu, CardMenu)
ADD_SCENE(nfc, not_implemented, NotImplemented)
ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, emulate_uid, EmulateUid)
ADD_SCENE(nfc, save_name, SaveName) ADD_SCENE(nfc, save_name, SaveName)
ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, save_success, SaveSuccess)

View File

@ -6,13 +6,13 @@ enum SubmenuDebugIndex {
}; };
void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_debug_on_enter(void* context) { void nfc_scene_debug_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
submenu_add_item( submenu_add_item(
@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) {
} }
bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_debug_on_exit(void* context) { void nfc_scene_debug_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -1,29 +1,29 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
if(type == InputTypeShort) { if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
} }
void nfc_scene_delete_on_enter(void* context) { void nfc_scene_delete_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup Custom Widget view // Setup Custom Widget view
char delete_str[64]; char temp_str[64];
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name); snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); widget_add_text_box_element(
nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
char uid_str[32]; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) { if(data->uid_len == 4) {
snprintf( snprintf(
uid_str, temp_str,
sizeof(uid_str), sizeof(temp_str),
"UID: %02X %02X %02X %02X", "UID: %02X %02X %02X %02X",
data->uid[0], data->uid[0],
data->uid[1], data->uid[1],
@ -31,8 +31,8 @@ void nfc_scene_delete_on_enter(void* context) {
data->uid[3]); data->uid[3]);
} else if(data->uid_len == 7) { } else if(data->uid_len == 7) {
snprintf( snprintf(
uid_str, temp_str,
sizeof(uid_str), sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X", "UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0], data->uid[0],
data->uid[1], data->uid[1],
@ -42,12 +42,13 @@ void nfc_scene_delete_on_enter(void* context) {
data->uid[5], data->uid[5],
data->uid[6]); data->uid[6]);
} }
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, uid_str); widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL; const char* protocol_name = NULL;
if(data->protocol == NfcDeviceProtocolEMV) { NfcProtocol protocol = nfc->dev->dev_data.protocol;
protocol_name = nfc_guess_protocol(data->protocol); if(protocol == NfcDeviceProtocolEMV) {
} else if(data->protocol == NfcDeviceProtocolMifareUl) { protocol_name = nfc_guess_protocol(protocol);
} else if(protocol == NfcDeviceProtocolMifareUl) {
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
} }
if(protocol_name) { if(protocol_name) {
@ -56,18 +57,17 @@ void nfc_scene_delete_on_enter(void* context) {
} }
// TODO change dinamically // TODO change dinamically
widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
char sak_str[16]; snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str);
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str); snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
char atqa_str[16]; widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str);
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, atqa_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
@ -79,14 +79,14 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart); nfc->scene_manager, NfcSceneStart);
} }
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_delete_on_exit(void* context) { void nfc_scene_delete_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
widget_reset(nfc->widget); widget_reset(nfc->widget);
} }

View File

@ -1,12 +1,12 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_delete_success_popup_callback(void* context) { void nfc_scene_delete_success_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
} }
void nfc_scene_delete_success_on_enter(void* context) { void nfc_scene_delete_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
@ -20,27 +20,21 @@ void nfc_scene_delete_success_on_enter(void* context) {
} }
bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventViewExit) { if(event.event == NfcCustomEventViewExit) {
return scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart); nfc->scene_manager, NfcSceneStart);
} }
} }
return false; return consumed;
} }
void nfc_scene_delete_success_on_exit(void* context) { void nfc_scene_delete_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
} }

View File

@ -36,19 +36,19 @@ void nfc_scene_device_info_on_enter(void* context) {
(nfc->dev->format == NfcDeviceSaveFormatBankCard); (nfc->dev->format == NfcDeviceSaveFormatBankCard);
// Setup Custom Widget view // Setup Custom Widget view
widget_add_text_box_element( widget_add_text_box_element(
nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name); nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false);
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
if(data_display_supported) { if(data_display_supported) {
widget_add_button_element( widget_add_button_element(
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
} }
char uid_str[32]; char temp_str[32];
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
if(data->uid_len == 4) { if(data->uid_len == 4) {
snprintf( snprintf(
uid_str, temp_str,
sizeof(uid_str), sizeof(temp_str),
"UID: %02X %02X %02X %02X", "UID: %02X %02X %02X %02X",
data->uid[0], data->uid[0],
data->uid[1], data->uid[1],
@ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) {
data->uid[3]); data->uid[3]);
} else if(data->uid_len == 7) { } else if(data->uid_len == 7) {
snprintf( snprintf(
uid_str, temp_str,
sizeof(uid_str), sizeof(temp_str),
"UID: %02X %02X %02X %02X %02X %02X %02X", "UID: %02X %02X %02X %02X %02X %02X %02X",
data->uid[0], data->uid[0],
data->uid[1], data->uid[1],
@ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) {
data->uid[5], data->uid[5],
data->uid[6]); data->uid[6]);
} }
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str);
const char* protocol_name = NULL; const char* protocol_name = NULL;
if(data->protocol == NfcDeviceProtocolEMV || NfcProtocol protocol = nfc->dev->dev_data.protocol;
data->protocol == NfcDeviceProtocolMifareDesfire) { if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) {
protocol_name = nfc_guess_protocol(data->protocol); protocol_name = nfc_guess_protocol(protocol);
} else if(data->protocol == NfcDeviceProtocolMifareUl) { } else if(protocol == NfcDeviceProtocolMifareUl) {
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
} else if(data->protocol == NfcDeviceProtocolMifareClassic) { } else if(protocol == NfcDeviceProtocolMifareClassic) {
protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
} }
if(protocol_name) { if(protocol_name) {
@ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) {
} }
// TODO change dinamically // TODO change dinamically
widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
char sak_str[16]; snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str); snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
char atqa_str[16]; widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str);
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
// Setup Data View // Setup Data View
if(nfc->dev->format == NfcDeviceSaveFormatUid) { if(nfc->dev->format == NfcDeviceSaveFormatUid) {
@ -99,7 +97,7 @@ void nfc_scene_device_info_on_enter(void* context) {
dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
TextBox* text_box = nfc->text_box; TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex); text_box_set_font(text_box, TextBoxFontHex);
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
@ -130,7 +128,7 @@ void nfc_scene_device_info_on_enter(void* context) {
widget_add_string_element( widget_add_string_element(
nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; EmvData* emv_data = &nfc->dev->dev_data.emv_data;
BankCard* bank_card = nfc->bank_card; BankCard* bank_card = nfc->bank_card;
bank_card_set_name(bank_card, emv_data->name); bank_card_set_name(bank_card, emv_data->name);
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
@ -212,21 +210,16 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_device_info_on_exit(void* context) { void nfc_scene_device_info_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear Custom Widget // Clear views
widget_reset(nfc->widget); widget_reset(nfc->widget);
if(nfc->dev->format == NfcDeviceSaveFormatUid) { if(nfc->dev->format == NfcDeviceSaveFormatUid) {
// Clear Dialog dialog_ex_reset(nfc->dialog_ex);
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_reset(dialog_ex);
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
// Clear TextBox
text_box_reset(nfc->text_box); text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
// Clear Bank Card
bank_card_clear(nfc->bank_card); bank_card_clear(nfc->bank_card);
} }
} }

View File

@ -1,36 +1,34 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
// Setup and start worker // Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
} }
bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) { if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10); notification_message(nfc->notifications, &sequence_blink_blue_10);
return true; consumed = true;
} }
return false;
return consumed;
} }
void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_reset(popup);
} }

View File

@ -5,13 +5,14 @@
#define NFC_MF_UL_DATA_CHANGED (1UL) #define NFC_MF_UL_DATA_CHANGED (1UL)
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
} }
void nfc_scene_emulate_mifare_ul_on_enter(void* context) { void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcEmulate); DOLPHIN_DEED(DolphinDeedNfcEmulate);
// Setup view // Setup view
@ -26,14 +27,14 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
nfc_worker_start( nfc_worker_start(
nfc->worker, nfc->worker,
NfcWorkerStateEmulateMifareUl, NfcWorkerStateEmulateMifareUltralight,
&nfc->dev->dev_data, &nfc->dev->dev_data,
nfc_emulate_mifare_ul_worker_callback, nfc_emulate_mifare_ul_worker_callback,
nfc); nfc);
} }
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeTick) { if(event.type == SceneManagerEventTypeTick) {
@ -55,11 +56,8 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
} }
void nfc_scene_emulate_mifare_ul_on_exit(void* context) { void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
} }

View File

@ -1,6 +1,8 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200)
enum { enum {
NfcSceneEmulateUidStateWidget, NfcSceneEmulateUidStateWidget,
NfcSceneEmulateUidStateTextBox, NfcSceneEmulateUidStateTextBox,
@ -28,14 +30,14 @@ void nfc_emulate_uid_textbox_callback(void* context) {
// Add widget with device name or inform that data received // Add widget with device name or inform that data received
static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget; Widget* widget = nfc->widget;
widget_reset(widget); widget_reset(widget);
string_t info_str; string_t info_str;
string_init(info_str); string_init(info_str);
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
widget_add_string_element(widget, 56, 32, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating UID");
if(strcmp(nfc->dev->dev_name, "")) { if(strcmp(nfc->dev->dev_name, "")) {
string_printf(info_str, "%s", nfc->dev->dev_name); string_printf(info_str, "%s", nfc->dev->dev_name);
} else { } else {
@ -45,7 +47,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
} }
string_strim(info_str); string_strim(info_str);
widget_add_text_box_element( widget_add_text_box_element(
widget, 56, 43, 70, 21, AlignLeft, AlignTop, string_get_cstr(info_str)); widget, 56, 43, 70, 21, AlignCenter, AlignTop, string_get_cstr(info_str), true);
string_clear(info_str); string_clear(info_str);
if(data_received) { if(data_received) {
widget_add_button_element( widget_add_button_element(
@ -95,13 +97,15 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
nfc_scene_emulate_uid_widget_config(nfc, true); nfc_scene_emulate_uid_widget_config(nfc, true);
} }
// Update TextBox data // Update TextBox data
if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) {
string_cat_printf(nfc->text_box_store, "R:"); string_cat_printf(nfc->text_box_store, "R:");
for(uint16_t i = 0; i < reader_data->size; i++) { for(uint16_t i = 0; i < reader_data->size; i++) {
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
} }
string_push_back(nfc->text_box_store, '\n'); string_push_back(nfc->text_box_store, '\n');
memset(reader_data, 0, sizeof(NfcReaderRequestData));
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
}
memset(reader_data, 0, sizeof(NfcReaderRequestData));
consumed = true; consumed = true;
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);

View File

@ -1,7 +1,7 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_field_on_enter(void* context) { void nfc_scene_field_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
furi_hal_nfc_field_on(); furi_hal_nfc_field_on();
@ -23,12 +23,9 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_field_on_exit(void* context) { void nfc_scene_field_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
notification_internal_message(nfc->notifications, &sequence_reset_blue);
Popup* popup = nfc->popup;
popup_reset(popup);
furi_hal_nfc_field_off(); furi_hal_nfc_field_off();
notification_internal_message(nfc->notifications, &sequence_reset_blue);
popup_reset(nfc->popup);
} }

View File

@ -1,7 +1,7 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_file_select_on_enter(void* context) { void nfc_scene_file_select_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Process file_select return // Process file_select return
if(nfc_file_select(nfc->dev)) { if(nfc_file_select(nfc->dev)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);

View File

@ -18,13 +18,13 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
} }
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) { void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_mifare_desfire_app_on_enter(void* context) { void nfc_scene_mifare_desfire_app_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
if(!app) { if(!app) {
@ -73,7 +73,8 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
} }
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -96,24 +97,24 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
return true; consumed = true;
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(state & 1) { if(state & 1) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_mifare_desfire_app_on_exit(void* context) { void nfc_scene_mifare_desfire_app_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear views
text_box_reset(nfc->text_box); text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -19,7 +19,7 @@ void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t inde
} }
void nfc_scene_mifare_desfire_data_on_enter(void* context) { void nfc_scene_mifare_desfire_data_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
@ -61,7 +61,8 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
} }
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
@ -76,7 +77,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
nfc->scene_manager, nfc->scene_manager,
NfcSceneMifareDesfireData, NfcSceneMifareDesfireData,
MifareDesfireDataStateItem + SubmenuIndexCardInfo); MifareDesfireDataStateItem + SubmenuIndexCardInfo);
return true; consumed = true;
} else { } else {
uint16_t index = event.event - SubmenuIndexDynamic; uint16_t index = event.event - SubmenuIndexDynamic;
scene_manager_set_scene_state( scene_manager_set_scene_state(
@ -84,25 +85,25 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
if(state >= MifareDesfireDataStateItem) { if(state >= MifareDesfireDataStateItem) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_mifare_desfire_data_on_exit(void* context) { void nfc_scene_mifare_desfire_data_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear views
text_box_reset(nfc->text_box); text_box_reset(nfc->text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -5,13 +5,13 @@ enum SubmenuIndex {
}; };
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) { void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_mifare_desfire_menu_on_enter(void* context) { void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
submenu_add_item( submenu_add_item(
@ -24,7 +24,8 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
} }
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) { if(event.event == SubmenuIndexSave) {
@ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_mifare_desfire_menu_on_exit(void* context) { void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -6,13 +6,13 @@ enum SubmenuIndex {
}; };
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_mifare_ul_menu_on_enter(void* context) { void nfc_scene_mifare_ul_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
submenu_add_item( submenu_add_item(
@ -26,7 +26,8 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) {
} }
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexSave) { if(event.event == SubmenuIndexSave) {
@ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true; consumed = true;
} else if(event.event == SubmenuIndexEmulate) { } else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
return scene_manager_search_and_switch_to_previous_scene( consumed =
nfc->scene_manager, NfcSceneStart); scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
} }
return false; return consumed;
} }
void nfc_scene_mifare_ul_menu_on_exit(void* context) { void nfc_scene_mifare_ul_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -1,42 +0,0 @@
#include "../nfc_i.h"
void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_not_implemented_on_enter(void* context) {
Nfc* nfc = (Nfc*)context;
// TODO Set data from worker
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back");
dialog_ex_set_header(dialog_ex, "Not implemented", 60, 24, AlignCenter, AlignCenter);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_not_implemented_dialog_callback);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
}
bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) {
return scene_manager_previous_scene(nfc->scene_manager);
}
}
return false;
}
void nfc_scene_not_implemented_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
}

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) { void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
} }
void nfc_scene_read_card_on_enter(void* context) { void nfc_scene_read_card_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead); DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view // Setup view
@ -22,29 +22,26 @@ void nfc_scene_read_card_on_enter(void* context) {
} }
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) { if(event.event == NfcCustomEventWorkerExit) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10); notification_message(nfc->notifications, &sequence_blink_blue_10);
return true; consumed = true;
} }
return false; return consumed;
} }
void nfc_scene_read_card_on_exit(void* context) { void nfc_scene_read_card_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
} }

View File

@ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback(
void* context) { void* context) {
furi_assert(context); furi_assert(context);
Nfc* nfc = context; Nfc* nfc = context;
if(type == InputTypeShort) { if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
} }
void nfc_scene_read_card_success_on_enter(void* context) { void nfc_scene_read_card_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
string_t data_str; string_t data_str;
string_t uid_str; string_t uid_str;
string_init(data_str); string_init(data_str);
@ -24,9 +26,9 @@ void nfc_scene_read_card_success_on_enter(void* context) {
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
// Setup view // Setup view
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
Widget* widget = nfc->widget; Widget* widget = nfc->widget;
string_set_str(data_str, nfc_get_dev_type(data->device)); string_set_str(data_str, nfc_get_dev_type(data->type));
string_set_str(uid_str, "UID:"); string_set_str(uid_str, "UID:");
for(uint8_t i = 0; i < data->uid_len; i++) { for(uint8_t i = 0; i < data->uid_len; i++) {
string_cat_printf(uid_str, " %02X", data->uid[i]); string_cat_printf(uid_str, " %02X", data->uid[i]);
@ -34,7 +36,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
if(data->device == NfcDeviceNfca) { if(data->type == FuriHalNfcTypeA) {
widget_add_button_element( widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc); widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
@ -44,7 +46,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
string_printf( string_printf(
data_str, data_str,
"%s\nATQA: %02X%02X SAK: %02X", "%s\nATQA: %02X%02X SAK: %02X",
nfc_guess_protocol(data->protocol), nfc_guess_protocol(nfc->dev->dev_data.protocol),
data->atqa[0], data->atqa[0],
data->atqa[1], data->atqa[1],
data->sak); data->sak);
@ -66,14 +68,14 @@ void nfc_scene_read_card_success_on_enter(void* context) {
} }
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc->scene_manager); consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(data->device == NfcDeviceNfca && event.event == GuiButtonTypeRight) { } else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu); scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
@ -84,6 +86,8 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
} }
void nfc_scene_read_card_success_on_exit(void* context) { void nfc_scene_read_card_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget); widget_reset(nfc->widget);
} }

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) { void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
} }
void nfc_scene_read_emv_app_on_enter(void* context) { void nfc_scene_read_emv_app_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead); DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view // Setup view
@ -26,31 +26,30 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
} }
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) { if(event.event == NfcCustomEventWorkerExit) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10); notification_message(nfc->notifications, &sequence_blink_blue_10);
return true; consumed = true;
} }
return false;
return consumed;
} }
void nfc_scene_read_emv_app_on_exit(void* context) { void nfc_scene_read_emv_app_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
} }

View File

@ -2,27 +2,38 @@
#include "../helpers/nfc_emv_parser.h" #include "../helpers/nfc_emv_parser.h"
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define NFC_SCENE_READ_SUCCESS_SHIFT " " void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) {
Nfc* nfc = context;
void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) { if(type == InputTypeShort) {
Nfc* nfc = (Nfc*)context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
}
void nfc_scene_read_emv_app_success_on_enter(void* context) { void nfc_scene_read_emv_app_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup view // Setup view
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; EmvData* emv_data = &nfc->dev->dev_data.emv_data;
DialogEx* dialog_ex = nfc->dialog_ex; Widget* widget = nfc->widget;
dialog_ex_set_left_button_text(dialog_ex, "Retry"); widget_add_button_element(
dialog_ex_set_right_button_text(dialog_ex, "Run app"); widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc);
dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter); widget_add_button_element(
dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc);
// Display UID and AID widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App");
widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21);
// Display UID
string_t temp_str;
string_init_printf(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
}
widget_add_string_element(
widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
string_reset(temp_str);
// Display application
string_printf(temp_str, "App: ");
string_t aid; string_t aid;
string_init(aid); string_init(aid);
bool aid_found = bool aid_found =
@ -32,19 +43,11 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
string_cat_printf(aid, "%02X", emv_data->aid[i]); string_cat_printf(aid, "%02X", emv_data->aid[i]);
} }
} }
nfc_text_store_set( string_cat(temp_str, aid);
nfc, widget_add_string_element(
NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
"Application:\n%s", string_clear(temp_str);
nfc_data->uid[0],
nfc_data->uid[1],
nfc_data->uid[2],
nfc_data->uid[3],
string_get_cstr(aid));
string_clear(aid); string_clear(aid);
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_emv_app_success_dialog_callback);
// Send notification // Send notification
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) == if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
@ -54,32 +57,27 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE); nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
} }
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
} }
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) { if(event.event == GuiButtonTypeLeft) {
return scene_manager_previous_scene(nfc->scene_manager); consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultRight) { } else if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm); scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_read_emv_app_success_on_exit(void* context) { void nfc_scene_read_emv_app_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex; // Clear views
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); widget_reset(nfc->widget);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
} }

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) { void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
} }
void nfc_scene_read_emv_data_on_enter(void* context) { void nfc_scene_read_emv_data_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead); DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view // Setup view
@ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
// Start worker // Start worker
nfc_worker_start( nfc_worker_start(
nfc->worker, nfc->worker,
NfcWorkerStateReadEMV, NfcWorkerStateReadEMVData,
&nfc->dev->dev_data, &nfc->dev->dev_data,
nfc_read_emv_data_worker_callback, nfc_read_emv_data_worker_callback,
nfc); nfc);
} }
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) { if(event.event == NfcCustomEventWorkerExit) {
scene_manager_set_scene_state( scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10); notification_message(nfc->notifications, &sequence_blink_blue_10);
return true; consumed = true;
} }
return false; return consumed;
} }
void nfc_scene_read_emv_data_on_exit(void* context) { void nfc_scene_read_emv_data_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
} }

View File

@ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback(
GuiButtonType result, GuiButtonType result,
InputType type, InputType type,
void* context) { void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
if(type == InputTypeShort) { if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
} }
void nfc_scene_read_emv_data_success_on_enter(void* context) { void nfc_scene_read_emv_data_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; EmvData* emv_data = &nfc->dev->dev_data.emv_data;
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Setup Custom Widget view // Setup Custom Widget view
@ -78,25 +78,23 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
string_clear(disp_currency); string_clear(disp_currency);
} }
string_clear(currency_name); string_clear(currency_name);
char temp_str[32];
// Add ATQA // Add ATQA
char atqa_str[16]; snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str);
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str);
// Add UID // Add UID
char uid_str[32];
snprintf( snprintf(
uid_str, temp_str,
sizeof(uid_str), sizeof(temp_str),
"UID: %02X %02X %02X %02X", "UID: %02X %02X %02X %02X",
nfc_data->uid[0], nfc_data->uid[0],
nfc_data->uid[1], nfc_data->uid[1],
nfc_data->uid[2], nfc_data->uid[2],
nfc_data->uid[3]); nfc_data->uid[3]);
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str); widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
// Add SAK // Add SAK
char sak_str[16]; snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak);
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str);
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
// Add expiration date // Add expiration date
if(emv_data->exp_mon) { if(emv_data->exp_mon) {
char exp_str[16]; char exp_str[16];
@ -117,28 +115,30 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
} }
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) { if(event.event == GuiButtonTypeLeft) {
return scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneReadEmvAppSuccess); nfc->scene_manager, NfcSceneReadEmvAppSuccess);
} else if(event.event == GuiButtonTypeRight) { } else if(event.event == GuiButtonTypeRight) {
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
nfc->dev->format = NfcDeviceSaveFormatBankCard; nfc->dev->format = NfcDeviceSaveFormatBankCard;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeBack) { } else if(event.type == SceneManagerEventTypeBack) {
return scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneReadEmvAppSuccess); nfc->scene_manager, NfcSceneReadEmvAppSuccess);
} }
return false; return consumed;
} }
void nfc_scene_read_emv_data_success_on_exit(void* context) { void nfc_scene_read_emv_data_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view
widget_reset(nfc->widget); widget_reset(nfc->widget);
} }

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) { void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
} }
void nfc_scene_read_mifare_desfire_on_enter(void* context) { void nfc_scene_read_mifare_desfire_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcRead); DOLPHIN_DEED(DolphinDeedNfcRead);
// Setup view // Setup view
@ -26,31 +26,28 @@ void nfc_scene_read_mifare_desfire_on_enter(void* context) {
} }
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) { if(event.event == NfcCustomEventWorkerExit) {
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
return true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } else if(event.type == SceneManagerEventTypeTick) {
notification_message(nfc->notifications, &sequence_blink_blue_10); notification_message(nfc->notifications, &sequence_blink_blue_10);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
return true; consumed = true;
} }
return false; return consumed;
} }
void nfc_scene_read_mifare_desfire_on_exit(void* context) { void nfc_scene_read_mifare_desfire_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
} }

View File

@ -9,13 +9,13 @@ enum {
}; };
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) { void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
DialogEx* dialog_ex = nfc->dialog_ex; DialogEx* dialog_ex = nfc->dialog_ex;
@ -67,9 +67,9 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
bool consumed = false;
uint32_t state = uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) { if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
@ -98,9 +98,8 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
} }
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) { void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clean dialog // Clean dialog
DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_reset(nfc->dialog_ex);
dialog_ex_reset(dialog_ex);
} }

View File

@ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
// Start worker // Start worker
nfc_worker_start( nfc_worker_start(
nfc->worker, nfc->worker,
NfcWorkerStateReadMifareUl, NfcWorkerStateReadMifareUltralight,
&nfc->dev->dev_data, &nfc->dev->dev_data,
nfc_read_mifare_ul_worker_callback, nfc_read_mifare_ul_worker_callback,
nfc); nfc);
@ -43,6 +43,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
void nfc_scene_read_mifare_ul_on_exit(void* context) { void nfc_scene_read_mifare_ul_on_exit(void* context) {
Nfc* nfc = context; Nfc* nfc = context;
// Stop worker // Stop worker
nfc_worker_stop(nfc->worker); nfc_worker_stop(nfc->worker);
// Clear view // Clear view

View File

@ -9,21 +9,21 @@ enum {
}; };
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
void nfc_scene_read_mifare_ul_success_on_enter(void* context) { void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
// Send notification // Send notification
notification_message(nfc->notifications, &sequence_success); notification_message(nfc->notifications, &sequence_success);
// Setup dialog view // Setup dialog view
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
DialogEx* dialog_ex = nfc->dialog_ex; DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_left_button_text(dialog_ex, "Retry");
dialog_ex_set_right_button_text(dialog_ex, "More"); dialog_ex_set_right_button_text(dialog_ex, "More");
@ -69,9 +69,9 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context; Nfc* nfc = context;
bool consumed = false;
uint32_t state = uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess); scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
@ -99,14 +99,10 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
} }
void nfc_scene_read_mifare_ul_success_on_exit(void* context) { void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clean dialog // Clean views
DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_reset(nfc->dialog_ex);
dialog_ex_reset(dialog_ex); text_box_reset(nfc->text_box);
// Clean TextBox
TextBox* text_box = nfc->text_box;
text_box_reset(text_box);
string_reset(nfc->text_box_store); string_reset(nfc->text_box_store);
} }

View File

@ -1,12 +1,12 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_restore_original_popup_callback(void* context) { void nfc_scene_restore_original_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
} }
void nfc_scene_restore_original_on_enter(void* context) { void nfc_scene_restore_original_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
Popup* popup = nfc->popup; Popup* popup = nfc->popup;
@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) {
} }
bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -32,15 +32,8 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event)
} }
void nfc_scene_restore_original_on_exit(void* context) { void nfc_scene_restore_original_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
} }

View File

@ -1,15 +1,13 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) { void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result); view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
} }
void nfc_scene_run_emv_app_confirm_on_enter(void* context) { void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex; DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_left_button_text(dialog_ex, "Back"); dialog_ex_set_left_button_text(dialog_ex, "Back");
@ -29,28 +27,23 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
} }
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultLeft) { if(event.event == DialogExResultLeft) {
return scene_manager_previous_scene(nfc->scene_manager); consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultRight) { } else if(event.event == DialogExResultRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_run_emv_app_confirm_on_exit(void* context) { void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex; // Clean view
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); dialog_ex_reset(nfc->dialog_ex);
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, NULL);
dialog_ex_set_right_button_text(dialog_ex, NULL);
dialog_ex_set_result_callback(dialog_ex, NULL);
dialog_ex_set_context(dialog_ex, NULL);
} }

View File

@ -3,13 +3,13 @@
#include <gui/modules/validators.h> #include <gui/modules/validators.h>
void nfc_scene_save_name_text_input_callback(void* context) { void nfc_scene_save_name_text_input_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
} }
void nfc_scene_save_name_on_enter(void* context) { void nfc_scene_save_name_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
TextInput* text_input = nfc->text_input; TextInput* text_input = nfc->text_input;
@ -37,7 +37,8 @@ void nfc_scene_save_name_on_enter(void* context) {
} }
bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventTextInputDone) { if(event.event == NfcCustomEventTextInputDone) {
@ -50,18 +51,18 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
if(nfc_device_save(nfc->dev, nfc->text_store)) { if(nfc_device_save(nfc->dev, nfc->text_store)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
return true; consumed = true;
} else { } else {
return scene_manager_search_and_switch_to_previous_scene( consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart); nfc->scene_manager, NfcSceneStart);
} }
} }
} }
return false; return consumed;
} }
void nfc_scene_save_name_on_exit(void* context) { void nfc_scene_save_name_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
void* validator_context = text_input_get_validator_callback_context(nfc->text_input); void* validator_context = text_input_get_validator_callback_context(nfc->text_input);

View File

@ -2,12 +2,12 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_scene_save_success_popup_callback(void* context) { void nfc_scene_save_success_popup_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
} }
void nfc_scene_save_success_on_enter(void* context) { void nfc_scene_save_success_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
DOLPHIN_DEED(DolphinDeedNfcSave); DOLPHIN_DEED(DolphinDeedNfcSave);
// Setup view // Setup view
@ -22,7 +22,7 @@ void nfc_scene_save_success_on_enter(void* context) {
} }
bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -47,15 +47,8 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_save_success_on_exit(void* context) { void nfc_scene_save_success_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
Popup* popup = nfc->popup; popup_reset(nfc->popup);
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
} }

View File

@ -9,13 +9,13 @@ enum SubmenuIndex {
}; };
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_saved_menu_on_enter(void* context) { void nfc_scene_saved_menu_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
if(nfc->dev->format == NfcDeviceSaveFormatUid || if(nfc->dev->format == NfcDeviceSaveFormatUid ||
@ -56,7 +56,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
} }
bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -92,7 +92,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_saved_menu_on_exit(void* context) { void nfc_scene_saved_menu_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -1,13 +1,13 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_set_atqa_byte_input_callback(void* context) { void nfc_scene_set_atqa_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
} }
void nfc_scene_set_atqa_on_enter(void* context) { void nfc_scene_set_atqa_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
ByteInput* byte_input = nfc->byte_input; ByteInput* byte_input = nfc->byte_input;
@ -23,19 +23,20 @@ void nfc_scene_set_atqa_on_enter(void* context) {
} }
bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) { if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_set_atqa_on_exit(void* context) { void nfc_scene_set_atqa_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -1,13 +1,13 @@
#include "../nfc_i.h" #include "../nfc_i.h"
void nfc_scene_set_sak_byte_input_callback(void* context) { void nfc_scene_set_sak_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
} }
void nfc_scene_set_sak_on_enter(void* context) { void nfc_scene_set_sak_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
ByteInput* byte_input = nfc->byte_input; ByteInput* byte_input = nfc->byte_input;
@ -23,19 +23,20 @@ void nfc_scene_set_sak_on_enter(void* context) {
} }
bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) { if(event.event == NfcCustomEventByteInputDone) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_set_sak_on_exit(void* context) { void nfc_scene_set_sak_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -6,13 +6,13 @@ enum SubmenuIndex {
}; };
void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_set_type_on_enter(void* context) { void nfc_scene_set_type_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
// Clear device name // Clear device name
nfc_device_set_name(nfc->dev, ""); nfc_device_set_name(nfc->dev, "");
@ -24,26 +24,27 @@ void nfc_scene_set_type_on_enter(void* context) {
} }
bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexNFCA7) { if(event.event == SubmenuIndexNFCA7) {
nfc->dev->dev_data.nfc_data.uid_len = 7; nfc->dev->dev_data.nfc_data.uid_len = 7;
nfc->dev->format = NfcDeviceSaveFormatUid; nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true; consumed = true;
} else if(event.event == SubmenuIndexNFCA4) { } else if(event.event == SubmenuIndexNFCA4) {
nfc->dev->dev_data.nfc_data.uid_len = 4; nfc->dev->dev_data.nfc_data.uid_len = 4;
nfc->dev->format = NfcDeviceSaveFormatUid; nfc->dev->format = NfcDeviceSaveFormatUid;
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_set_type_on_exit(void* context) { void nfc_scene_set_type_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -2,13 +2,13 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
void nfc_scene_set_uid_byte_input_callback(void* context) { void nfc_scene_set_uid_byte_input_callback(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
} }
void nfc_scene_set_uid_on_enter(void* context) { void nfc_scene_set_uid_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Setup view // Setup view
ByteInput* byte_input = nfc->byte_input; ByteInput* byte_input = nfc->byte_input;
@ -26,19 +26,20 @@ void nfc_scene_set_uid_on_enter(void* context) {
bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = (Nfc*)context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) { if(event.event == NfcCustomEventByteInputDone) {
DOLPHIN_DEED(DolphinDeedNfcAdd); DOLPHIN_DEED(DolphinDeedNfcAdd);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
return true; consumed = true;
} }
} }
return false; return consumed;
} }
void nfc_scene_set_uid_on_exit(void* context) { void nfc_scene_set_uid_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
// Clear view // Clear view
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);

View File

@ -9,13 +9,13 @@ enum SubmenuIndex {
}; };
void nfc_scene_start_submenu_callback(void* context, uint32_t index) { void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index); view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
} }
void nfc_scene_start_on_enter(void* context) { void nfc_scene_start_on_enter(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
Submenu* submenu = nfc->submenu; Submenu* submenu = nfc->submenu;
submenu_add_item( submenu_add_item(
@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) {
} }
bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
} }
void nfc_scene_start_on_exit(void* context) { void nfc_scene_start_on_exit(void* context) {
Nfc* nfc = (Nfc*)context; Nfc* nfc = context;
submenu_reset(nfc->submenu); submenu_reset(nfc->submenu);
} }

View File

@ -59,6 +59,8 @@ typedef enum {
NotificationMessageTypeForceSpeakerVolumeSetting, NotificationMessageTypeForceSpeakerVolumeSetting,
NotificationMessageTypeForceVibroSetting, NotificationMessageTypeForceVibroSetting,
NotificationMessageTypeForceDisplayBrightnessSetting, NotificationMessageTypeForceDisplayBrightnessSetting,
NotificationMessageTypeLedBrightnessSettingApply,
} NotificationMessageType; } NotificationMessageType;
typedef struct { typedef struct {

View File

@ -212,18 +212,21 @@ void notification_process_notification_message(
// store and send on delay or after seq // store and send on delay or after seq
led_active = true; led_active = true;
led_values[0] = notification_message->data.led.value; led_values[0] = notification_message->data.led.value;
app->led[0].value_last[LayerNotification] = led_values[0];
reset_mask |= reset_red_mask; reset_mask |= reset_red_mask;
break; break;
case NotificationMessageTypeLedGreen: case NotificationMessageTypeLedGreen:
// store and send on delay or after seq // store and send on delay or after seq
led_active = true; led_active = true;
led_values[1] = notification_message->data.led.value; led_values[1] = notification_message->data.led.value;
app->led[1].value_last[LayerNotification] = led_values[1];
reset_mask |= reset_green_mask; reset_mask |= reset_green_mask;
break; break;
case NotificationMessageTypeLedBlue: case NotificationMessageTypeLedBlue:
// store and send on delay or after seq // store and send on delay or after seq
led_active = true; led_active = true;
led_values[2] = notification_message->data.led.value; led_values[2] = notification_message->data.led.value;
app->led[2].value_last[LayerNotification] = led_values[2];
reset_mask |= reset_blue_mask; reset_mask |= reset_blue_mask;
break; break;
case NotificationMessageTypeVibro: case NotificationMessageTypeVibro:
@ -273,6 +276,16 @@ void notification_process_notification_message(
case NotificationMessageTypeForceDisplayBrightnessSetting: case NotificationMessageTypeForceDisplayBrightnessSetting:
display_brightness_setting = display_brightness_setting =
notification_message->data.forced_settings.display_brightness; notification_message->data.forced_settings.display_brightness;
break;
case NotificationMessageTypeLedBrightnessSettingApply:
led_active = true;
for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) {
led_values[i] = app->led[i].value_last[LayerNotification];
}
reset_mask |= reset_red_mask;
reset_mask |= reset_green_mask;
reset_mask |= reset_blue_mask;
break;
} }
notification_message_index++; notification_message_index++;
notification_message = (*message->sequence)[notification_message_index]; notification_message = (*message->sequence)[notification_message_index];
@ -316,23 +329,33 @@ void notification_process_internal_message(NotificationApp* app, NotificationApp
app, notification_message->data.led.value)); app, notification_message->data.led.value));
break; break;
case NotificationMessageTypeLedRed: case NotificationMessageTypeLedRed:
app->led[0].value_last[LayerInternal] = notification_message->data.led.value;
notification_apply_internal_led_layer( notification_apply_internal_led_layer(
&app->led[0], &app->led[0],
notification_settings_get_rgb_led_brightness( notification_settings_get_rgb_led_brightness(
app, notification_message->data.led.value)); app, notification_message->data.led.value));
break; break;
case NotificationMessageTypeLedGreen: case NotificationMessageTypeLedGreen:
app->led[1].value_last[LayerInternal] = notification_message->data.led.value;
notification_apply_internal_led_layer( notification_apply_internal_led_layer(
&app->led[1], &app->led[1],
notification_settings_get_rgb_led_brightness( notification_settings_get_rgb_led_brightness(
app, notification_message->data.led.value)); app, notification_message->data.led.value));
break; break;
case NotificationMessageTypeLedBlue: case NotificationMessageTypeLedBlue:
app->led[2].value_last[LayerInternal] = notification_message->data.led.value;
notification_apply_internal_led_layer( notification_apply_internal_led_layer(
&app->led[2], &app->led[2],
notification_settings_get_rgb_led_brightness( notification_settings_get_rgb_led_brightness(
app, notification_message->data.led.value)); app, notification_message->data.led.value));
break; break;
case NotificationMessageTypeLedBrightnessSettingApply:
for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) {
uint8_t new_val = notification_settings_get_rgb_led_brightness(
app, app->led[i].value_last[LayerInternal]);
notification_apply_internal_led_layer(&app->led[i], new_val);
}
break;
default: default:
break; break;
} }

View File

@ -25,6 +25,7 @@ typedef enum {
} NotificationLedLayerIndex; } NotificationLedLayerIndex;
typedef struct { typedef struct {
uint8_t value_last[LayerMAX];
uint8_t value[LayerMAX]; uint8_t value[LayerMAX];
NotificationLedLayerIndex index; NotificationLedLayerIndex index;
Light light; Light light;

View File

@ -82,12 +82,22 @@ static void screen_changed(VariableItem* item) {
notification_message(app->notification, &sequence_display_on); notification_message(app->notification, &sequence_display_on);
} }
const NotificationMessage apply_message = {
.type = NotificationMessageTypeLedBrightnessSettingApply,
};
const NotificationSequence apply_sequence = {
&apply_message,
NULL,
};
static void led_changed(VariableItem* item) { static void led_changed(VariableItem* item) {
NotificationAppSettings* app = variable_item_get_context(item); NotificationAppSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item); uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, backlight_text[index]); variable_item_set_current_value_text(item, backlight_text[index]);
app->notification->settings.led_brightness = backlight_value[index]; app->notification->settings.led_brightness = backlight_value[index];
notification_message(app->notification, &apply_sequence);
notification_internal_message(app->notification, &apply_sequence);
notification_message(app->notification, &sequence_blink_white_100); notification_message(app->notification, &sequence_blink_white_100);
} }

10
applications/power/power_service/power.c Executable file → Normal file
View File

@ -12,6 +12,8 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
furi_assert(context); furi_assert(context);
Power* power = context; Power* power = context;
canvas_draw_icon(canvas, 0, 1, &I_Battery_26x8); canvas_draw_icon(canvas, 0, 1, &I_Battery_26x8);
if(power->info.gauge_is_ok) {
canvas_draw_box(canvas, 2, 3, (power->info.charge + 4) / 5, 4); canvas_draw_box(canvas, 2, 3, (power->info.charge + 4) / 5, 4);
if(power->state == PowerStateCharging) { if(power->state == PowerStateCharging) {
canvas_set_bitmap_mode(canvas, 1); canvas_set_bitmap_mode(canvas, 1);
@ -21,6 +23,9 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_9x10); canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_9x10);
canvas_set_bitmap_mode(canvas, 0); canvas_set_bitmap_mode(canvas, 0);
} }
} else {
canvas_draw_box(canvas, 8, 4, 8, 2);
}
} }
static ViewPort* power_battery_view_port_alloc(Power* power) { static ViewPort* power_battery_view_port_alloc(Power* power) {
@ -119,6 +124,7 @@ static void power_check_charging_state(Power* power) {
static bool power_update_info(Power* power) { static bool power_update_info(Power* power) {
PowerInfo info; PowerInfo info;
info.gauge_is_ok = furi_hal_power_gauge_is_ok();
info.charge = furi_hal_power_get_pct(); info.charge = furi_hal_power_get_pct();
info.health = furi_hal_power_get_bat_health_pct(); info.health = furi_hal_power_get_bat_health_pct();
info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
@ -140,6 +146,10 @@ static bool power_update_info(Power* power) {
} }
static void power_check_low_battery(Power* power) { static void power_check_low_battery(Power* power) {
if(!power->info.gauge_is_ok) {
return;
}
// Check battery charge and vbus voltage // Check battery charge and vbus voltage
if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) && if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) &&
power->show_low_bat_level_message) { power->show_low_bat_level_message) {

View File

@ -29,6 +29,8 @@ typedef struct {
} PowerEvent; } PowerEvent;
typedef struct { typedef struct {
bool gauge_is_ok;
float current_charger; float current_charger;
float current_gauge; float current_gauge;

View File

@ -49,7 +49,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context; SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventSceneDelete) { if(event.event == SubGhzCustomEventSceneDelete) {
strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); strncpy(subghz->file_path_tmp, subghz->file_path, SUBGHZ_MAX_LEN_NAME);
if(subghz_delete_file(subghz)) { if(subghz_delete_file(subghz)) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
} else { } else {

View File

@ -21,10 +21,15 @@ void subghz_scene_delete_raw_on_enter(void* context) {
string_init(frequency_str); string_init(frequency_str);
string_init(modulation_str); string_init(modulation_str);
char delete_str[64]; char delete_str[SUBGHZ_MAX_LEN_NAME + 16];
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name); string_t file_name;
string_init(file_name);
path_extract_filename_no_ext(subghz->file_path, file_name);
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", string_get_cstr(file_name));
string_clear(file_name);
widget_add_text_box_element( widget_add_text_box_element(
subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
widget_add_string_element( widget_add_string_element(
subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
@ -56,7 +61,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
SubGhz* subghz = context; SubGhz* subghz = context;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubGhzCustomEventSceneDeleteRAW) { if(event.event == SubGhzCustomEventSceneDeleteRAW) {
strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); strncpy(subghz->file_path_tmp, subghz->file_path, SUBGHZ_MAX_LEN_NAME);
if(subghz_delete_file(subghz)) { if(subghz_delete_file(subghz)) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
} else { } else {

View File

@ -45,7 +45,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
return true; return true;
} else if(event.event == SubmenuIndexEdit) { } else if(event.event == SubmenuIndexEdit) {
memset(subghz->file_name_tmp, 0, sizeof(subghz->file_name_tmp)); memset(subghz->file_path_tmp, 0, sizeof(subghz->file_path_tmp));
scene_manager_set_scene_state( scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);

View File

@ -48,6 +48,8 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubGhzCustomEventSceneExit) { } else if(event.event == SubGhzCustomEventSceneExit) {
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart); subghz->scene_manager, SubGhzSceneStart);
} else { } else {

View File

@ -23,8 +23,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
break; break;
} }
path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); strncpy(subghz->file_path, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME);
strncpy(subghz->file_name, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME);
ret = true; ret = true;
} while(false); } while(false);
@ -66,19 +65,23 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
void subghz_scene_read_raw_on_enter(void* context) { void subghz_scene_read_raw_on_enter(void* context) {
SubGhz* subghz = context; SubGhz* subghz = context;
string_t file_name;
string_init(file_name);
switch(subghz->txrx->rx_key_state) { switch(subghz->txrx->rx_key_state) {
case SubGhzRxKeyStateBack: case SubGhzRxKeyStateBack:
subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, ""); subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "");
break; break;
case SubGhzRxKeyStateRAWLoad: case SubGhzRxKeyStateRAWLoad:
path_extract_filename_no_ext(subghz->file_path, file_name);
subghz_read_raw_set_status( subghz_read_raw_set_status(
subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, subghz->file_name); subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, string_get_cstr(file_name));
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
break; break;
case SubGhzRxKeyStateRAWSave: case SubGhzRxKeyStateRAWSave:
path_extract_filename_no_ext(subghz->file_path, file_name);
subghz_read_raw_set_status( subghz_read_raw_set_status(
subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, subghz->file_name); subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, string_get_cstr(file_name));
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
break; break;
default: default:
@ -86,14 +89,14 @@ void subghz_scene_read_raw_on_enter(void* context) {
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
break; break;
} }
string_clear(file_name);
subghz_scene_read_raw_update_statusbar(subghz); subghz_scene_read_raw_update_statusbar(subghz);
//set callback view raw //set callback view raw
subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
subghz->txrx->decoder_result = subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "RAW"); subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME);
furi_assert(subghz->txrx->decoder_result); furi_assert(subghz->txrx->decoder_result);
//set filter RAW feed //set filter RAW feed
@ -230,9 +233,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
}; };
subghz_protocol_raw_save_to_file_stop( subghz_protocol_raw_save_to_file_stop(
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, RAW_FILE_NAME);
subghz->state_notifications = SubGhzNotificationStateIDLE;
string_t temp_str;
string_init(temp_str);
string_printf(
temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(temp_str));
string_clear(temp_str);
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
return true; return true;

View File

@ -71,7 +71,10 @@ void subghz_scene_receiver_on_enter(void* context) {
string_init(str_buff); string_init(str_buff);
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz_history_reset(subghz->txrx->history); subghz_history_reset(subghz->txrx->history);
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
} }
//Load history to receiver //Load history to receiver
@ -120,8 +123,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz_sleep(subghz); subghz_sleep(subghz);
}; };
subghz->txrx->hopper_state = SubGhzHopperStateOFF; subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
subghz->txrx->idx_menu_chosen = 0; subghz->txrx->idx_menu_chosen = 0;
subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
@ -129,6 +130,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
} else { } else {
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
scene_manager_search_and_switch_to_previous_scene( scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart); subghz->scene_manager, SubGhzSceneStart);
} }

Some files were not shown because too many files have changed in this diff Show More