Merge branch 'release-candidate' into release

This commit is contained in:
Aleksandr Kutuzov 2022-04-25 15:50:08 +03:00
commit d21e5bd56e
No known key found for this signature in database
GPG Key ID: 0D0011717914BBCD
168 changed files with 2767 additions and 2253 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,10 +3,7 @@
#include <stdint.h>
#include <stdbool.h>
#define BT_SETTINGS_VERSION (0)
typedef struct {
uint8_t version;
bool enabled;
} 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() */
void animation_manager_interact_process(AnimationManager* animation_manager) {
bool animation_manager_interact_process(AnimationManager* animation_manager) {
furi_assert(animation_manager);
bool consumed = true;
if(animation_manager->levelup_pending) {
animation_manager->levelup_pending = false;
@ -181,7 +182,11 @@ void animation_manager_interact_process(AnimationManager* animation_manager) {
if(!blocked) {
animation_manager_start_new_idle(animation_manager);
}
} else {
consumed = false;
}
return consumed;
}
static void animation_manager_start_new_idle(AnimationManager* animation_manager) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -194,17 +194,18 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width);
/** Draw text box element
*
* @param canvas Canvas instance
* @param x x coordinate
* @param y y coordinate
* @param width width to fit text
* @param height height to fit text
* @param horizontal Align instance
* @param vertical Align instance
* @param[in] text Formatted text. The following formats are available:
* "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background
* @param canvas Canvas instance
* @param x x coordinate
* @param y y coordinate
* @param width width to fit text
* @param height height to fit text
* @param horizontal Align instance
* @param vertical Align instance
* @param[in] text Formatted text. The following formats are available:
* "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background
* @param strip_to_dots Strip text to ... if does not fit to width
*/
void elements_text_box(
Canvas* canvas,
@ -214,7 +215,8 @@ void elements_text_box(
uint8_t height,
Align horizontal,
Align vertical,
const char* text);
const char* text,
bool strip_to_dots);
#ifdef __cplusplus
}

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

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,
Align horizontal,
Align vertical,
const char* text) {
const char* text,
bool strip_to_dots) {
furi_assert(widget);
WidgetElement* text_box_element =
widget_element_text_box_create(x, y, width, height, horizontal, vertical, text);
WidgetElement* text_box_element = widget_element_text_box_create(
x, y, width, height, horizontal, vertical, text, strip_to_dots);
widget_add_element(widget, text_box_element);
}

View File

@ -81,17 +81,18 @@ void widget_add_string_element(
/** Add Text Box Element
*
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param width width to fit text
* @param height height to fit text
* @param horizontal Align instance
* @param vertical Align instance
* @param[in] text Formatted text. The following formats are available:
* "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background
* @param widget Widget instance
* @param x x coordinate
* @param y y coordinate
* @param width width to fit text
* @param height height to fit text
* @param horizontal Align instance
* @param vertical Align instance
* @param[in] text Formatted text. The following formats are available:
* "\e#Bold text\e#" - bold font is used
* "\e*Monospaced text\e*" - monospaced font is used
* "\e#Inversed text\e#" - white text on black background
* @param strip_to_dots Strip text to ... if does not fit to width
*/
void widget_add_text_box_element(
Widget* widget,
@ -101,7 +102,8 @@ void widget_add_text_box_element(
uint8_t height,
Align horizontal,
Align vertical,
const char* text);
const char* text,
bool strip_to_dots);
/** Add Button Element
*

View File

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

View File

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

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));
widget_add_text_box_element(
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store());
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false);
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);

View File

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

View File

@ -2,9 +2,9 @@
#include "../ibutton_app.h"
typedef enum {
SubmenuIndexWrite,
SubmenuIndexEmulate,
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexWrite,
} SubmenuIndex;
static void submenu_callback(void* context, uint32_t index) {
@ -22,11 +22,11 @@ void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) {
iButtonAppViewManager* view_manager = app->get_view_manager();
Submenu* submenu = view_manager->get_submenu();
submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app);
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) {
submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app);
}
submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app);
submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app);
submenu_set_selected_item(submenu, submenu_item_selected);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu);
@ -62,4 +62,4 @@ void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) {
Submenu* submenu = view->get_submenu();
submenu_reset(submenu);
}
}

View File

@ -14,14 +14,17 @@ int32_t InfraredApp::run(void* args) {
if(args) {
std::string path = static_cast<const char*>(args);
std::string remote_name(path, path.find_last_of('/') + 1, path.size());
remote_name.erase(remote_name.find_last_of('.'));
path.erase(path.find_last_of('/'));
bool result = remote_manager.load(path, remote_name);
if(result) {
current_scene = InfraredApp::Scene::Remote;
} else {
printf("Failed to load remote \'%s\'\r\n", remote_name.c_str());
return -1;
auto last_dot = remote_name.find_last_of('.');
if(last_dot != std::string::npos) {
remote_name.erase(last_dot);
path.erase(path.find_last_of('/'));
bool result = remote_manager.load(path, remote_name);
if(result) {
current_scene = InfraredApp::Scene::Remote;
} else {
printf("Failed to load remote \'%s\'\r\n", remote_name.c_str());
return -1;
}
}
}
@ -49,12 +52,14 @@ int32_t InfraredApp::run(void* args) {
InfraredApp::InfraredApp() {
furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size());
notification = static_cast<NotificationApp*>(furi_record_open("notification"));
dialogs = static_cast<DialogsApp*>(furi_record_open("dialogs"));
infrared_worker = infrared_worker_alloc();
}
InfraredApp::~InfraredApp() {
infrared_worker_free(infrared_worker);
furi_record_close("notification");
furi_record_close("dialogs");
for(auto& [key, scene] : scenes) delete scene;
}
@ -248,6 +253,10 @@ void InfraredApp::notify_blink_green() {
notification_message(notification, &sequence);
}
DialogsApp* InfraredApp::get_dialogs() {
return dialogs;
}
void InfraredApp::notify_green_on() {
notification_message(notification, &sequence_set_only_green_255);
}

View File

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

View File

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

View File

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

View File

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

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_icon(dialog_ex, 0, 0, NULL);
dialog_ex_set_left_button_text(dialog_ex, "Back");
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Delete");
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
dialog_ex_set_context(dialog_ex, app);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,19 +24,15 @@ static void input_cli_dump(Cli* cli, string_t args, Input* input) {
FuriPubSubSubscription* input_subscription =
furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue);
bool stop = false;
InputEvent input_event;
while(!stop) {
printf("Press CTRL+C to stop\r\n");
while(!cli_cmd_interrupt_received(cli)) {
if(osMessageQueueGet(input_queue, &input_event, NULL, 100) == osOK) {
printf(
"key: %s type: %s\r\n",
input_get_key_name(input_event.key),
input_get_type_name(input_event.type));
}
if(cli_cmd_interrupt_received(cli)) {
stop = true;
}
}
furi_pubsub_unsubscribe(input->event_pubsub, input_subscription);

View File

@ -1,17 +1,17 @@
#include "lfrfid_app_scene_read_menu.h"
typedef enum {
SubmenuWrite,
SubmenuSave,
SubmenuEmulate,
SubmenuWrite,
} SubmenuIndex;
void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
auto submenu = app->view_controller.get<SubmenuVM>();
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
submenu->add_item("Save", SubmenuSave, submenu_callback, app);
submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
if(need_restore) {
submenu->set_selected_item(submenu_item_selected);

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,19 +4,8 @@
#include "nfc_worker.h"
#include <furi.h>
#include <stdbool.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 {
FuriThread* thread;
Storage* storage;
@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker);
void nfc_worker_emulate(NfcWorker* nfc_worker);
void nfc_worker_field(NfcWorker* nfc_worker);
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker);
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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);
return true;
} else if(event.event == SubmenuIndexEdit) {
memset(subghz->file_name_tmp, 0, sizeof(subghz->file_name_tmp));
memset(subghz->file_path_tmp, 0, sizeof(subghz->file_path_tmp));
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);

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