mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-23 05:24:46 -07:00
Merge branch 'flipperdevices:dev' into dev
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
make assets_manifest
|
make assets_rebuild assets_manifest
|
||||||
git diff --quiet || ( echo "Assets recompilation required."; exit 255 )
|
git diff --quiet || ( echo "Assets recompilation required."; exit 255 )
|
||||||
|
|
||||||
- name: 'Build the firmware in docker'
|
- name: 'Build the firmware in docker'
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -79,7 +79,6 @@ ifeq ($(FORCE), 1)
|
|||||||
endif
|
endif
|
||||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
|
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
|
||||||
|
|
||||||
|
|
||||||
.PHONY: updater
|
.PHONY: updater
|
||||||
updater:
|
updater:
|
||||||
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all
|
@$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all
|
||||||
@@ -97,14 +96,16 @@ updater_package_bin: firmware_all updater
|
|||||||
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)"
|
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)"
|
||||||
|
|
||||||
.PHONY: updater_package
|
.PHONY: updater_package
|
||||||
updater_package: firmware_all updater
|
updater_package: firmware_all updater assets_manifest
|
||||||
@$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) -a assets/resources --bundlever "$(VERSION_STRING)"
|
@$(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
|
.PHONY: assets_manifest
|
||||||
assets_manifest:
|
assets_manifest:
|
||||||
@$(MAKE) -C $(PROJECT_ROOT)/assets clean
|
@$(MAKE) -C $(PROJECT_ROOT)/assets manifest
|
||||||
@$(MAKE) -C $(PROJECT_ROOT)/assets
|
|
||||||
@$(PROJECT_ROOT)/scripts/assets.py manifest assets/resources
|
.PHONY: assets_rebuild
|
||||||
|
assets_rebuild:
|
||||||
|
@$(MAKE) -C $(PROJECT_ROOT)/assets clean all
|
||||||
|
|
||||||
.PHONY: flash_radio
|
.PHONY: flash_radio
|
||||||
flash_radio:
|
flash_radio:
|
||||||
@@ -124,8 +125,8 @@ flash_radio_fus:
|
|||||||
|
|
||||||
.PHONY: flash_radio_fus_please_i_m_not_going_to_complain
|
.PHONY: flash_radio_fus_please_i_m_not_going_to_complain
|
||||||
flash_radio_fus_please_i_m_not_going_to_complain:
|
flash_radio_fus_please_i_m_not_going_to_complain:
|
||||||
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin
|
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin
|
||||||
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin
|
@$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin
|
||||||
@$(PROJECT_ROOT)/scripts/ob.py set
|
@$(PROJECT_ROOT)/scripts/ob.py set
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ extern int32_t usb_test_app(void* p);
|
|||||||
extern int32_t vibro_test_app(void* p);
|
extern int32_t vibro_test_app(void* p);
|
||||||
extern int32_t bt_hid_app(void* p);
|
extern int32_t bt_hid_app(void* p);
|
||||||
extern int32_t battery_test_app(void* p);
|
extern int32_t battery_test_app(void* p);
|
||||||
|
extern int32_t text_box_test_app(void* p);
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
extern int32_t music_player_app(void* p);
|
extern int32_t music_player_app(void* p);
|
||||||
@@ -304,6 +305,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
|||||||
#ifdef APP_BATTERY_TEST
|
#ifdef APP_BATTERY_TEST
|
||||||
{.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL},
|
{.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef APP_TEXT_BOX_TEST
|
||||||
|
{.app = text_box_test_app, .name = "Text Box Test", .stack_size = 1024, .icon = NULL},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS);
|
const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS);
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ CFLAGS += -DAPP_DISPLAY_TEST
|
|||||||
SRV_GUI = 1
|
SRV_GUI = 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
APP_TEXT_BOX_TEST ?= 0
|
||||||
|
ifeq ($(APP_TEXT_BOX_TEST), 1)
|
||||||
|
CFLAGS += -DAPP_TEXT_BOX_TEST
|
||||||
|
SRV_GUI = 1
|
||||||
|
endif
|
||||||
|
|
||||||
APP_BATTERY_TEST ?= 0
|
APP_BATTERY_TEST ?= 0
|
||||||
ifeq ($(APP_BATTERY_TEST), 1)
|
ifeq ($(APP_BATTERY_TEST), 1)
|
||||||
CFLAGS += -DAPP_BATTERY_TEST
|
CFLAGS += -DAPP_BATTERY_TEST
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ void archive_scene_delete_on_enter(void* context) {
|
|||||||
|
|
||||||
char delete_str[64];
|
char delete_str[64];
|
||||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name);
|
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name);
|
||||||
widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
|
widget_add_text_box_element(
|
||||||
|
app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget);
|
view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget);
|
||||||
}
|
}
|
||||||
|
|||||||
126
applications/debug_tools/text_box_test.c
Normal file
126
applications/debug_tools/text_box_test.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <input/input.h>
|
||||||
|
#include <gui/elements.h>
|
||||||
|
|
||||||
|
#define TAG "TextBoxTest"
|
||||||
|
|
||||||
|
static void text_box_center_top_secondary_128x22(Canvas* canvas) {
|
||||||
|
canvas_draw_frame(canvas, 0, 0, 128, 22);
|
||||||
|
elements_text_box(canvas, 0, 0, 128, 22, AlignCenter, AlignTop, "secondary font test", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_box_right_bottom_bold_128x22(Canvas* canvas) {
|
||||||
|
canvas_draw_frame(canvas, 0, 0, 128, 22);
|
||||||
|
elements_text_box(
|
||||||
|
canvas, 0, 0, 128, 22, AlignRight, AlignBottom, "\e#Bold font test\e#", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_box_left_center_mixed_80x50(Canvas* canvas) {
|
||||||
|
canvas_draw_frame(canvas, 0, 0, 80, 50);
|
||||||
|
elements_text_box(
|
||||||
|
canvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
80,
|
||||||
|
50,
|
||||||
|
AlignLeft,
|
||||||
|
AlignCenter,
|
||||||
|
"\e#Never\e# gonna give you up\n\e!Never\e! gonna let you down",
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_box_center_center_secondary_110x44(Canvas* canvas) {
|
||||||
|
canvas_draw_frame(canvas, 4, 20, 110, 30);
|
||||||
|
elements_text_box(
|
||||||
|
canvas,
|
||||||
|
4,
|
||||||
|
20,
|
||||||
|
110,
|
||||||
|
30,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
"Loooooooooooooo0000000ooong file name from happy 100500 Flipper 0wners",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void (*text_box_test_render[])(Canvas* canvas) = {
|
||||||
|
text_box_center_top_secondary_128x22,
|
||||||
|
text_box_right_bottom_bold_128x22,
|
||||||
|
text_box_left_center_mixed_80x50,
|
||||||
|
text_box_center_center_secondary_110x44,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t idx;
|
||||||
|
} TextBoxTestState;
|
||||||
|
|
||||||
|
static void text_box_test_render_callback(Canvas* canvas, void* ctx) {
|
||||||
|
TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25);
|
||||||
|
canvas_clear(canvas);
|
||||||
|
|
||||||
|
text_box_test_render[state->idx](canvas);
|
||||||
|
|
||||||
|
release_mutex((ValueMutex*)ctx, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_box_test_input_callback(InputEvent* input_event, void* ctx) {
|
||||||
|
osMessageQueueId_t event_queue = ctx;
|
||||||
|
osMessageQueuePut(event_queue, input_event, 0, osWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t text_box_test_app(void* p) {
|
||||||
|
osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(InputEvent), NULL);
|
||||||
|
furi_check(event_queue);
|
||||||
|
|
||||||
|
TextBoxTestState _state = {.idx = 0};
|
||||||
|
|
||||||
|
ValueMutex state_mutex;
|
||||||
|
if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) {
|
||||||
|
FURI_LOG_E(TAG, "Cannot create mutex");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
|
||||||
|
view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex);
|
||||||
|
view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue);
|
||||||
|
|
||||||
|
// Open GUI and register view_port
|
||||||
|
Gui* gui = furi_record_open("gui");
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||||
|
|
||||||
|
uint32_t test_renders_num = SIZEOF_ARRAY(text_box_test_render);
|
||||||
|
InputEvent event;
|
||||||
|
while(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK) {
|
||||||
|
TextBoxTestState* state = acquire_mutex_block(&state_mutex);
|
||||||
|
|
||||||
|
if(event.type == InputTypeShort) {
|
||||||
|
if(event.key == InputKeyRight) {
|
||||||
|
if(state->idx < test_renders_num - 1) {
|
||||||
|
state->idx++;
|
||||||
|
}
|
||||||
|
} else if(event.key == InputKeyLeft) {
|
||||||
|
if(state->idx > 0) {
|
||||||
|
state->idx--;
|
||||||
|
}
|
||||||
|
} else if(event.key == InputKeyBack) {
|
||||||
|
release_mutex(&state_mutex, state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release_mutex(&state_mutex, state);
|
||||||
|
view_port_update(view_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove & free all stuff created by app
|
||||||
|
gui_remove_view_port(gui, view_port);
|
||||||
|
view_port_free(view_port);
|
||||||
|
osMessageQueueDelete(event_queue);
|
||||||
|
delete_mutex(&state_mutex);
|
||||||
|
|
||||||
|
furi_record_close("gui");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -547,7 +547,8 @@ void elements_text_box(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text) {
|
const char* text,
|
||||||
|
bool strip_to_dots) {
|
||||||
furi_assert(canvas);
|
furi_assert(canvas);
|
||||||
|
|
||||||
ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM];
|
ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM];
|
||||||
@@ -571,6 +572,7 @@ void elements_text_box(
|
|||||||
uint8_t total_height_default = 0;
|
uint8_t total_height_default = 0;
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
bool full_text_processed = false;
|
bool full_text_processed = false;
|
||||||
|
uint16_t dots_width = canvas_string_width(canvas, "...");
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
|
||||||
@@ -663,7 +665,6 @@ void elements_text_box(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set vertical alignment for all lines
|
// Set vertical alignment for all lines
|
||||||
if(full_text_processed) {
|
|
||||||
if(total_height_default < height) {
|
if(total_height_default < height) {
|
||||||
if(vertical == AlignTop) {
|
if(vertical == AlignTop) {
|
||||||
line[0].y = y + line[0].height;
|
line[0].y = y + line[0].height;
|
||||||
@@ -688,7 +689,6 @@ void elements_text_box(
|
|||||||
j = j % (line_num - 1) + 1;
|
j = j % (line_num - 1) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw line by line
|
// Draw line by line
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
@@ -733,6 +733,13 @@ void elements_text_box(
|
|||||||
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
|
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
|
||||||
canvas_invert_color(canvas);
|
canvas_invert_color(canvas);
|
||||||
} else {
|
} else {
|
||||||
|
if((i == line_num - 1) && strip_to_dots) {
|
||||||
|
uint8_t next_symbol_width = canvas_glyph_width(canvas, line[i].text[j]);
|
||||||
|
if(line[i].x + next_symbol_width + dots_width > x + width) {
|
||||||
|
canvas_draw_str(canvas, line[i].x, line[i].y, "...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
|
canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]);
|
||||||
}
|
}
|
||||||
line[i].x += canvas_glyph_width(canvas, line[i].text[j]);
|
line[i].x += canvas_glyph_width(canvas, line[i].text[j]);
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width);
|
|||||||
* "\e#Bold text\e#" - bold font is used
|
* "\e#Bold text\e#" - bold font is used
|
||||||
* "\e*Monospaced text\e*" - monospaced font is used
|
* "\e*Monospaced text\e*" - monospaced font is used
|
||||||
* "\e#Inversed text\e#" - white text on black background
|
* "\e#Inversed text\e#" - white text on black background
|
||||||
|
* @param strip_to_dots Strip text to ... if does not fit to width
|
||||||
*/
|
*/
|
||||||
void elements_text_box(
|
void elements_text_box(
|
||||||
Canvas* canvas,
|
Canvas* canvas,
|
||||||
@@ -214,7 +215,8 @@ void elements_text_box(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text);
|
const char* text,
|
||||||
|
bool strip_to_dots);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
7
applications/gui/modules/widget.c
Executable file → Normal file
7
applications/gui/modules/widget.c
Executable file → Normal file
@@ -154,10 +154,11 @@ void widget_add_text_box_element(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text) {
|
const char* text,
|
||||||
|
bool strip_to_dots) {
|
||||||
furi_assert(widget);
|
furi_assert(widget);
|
||||||
WidgetElement* text_box_element =
|
WidgetElement* text_box_element = widget_element_text_box_create(
|
||||||
widget_element_text_box_create(x, y, width, height, horizontal, vertical, text);
|
x, y, width, height, horizontal, vertical, text, strip_to_dots);
|
||||||
widget_add_element(widget, text_box_element);
|
widget_add_element(widget, text_box_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ void widget_add_string_element(
|
|||||||
* "\e#Bold text\e#" - bold font is used
|
* "\e#Bold text\e#" - bold font is used
|
||||||
* "\e*Monospaced text\e*" - monospaced font is used
|
* "\e*Monospaced text\e*" - monospaced font is used
|
||||||
* "\e#Inversed text\e#" - white text on black background
|
* "\e#Inversed text\e#" - white text on black background
|
||||||
|
* @param strip_to_dots Strip text to ... if does not fit to width
|
||||||
*/
|
*/
|
||||||
void widget_add_text_box_element(
|
void widget_add_text_box_element(
|
||||||
Widget* widget,
|
Widget* widget,
|
||||||
@@ -101,7 +102,8 @@ void widget_add_text_box_element(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text);
|
const char* text,
|
||||||
|
bool strip_to_dots);
|
||||||
|
|
||||||
/** Add Button Element
|
/** Add Button Element
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ WidgetElement* widget_element_text_box_create(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text);
|
const char* text,
|
||||||
|
bool strip_to_dots);
|
||||||
|
|
||||||
/** Create button element */
|
/** Create button element */
|
||||||
WidgetElement* widget_element_button_create(
|
WidgetElement* widget_element_button_create(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ typedef struct {
|
|||||||
Align horizontal;
|
Align horizontal;
|
||||||
Align vertical;
|
Align vertical;
|
||||||
string_t text;
|
string_t text;
|
||||||
|
bool strip_to_dots;
|
||||||
} GuiTextBoxModel;
|
} GuiTextBoxModel;
|
||||||
|
|
||||||
static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) {
|
static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) {
|
||||||
@@ -26,7 +27,8 @@ static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) {
|
|||||||
model->height,
|
model->height,
|
||||||
model->horizontal,
|
model->horizontal,
|
||||||
model->vertical,
|
model->vertical,
|
||||||
string_get_cstr(model->text));
|
string_get_cstr(model->text),
|
||||||
|
model->strip_to_dots);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +48,8 @@ WidgetElement* widget_element_text_box_create(
|
|||||||
uint8_t height,
|
uint8_t height,
|
||||||
Align horizontal,
|
Align horizontal,
|
||||||
Align vertical,
|
Align vertical,
|
||||||
const char* text) {
|
const char* text,
|
||||||
|
bool strip_to_dots) {
|
||||||
furi_assert(text);
|
furi_assert(text);
|
||||||
|
|
||||||
// Allocate and init model
|
// Allocate and init model
|
||||||
@@ -58,6 +61,7 @@ WidgetElement* widget_element_text_box_create(
|
|||||||
model->horizontal = horizontal;
|
model->horizontal = horizontal;
|
||||||
model->vertical = vertical;
|
model->vertical = vertical;
|
||||||
string_init_set_str(model->text, text);
|
string_init_set_str(model->text, text);
|
||||||
|
model->strip_to_dots = strip_to_dots;
|
||||||
|
|
||||||
// Allocate and init Element
|
// Allocate and init Element
|
||||||
WidgetElement* gui_string = malloc(sizeof(WidgetElement));
|
WidgetElement* gui_string = malloc(sizeof(WidgetElement));
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) {
|
|||||||
|
|
||||||
app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key));
|
app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key));
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store());
|
widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false);
|
||||||
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
|
widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app);
|
||||||
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);
|
widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) {
|
|||||||
|
|
||||||
app->set_text_store("%s", ibutton_key_get_name_p(key));
|
app->set_text_store("%s", ibutton_key_get_name_p(key));
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store());
|
widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store(), false);
|
||||||
|
|
||||||
switch(ibutton_key_get_type(key)) {
|
switch(ibutton_key_get_type(key)) {
|
||||||
case iButtonKeyDS1990:
|
case iButtonKeyDS1990:
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ void InfraredAppSceneEdit::on_enter(InfraredApp* app) {
|
|||||||
InfraredAppViewManager* view_manager = app->get_view_manager();
|
InfraredAppViewManager* view_manager = app->get_view_manager();
|
||||||
Submenu* submenu = view_manager->get_submenu();
|
Submenu* submenu = view_manager->get_submenu();
|
||||||
|
|
||||||
submenu_add_item(submenu, "Add Key", SubmenuIndexAddKey, submenu_callback, app);
|
submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app);
|
||||||
submenu_add_item(submenu, "Rename Key", SubmenuIndexRenameKey, submenu_callback, app);
|
submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app);
|
||||||
submenu_add_item(submenu, "Delete Key", SubmenuIndexDeleteKey, submenu_callback, app);
|
submenu_add_item(submenu, "Delete Button", SubmenuIndexDeleteKey, submenu_callback, app);
|
||||||
submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app);
|
submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app);
|
||||||
submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app);
|
submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app);
|
||||||
submenu_set_selected_item(submenu, submenu_item_selected);
|
submenu_set_selected_item(submenu, submenu_item_selected);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) {
|
|||||||
|
|
||||||
dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter);
|
dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter);
|
||||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "Delete");
|
dialog_ex_set_right_button_text(dialog_ex, "Delete");
|
||||||
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
|
dialog_ex_set_result_callback(dialog_ex, dialog_result_callback);
|
||||||
dialog_ex_set_context(dialog_ex, app);
|
dialog_ex_set_context(dialog_ex, app);
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) {
|
|||||||
Submenu* submenu = view_manager->get_submenu();
|
Submenu* submenu = view_manager->get_submenu();
|
||||||
int item_number = 0;
|
int item_number = 0;
|
||||||
|
|
||||||
const char* header =
|
const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ?
|
||||||
app->get_edit_action() == InfraredApp::EditAction::Rename ? "Rename key:" : "Delete key:";
|
"Rename Button:" :
|
||||||
|
"Delete Button:";
|
||||||
submenu_set_header(submenu, header);
|
submenu_set_header(submenu, header);
|
||||||
|
|
||||||
auto remote_manager = app->get_remote_manager();
|
auto remote_manager = app->get_remote_manager();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ void InfraredAppSceneEditRename::on_enter(InfraredApp* app) {
|
|||||||
strncpy(buffer_str, button_name.c_str(), max_len);
|
strncpy(buffer_str, button_name.c_str(), max_len);
|
||||||
buffer_str[max_len + 1] = 0;
|
buffer_str[max_len + 1] = 0;
|
||||||
enter_name_length = max_len;
|
enter_name_length = max_len;
|
||||||
text_input_set_header_text(text_input, "Name the key");
|
text_input_set_header_text(text_input, "Name the button");
|
||||||
} else {
|
} else {
|
||||||
auto remote_name = remote_manager->get_remote_name();
|
auto remote_name = remote_manager->get_remote_name();
|
||||||
strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size());
|
strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size());
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) {
|
|||||||
app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt);
|
app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_input_set_header_text(text_input, "Name the key");
|
text_input_set_header_text(text_input, "Name the button");
|
||||||
text_input_set_result_callback(
|
text_input_set_result_callback(
|
||||||
text_input,
|
text_input,
|
||||||
InfraredApp::text_input_callback,
|
InfraredApp::text_input_callback,
|
||||||
|
|||||||
@@ -3,19 +3,19 @@
|
|||||||
|
|
||||||
bool nfc_custom_event_callback(void* context, uint32_t event) {
|
bool nfc_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
return scene_manager_handle_custom_event(nfc->scene_manager, event);
|
return scene_manager_handle_custom_event(nfc->scene_manager, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_back_event_callback(void* context) {
|
bool nfc_back_event_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
return scene_manager_handle_back_event(nfc->scene_manager);
|
return scene_manager_handle_back_event(nfc->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_tick_event_callback(void* context) {
|
void nfc_tick_event_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
scene_manager_handle_tick_event(nfc->scene_manager);
|
scene_manager_handle_tick_event(nfc->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,40 +16,35 @@ static void nfc_cli_print_usage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_cli_detect(Cli* cli, string_t args) {
|
static void nfc_cli_detect(Cli* cli, string_t args) {
|
||||||
// Check if nfc worker is not busy
|
// Check if nfc worker is not busy
|
||||||
if(furi_hal_nfc_is_busy()) {
|
if(furi_hal_nfc_is_busy()) {
|
||||||
printf("Nfc is busy\r\n");
|
printf("Nfc is busy\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
uint8_t dev_cnt = 0;
|
FuriHalNfcDevData dev_data = {};
|
||||||
bool cmd_exit = false;
|
bool cmd_exit = false;
|
||||||
furi_hal_nfc_exit_sleep();
|
furi_hal_nfc_exit_sleep();
|
||||||
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
|
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
|
||||||
while(!cmd_exit) {
|
while(!cmd_exit) {
|
||||||
cmd_exit |= cli_cmd_interrupt_received(cli);
|
cmd_exit |= cli_cmd_interrupt_received(cli);
|
||||||
cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true);
|
if(furi_hal_nfc_detect(&dev_data, 400)) {
|
||||||
if(dev_cnt > 0) {
|
printf("found: %s ", nfc_get_dev_type(dev_data.type));
|
||||||
printf("Found %d devices\r\n", dev_cnt);
|
printf("UID length: %d, UID:", dev_data.uid_len);
|
||||||
for(uint8_t i = 0; i < dev_cnt; i++) {
|
for(size_t i = 0; i < dev_data.uid_len; i++) {
|
||||||
printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type));
|
printf("%02X", dev_data.uid[i]);
|
||||||
if(dev_list[i].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
|
|
||||||
printf("type: %s, ", nfc_get_nfca_type(dev_list[i].dev.nfca.type));
|
|
||||||
}
|
|
||||||
printf("UID length: %d, UID:", dev_list[i].nfcidLen);
|
|
||||||
for(uint8_t j = 0; j < dev_list[i].nfcidLen; j++) {
|
|
||||||
printf("%02X", dev_list[i].nfcid[j]);
|
|
||||||
}
|
}
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
furi_hal_nfc_sleep();
|
||||||
osDelay(50);
|
osDelay(50);
|
||||||
}
|
}
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_cli_emulate(Cli* cli, string_t args) {
|
static void nfc_cli_emulate(Cli* cli, string_t args) {
|
||||||
// Check if nfc worker is not busy
|
// Check if nfc worker is not busy
|
||||||
if(furi_hal_nfc_is_busy()) {
|
if(furi_hal_nfc_is_busy()) {
|
||||||
printf("Nfc is busy\r\n");
|
printf("Nfc is busy\r\n");
|
||||||
@@ -60,26 +55,25 @@ void nfc_cli_emulate(Cli* cli, string_t args) {
|
|||||||
printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
|
printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n");
|
||||||
printf("Press Ctrl+C to abort\r\n");
|
printf("Press Ctrl+C to abort\r\n");
|
||||||
|
|
||||||
NfcDeviceCommonData params = {
|
FuriHalNfcDevData params = {
|
||||||
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
|
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
|
||||||
.uid_len = 7,
|
.uid_len = 7,
|
||||||
.atqa = {0x44, 0x00},
|
.atqa = {0x44, 0x00},
|
||||||
.sak = 0x00,
|
.sak = 0x00,
|
||||||
.device = NfcDeviceNfca,
|
.type = FuriHalNfcTypeA,
|
||||||
.protocol = NfcDeviceProtocolMifareUl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
|
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) {
|
||||||
printf("Reader detected\r\n");
|
printf("Reader detected\r\n");
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
}
|
}
|
||||||
osDelay(50);
|
osDelay(50);
|
||||||
}
|
}
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_cli_field(Cli* cli, string_t args) {
|
static void nfc_cli_field(Cli* cli, string_t args) {
|
||||||
// Check if nfc worker is not busy
|
// Check if nfc worker is not busy
|
||||||
if(furi_hal_nfc_is_busy()) {
|
if(furi_hal_nfc_is_busy()) {
|
||||||
printf("Nfc is busy\r\n");
|
printf("Nfc is busy\r\n");
|
||||||
@@ -97,7 +91,7 @@ void nfc_cli_field(Cli* cli, string_t args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_nfc_field_off();
|
furi_hal_nfc_field_off();
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfc_cli(Cli* cli, string_t args, void* context) {
|
static void nfc_cli(Cli* cli, string_t args, void* context) {
|
||||||
|
|||||||
@@ -41,31 +41,31 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_str
|
|||||||
static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
|
static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
|
||||||
if(string_start_with_str_p(format_string, "UID")) {
|
if(string_start_with_str_p(format_string, "UID")) {
|
||||||
dev->format = NfcDeviceSaveFormatUid;
|
dev->format = NfcDeviceSaveFormatUid;
|
||||||
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown;
|
dev->dev_data.protocol = NfcDeviceProtocolUnknown;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(string_start_with_str_p(format_string, "Bank card")) {
|
if(string_start_with_str_p(format_string, "Bank card")) {
|
||||||
dev->format = NfcDeviceSaveFormatBankCard;
|
dev->format = NfcDeviceSaveFormatBankCard;
|
||||||
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV;
|
dev->dev_data.protocol = NfcDeviceProtocolEMV;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Check Mifare Ultralight types
|
// Check Mifare Ultralight types
|
||||||
for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
|
for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
|
||||||
if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) {
|
if(string_equal_str_p(format_string, nfc_mf_ul_type(type, true))) {
|
||||||
dev->format = NfcDeviceSaveFormatMifareUl;
|
dev->format = NfcDeviceSaveFormatMifareUl;
|
||||||
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl;
|
dev->dev_data.protocol = NfcDeviceProtocolMifareUl;
|
||||||
dev->dev_data.mf_ul_data.type = type;
|
dev->dev_data.mf_ul_data.type = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(string_start_with_str_p(format_string, "Mifare Classic")) {
|
if(string_start_with_str_p(format_string, "Mifare Classic")) {
|
||||||
dev->format = NfcDeviceSaveFormatMifareClassic;
|
dev->format = NfcDeviceSaveFormatMifareClassic;
|
||||||
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic;
|
dev->dev_data.protocol = NfcDeviceProtocolMifareClassic;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(string_start_with_str_p(format_string, "Mifare DESFire")) {
|
if(string_start_with_str_p(format_string, "Mifare DESFire")) {
|
||||||
dev->format = NfcDeviceSaveFormatMifareDesfire;
|
dev->format = NfcDeviceSaveFormatMifareDesfire;
|
||||||
dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
|
dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -73,7 +73,7 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_strin
|
|||||||
|
|
||||||
static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
MifareUlData* data = &dev->dev_data.mf_ul_data;
|
MfUltralightData* data = &dev->dev_data.mf_ul_data;
|
||||||
string_t temp_str;
|
string_t temp_str;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev)
|
|||||||
|
|
||||||
bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
MifareUlData* data = &dev->dev_data.mf_ul_data;
|
MfUltralightData* data = &dev->dev_data.mf_ul_data;
|
||||||
string_t temp_str;
|
string_t temp_str;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
|
|
||||||
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
NfcEmvData* data = &dev->dev_data.emv_data;
|
EmvData* data = &dev->dev_data.emv_data;
|
||||||
uint32_t data_temp = 0;
|
uint32_t data_temp = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -577,8 +577,8 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev)
|
|||||||
|
|
||||||
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
NfcEmvData* data = &dev->dev_data.emv_data;
|
EmvData* data = &dev->dev_data.emv_data;
|
||||||
memset(data, 0, sizeof(NfcEmvData));
|
memset(data, 0, sizeof(EmvData));
|
||||||
uint32_t data_cnt = 0;
|
uint32_t data_cnt = 0;
|
||||||
string_t temp_str;
|
string_t temp_str;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
@@ -700,7 +700,7 @@ static bool nfc_device_save_file(
|
|||||||
|
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
|
||||||
string_t temp_str;
|
string_t temp_str;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
|
|
||||||
@@ -758,7 +758,7 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
|
|||||||
static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
|
static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &dev->dev_data.nfc_data;
|
||||||
uint32_t data_cnt = 0;
|
uint32_t data_cnt = 0;
|
||||||
string_t temp_str;
|
string_t temp_str;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
@@ -789,6 +789,7 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
|
|||||||
if(!nfc_device_parse_format_string(dev, temp_str)) break;
|
if(!nfc_device_parse_format_string(dev, temp_str)) break;
|
||||||
// Read and parse UID, ATQA and SAK
|
// Read and parse UID, ATQA and SAK
|
||||||
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
|
if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
|
||||||
|
if(!(data_cnt == 4 || data_cnt == 7)) break;
|
||||||
data->uid_len = data_cnt;
|
data->uid_len = data_cnt;
|
||||||
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
|
||||||
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
|
||||||
@@ -863,7 +864,7 @@ bool nfc_file_select(NfcDevice* dev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_device_data_clear(NfcDeviceData* dev_data) {
|
void nfc_device_data_clear(NfcDeviceData* dev_data) {
|
||||||
if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
|
if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
mf_df_clear(&dev_data->mf_df_data);
|
mf_df_clear(&dev_data->mf_df_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
|
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
#include <lib/nfc_protocols/emv.h>
|
||||||
#include <lib/nfc_protocols/mifare_ultralight.h>
|
#include <lib/nfc_protocols/mifare_ultralight.h>
|
||||||
#include <lib/nfc_protocols/mifare_classic.h>
|
#include <lib/nfc_protocols/mifare_classic.h>
|
||||||
#include <lib/nfc_protocols/mifare_desfire.h>
|
#include <lib/nfc_protocols/mifare_desfire.h>
|
||||||
@@ -17,13 +19,6 @@
|
|||||||
#define NFC_APP_EXTENSION ".nfc"
|
#define NFC_APP_EXTENSION ".nfc"
|
||||||
#define NFC_APP_SHADOW_EXTENSION ".shd"
|
#define NFC_APP_SHADOW_EXTENSION ".shd"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
NfcDeviceNfca,
|
|
||||||
NfcDeviceNfcb,
|
|
||||||
NfcDeviceNfcf,
|
|
||||||
NfcDeviceNfcv,
|
|
||||||
} NfcDeviceType;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NfcDeviceProtocolUnknown,
|
NfcDeviceProtocolUnknown,
|
||||||
NfcDeviceProtocolEMV,
|
NfcDeviceProtocolEMV,
|
||||||
@@ -40,38 +35,18 @@ typedef enum {
|
|||||||
NfcDeviceSaveFormatMifareDesfire,
|
NfcDeviceSaveFormatMifareDesfire,
|
||||||
} NfcDeviceSaveFormat;
|
} NfcDeviceSaveFormat;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t uid_len;
|
|
||||||
uint8_t uid[10];
|
|
||||||
uint8_t atqa[2];
|
|
||||||
uint8_t sak;
|
|
||||||
NfcDeviceType device;
|
|
||||||
NfcProtocol protocol;
|
|
||||||
} NfcDeviceCommonData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char name[32];
|
|
||||||
uint8_t aid[16];
|
|
||||||
uint16_t aid_len;
|
|
||||||
uint8_t number[10];
|
|
||||||
uint8_t number_len;
|
|
||||||
uint8_t exp_mon;
|
|
||||||
uint8_t exp_year;
|
|
||||||
uint16_t country_code;
|
|
||||||
uint16_t currency_code;
|
|
||||||
} NfcEmvData;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t data[NFC_READER_DATA_MAX_SIZE];
|
uint8_t data[NFC_READER_DATA_MAX_SIZE];
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
} NfcReaderRequestData;
|
} NfcReaderRequestData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NfcDeviceCommonData nfc_data;
|
FuriHalNfcDevData nfc_data;
|
||||||
|
NfcProtocol protocol;
|
||||||
NfcReaderRequestData reader_data;
|
NfcReaderRequestData reader_data;
|
||||||
union {
|
union {
|
||||||
NfcEmvData emv_data;
|
EmvData emv_data;
|
||||||
MifareUlData mf_ul_data;
|
MfUltralightData mf_ul_data;
|
||||||
MfClassicData mf_classic_data;
|
MfClassicData mf_classic_data;
|
||||||
MifareDesfireData mf_df_data;
|
MifareDesfireData mf_df_data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct Nfc {
|
|||||||
NotificationApp* notifications;
|
NotificationApp* notifications;
|
||||||
SceneManager* scene_manager;
|
SceneManager* scene_manager;
|
||||||
NfcDevice* dev;
|
NfcDevice* dev;
|
||||||
NfcDeviceCommonData dev_edit_data;
|
FuriHalNfcDevData dev_edit_data;
|
||||||
|
|
||||||
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
||||||
string_t text_box_store;
|
string_t text_box_store;
|
||||||
|
|||||||
@@ -1,48 +1,14 @@
|
|||||||
#include "nfc_types.h"
|
#include "nfc_types.h"
|
||||||
|
|
||||||
const char* nfc_get_rfal_type(rfalNfcDevType type) {
|
const char* nfc_get_dev_type(FuriHalNfcType type) {
|
||||||
if(type == RFAL_NFC_LISTEN_TYPE_NFCA) {
|
if(type == FuriHalNfcTypeA) {
|
||||||
return "NFC-A";
|
return "NFC-A";
|
||||||
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) {
|
} else if(type == FuriHalNfcTypeB) {
|
||||||
return "NFC-B";
|
return "NFC-B";
|
||||||
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) {
|
} else if(type == FuriHalNfcTypeF) {
|
||||||
return "NFC-F";
|
return "NFC-F";
|
||||||
} else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) {
|
} else if(type == FuriHalNfcTypeV) {
|
||||||
return "NFC-V";
|
return "NFC-V";
|
||||||
} else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) {
|
|
||||||
return "NFC-ST25TB";
|
|
||||||
} else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) {
|
|
||||||
return "NFC-AP2P";
|
|
||||||
} else {
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* nfc_get_dev_type(NfcDeviceType type) {
|
|
||||||
if(type == NfcDeviceNfca) {
|
|
||||||
return "NFC-A";
|
|
||||||
} else if(type == NfcDeviceNfcb) {
|
|
||||||
return "NFC-B";
|
|
||||||
} else if(type == NfcDeviceNfcf) {
|
|
||||||
return "NFC-F";
|
|
||||||
} else if(type == NfcDeviceNfcv) {
|
|
||||||
return "NFC-V";
|
|
||||||
} else {
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) {
|
|
||||||
if(type == RFAL_NFCA_T1T) {
|
|
||||||
return "T1T";
|
|
||||||
} else if(type == RFAL_NFCA_T2T) {
|
|
||||||
return "T2T";
|
|
||||||
} else if(type == RFAL_NFCA_T4T) {
|
|
||||||
return "T4T";
|
|
||||||
} else if(type == RFAL_NFCA_NFCDEP) {
|
|
||||||
return "NFCDEP";
|
|
||||||
} else if(type == RFAL_NFCA_T4T_NFCDEP) {
|
|
||||||
return "T4T_NFCDEP";
|
|
||||||
} else {
|
} else {
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "st_errno.h"
|
#include "nfc_device.h"
|
||||||
#include "rfal_nfc.h"
|
|
||||||
|
|
||||||
#include <gui/view_dispatcher.h>
|
const char* nfc_get_dev_type(FuriHalNfcType type);
|
||||||
#include "nfc_worker.h"
|
|
||||||
|
|
||||||
const char* nfc_get_rfal_type(rfalNfcDevType type);
|
|
||||||
|
|
||||||
const char* nfc_get_dev_type(NfcDeviceType type);
|
|
||||||
|
|
||||||
const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type);
|
|
||||||
|
|
||||||
const char* nfc_guess_protocol(NfcProtocol protocol);
|
const char* nfc_guess_protocol(NfcProtocol protocol);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
|
|
||||||
#include <lib/nfc_protocols/nfc_util.h>
|
#include <lib/nfc_protocols/nfc_util.h>
|
||||||
#include <lib/nfc_protocols/emv_decoder.h>
|
#include <lib/nfc_protocols/emv.h>
|
||||||
|
#include <lib/nfc_protocols/mifare_common.h>
|
||||||
#include <lib/nfc_protocols/mifare_ultralight.h>
|
#include <lib/nfc_protocols/mifare_ultralight.h>
|
||||||
#include <lib/nfc_protocols/mifare_classic.h>
|
#include <lib/nfc_protocols/mifare_classic.h>
|
||||||
#include <lib/nfc_protocols/mifare_desfire.h>
|
#include <lib/nfc_protocols/mifare_desfire.h>
|
||||||
@@ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
nfc_worker_emulate(nfc_worker);
|
nfc_worker_emulate(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
||||||
nfc_worker_read_emv_app(nfc_worker);
|
nfc_worker_read_emv_app(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
|
} else if(nfc_worker->state == NfcWorkerStateReadEMVData) {
|
||||||
nfc_worker_read_emv(nfc_worker);
|
nfc_worker_read_emv(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
nfc_worker_emulate_apdu(nfc_worker);
|
nfc_worker_emulate_apdu(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
|
||||||
nfc_worker_read_mifare_ul(nfc_worker);
|
nfc_worker_read_mifare_ultralight(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
|
||||||
nfc_worker_emulate_mifare_ul(nfc_worker);
|
nfc_worker_emulate_mifare_ul(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
||||||
nfc_worker_mifare_classic_dict_attack(nfc_worker);
|
nfc_worker_mifare_classic_dict_attack(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
||||||
nfc_worker_read_mifare_desfire(nfc_worker);
|
nfc_worker_read_mifare_desfire(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateField) {
|
|
||||||
nfc_worker_field(nfc_worker);
|
|
||||||
}
|
}
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||||
furi_hal_power_insomnia_exit();
|
furi_hal_power_insomnia_exit();
|
||||||
|
|
||||||
@@ -117,269 +116,114 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_detect(NfcWorker* nfc_worker) {
|
void nfc_worker_detect(NfcWorker* nfc_worker) {
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
rfalNfcDevice* dev;
|
|
||||||
uint8_t dev_cnt;
|
|
||||||
nfc_device_data_clear(nfc_worker->dev_data);
|
nfc_device_data_clear(nfc_worker->dev_data);
|
||||||
NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data;
|
NfcDeviceData* dev_data = nfc_worker->dev_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateDetect) {
|
while(nfc_worker->state == NfcWorkerStateDetect) {
|
||||||
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) {
|
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
||||||
// Process first found device
|
// Process first found device
|
||||||
dev = &dev_list[0];
|
if(nfc_data->type == FuriHalNfcTypeA) {
|
||||||
result->uid_len = dev->nfcidLen;
|
if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
memcpy(result->uid, dev->nfcid, dev->nfcidLen);
|
dev_data->protocol = NfcDeviceProtocolMifareUl;
|
||||||
if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) {
|
|
||||||
result->device = NfcDeviceNfca;
|
|
||||||
result->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
|
|
||||||
result->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
|
|
||||||
result->sak = dev->dev.nfca.selRes.sak;
|
|
||||||
if(mf_ul_check_card_type(
|
|
||||||
dev->dev.nfca.sensRes.anticollisionInfo,
|
|
||||||
dev->dev.nfca.sensRes.platformInfo,
|
|
||||||
dev->dev.nfca.selRes.sak)) {
|
|
||||||
result->protocol = NfcDeviceProtocolMifareUl;
|
|
||||||
} else if(mf_classic_check_card_type(
|
} else if(mf_classic_check_card_type(
|
||||||
dev->dev.nfca.sensRes.anticollisionInfo,
|
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
dev->dev.nfca.sensRes.platformInfo,
|
dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||||
dev->dev.nfca.selRes.sak)) {
|
|
||||||
result->protocol = NfcDeviceProtocolMifareClassic;
|
|
||||||
} else if(mf_df_check_card_type(
|
} else if(mf_df_check_card_type(
|
||||||
dev->dev.nfca.sensRes.anticollisionInfo,
|
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
dev->dev.nfca.sensRes.platformInfo,
|
dev_data->protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
dev->dev.nfca.selRes.sak)) {
|
} else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
||||||
result->protocol = NfcDeviceProtocolMifareDesfire;
|
dev_data->protocol = NfcDeviceProtocolEMV;
|
||||||
} else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
|
|
||||||
result->protocol = NfcDeviceProtocolEMV;
|
|
||||||
} else {
|
} else {
|
||||||
result->protocol = NfcDeviceProtocolUnknown;
|
dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
}
|
}
|
||||||
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) {
|
|
||||||
result->device = NfcDeviceNfcb;
|
|
||||||
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) {
|
|
||||||
result->device = NfcDeviceNfcf;
|
|
||||||
} else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) {
|
|
||||||
result->device = NfcDeviceNfcv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify caller and exit
|
// Notify caller and exit
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_worker_emulate_uid_callback(
|
void nfc_worker_emulate(NfcWorker* nfc_worker) {
|
||||||
uint8_t* buff_rx,
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
uint16_t buff_rx_len,
|
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
||||||
uint8_t* buff_tx,
|
|
||||||
uint16_t* buff_tx_len,
|
|
||||||
uint32_t* data_type,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
NfcWorker* nfc_worker = context;
|
|
||||||
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
|
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
|
||||||
reader_data->size = buff_rx_len / 8;
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateEmulate) {
|
||||||
|
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
|
||||||
|
if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
|
||||||
|
reader_data->size = tx_rx.rx_bits / 8;
|
||||||
if(reader_data->size > 0) {
|
if(reader_data->size > 0) {
|
||||||
memcpy(reader_data->data, buff_rx, reader_data->size);
|
memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
} else {
|
||||||
}
|
FURI_LOG_E(TAG, "Failed to get reader commands");
|
||||||
|
}
|
||||||
void nfc_worker_emulate(NfcWorker* nfc_worker) {
|
}
|
||||||
NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulate) {
|
|
||||||
furi_hal_nfc_emulate_nfca(
|
|
||||||
data->uid,
|
|
||||||
data->uid_len,
|
|
||||||
data->atqa,
|
|
||||||
data->sak,
|
|
||||||
nfc_worker_emulate_uid_callback,
|
|
||||||
nfc_worker,
|
|
||||||
1000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
|
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
EmvApplication emv_app = {};
|
EmvApplication emv_app = {};
|
||||||
uint8_t dev_cnt = 0;
|
|
||||||
uint8_t tx_buff[255] = {};
|
|
||||||
uint16_t tx_len = 0;
|
|
||||||
uint8_t* rx_buff;
|
|
||||||
uint16_t* rx_len;
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
NfcDeviceData* result = nfc_worker->dev_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
nfc_device_data_clear(result);
|
nfc_device_data_clear(result);
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
||||||
memset(&emv_app, 0, sizeof(emv_app));
|
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
||||||
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
|
|
||||||
// Card was found. Check that it supports EMV
|
// Card was found. Check that it supports EMV
|
||||||
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
|
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
||||||
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
|
result->protocol = NfcDeviceProtocolEMV;
|
||||||
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
|
if(emv_search_application(&tx_rx, &emv_app)) {
|
||||||
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
|
|
||||||
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
|
|
||||||
memcpy(
|
|
||||||
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
|
|
||||||
result->nfc_data.protocol = NfcDeviceProtocolEMV;
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Send select PPSE command");
|
|
||||||
tx_len = emv_prepare_select_ppse(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err != ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
|
|
||||||
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
|
|
||||||
FURI_LOG_D(TAG, "Select PPSE responce parced");
|
|
||||||
// Notify caller and exit
|
// Notify caller and exit
|
||||||
result->emv_data.aid_len = emv_app.aid_len;
|
result->emv_data.aid_len = emv_app.aid_len;
|
||||||
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find pay application");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Can't find EMV card
|
|
||||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Can't find EMV card
|
|
||||||
FURI_LOG_D(TAG, "Can't find any cards");
|
FURI_LOG_D(TAG, "Can't find any cards");
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
}
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
osDelay(20);
|
osDelay(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
EmvApplication emv_app = {};
|
EmvApplication emv_app = {};
|
||||||
uint8_t dev_cnt = 0;
|
|
||||||
uint8_t tx_buff[255] = {};
|
|
||||||
uint16_t tx_len = 0;
|
|
||||||
uint8_t* rx_buff;
|
|
||||||
uint16_t* rx_len;
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
NfcDeviceData* result = nfc_worker->dev_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
nfc_device_data_clear(result);
|
nfc_device_data_clear(result);
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadEMV) {
|
while(nfc_worker->state == NfcWorkerStateReadEMVData) {
|
||||||
memset(&emv_app, 0, sizeof(emv_app));
|
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
||||||
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) {
|
|
||||||
// Card was found. Check that it supports EMV
|
// Card was found. Check that it supports EMV
|
||||||
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
|
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
||||||
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
|
result->protocol = NfcDeviceProtocolEMV;
|
||||||
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
|
if(emv_read_bank_card(&tx_rx, &emv_app)) {
|
||||||
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
|
result->emv_data.number_len = emv_app.card_number_len;
|
||||||
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
|
|
||||||
memcpy(
|
memcpy(
|
||||||
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
|
result->emv_data.number, emv_app.card_number, result->emv_data.number_len);
|
||||||
result->nfc_data.protocol = NfcDeviceProtocolEMV;
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Send select PPSE command");
|
|
||||||
tx_len = emv_prepare_select_ppse(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err != ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err);
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response");
|
|
||||||
if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
|
|
||||||
FURI_LOG_D(TAG, "Select PPSE responce parced");
|
|
||||||
result->emv_data.aid_len = emv_app.aid_len;
|
result->emv_data.aid_len = emv_app.aid_len;
|
||||||
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
||||||
} else {
|
if(emv_app.name_found) {
|
||||||
FURI_LOG_D(TAG, "Can't find pay application");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "Starting application ...");
|
|
||||||
tx_len = emv_prepare_select_app(tx_buff, &emv_app);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err != ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Error during application selection request: %d", err);
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "Select application response received. Start parsing response");
|
|
||||||
if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) {
|
|
||||||
FURI_LOG_D(TAG, "Card name: %s", emv_app.name);
|
|
||||||
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
|
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
|
||||||
} else if(emv_app.pdol.size > 0) {
|
|
||||||
FURI_LOG_D(TAG, "Can't find card name, but PDOL is present.");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find card name or PDOL");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
FURI_LOG_D(TAG, "Starting Get Processing Options command ...");
|
|
||||||
tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err != ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err);
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) {
|
|
||||||
FURI_LOG_D(TAG, "Card number parsed");
|
|
||||||
result->emv_data.number_len = emv_app.card_number_len;
|
|
||||||
memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len);
|
|
||||||
// Notify caller and exit
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Mastercard doesn't give PAN / card number as GPO response
|
|
||||||
// Iterate over all files found in application
|
|
||||||
bool pan_found = false;
|
|
||||||
for(uint8_t i = 0; (i < emv_app.afl.size) && !pan_found; i += 4) {
|
|
||||||
uint8_t sfi = emv_app.afl.data[i] >> 3;
|
|
||||||
uint8_t record_start = emv_app.afl.data[i + 1];
|
|
||||||
uint8_t record_end = emv_app.afl.data[i + 2];
|
|
||||||
|
|
||||||
// Iterate over all records in file
|
|
||||||
for(uint8_t record = record_start; record <= record_end; ++record) {
|
|
||||||
tx_len = emv_prepare_read_sfi_record(tx_buff, sfi, record);
|
|
||||||
err = furi_hal_nfc_data_exchange(
|
|
||||||
tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err != ERR_NONE) {
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
"Error reading application sfi %d, record %d",
|
|
||||||
sfi,
|
|
||||||
record);
|
|
||||||
}
|
|
||||||
if(emv_decode_read_sfi_record(rx_buff, *rx_len, &emv_app)) {
|
|
||||||
pan_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(pan_found) {
|
|
||||||
FURI_LOG_D(TAG, "Card PAN found");
|
|
||||||
result->emv_data.number_len = emv_app.card_number_len;
|
|
||||||
memcpy(
|
|
||||||
result->emv_data.number,
|
|
||||||
emv_app.card_number,
|
|
||||||
result->emv_data.number_len);
|
|
||||||
if(emv_app.exp_month) {
|
if(emv_app.exp_month) {
|
||||||
result->emv_data.exp_mon = emv_app.exp_month;
|
result->emv_data.exp_mon = emv_app.exp_month;
|
||||||
result->emv_data.exp_year = emv_app.exp_year;
|
result->emv_data.exp_year = emv_app.exp_year;
|
||||||
@@ -395,301 +239,102 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't read card number");
|
|
||||||
}
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Can't find EMV card
|
|
||||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Can't find EMV card
|
|
||||||
FURI_LOG_D(TAG, "Can't find any cards");
|
FURI_LOG_D(TAG, "Can't find any cards");
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
}
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
osDelay(20);
|
osDelay(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
uint8_t tx_buff[255] = {};
|
FuriHalNfcDevData params = {
|
||||||
uint16_t tx_len = 0;
|
|
||||||
uint8_t* rx_buff;
|
|
||||||
uint16_t* rx_len;
|
|
||||||
NfcDeviceCommonData params = {
|
|
||||||
.uid = {0xCF, 0x72, 0xd4, 0x40},
|
.uid = {0xCF, 0x72, 0xd4, 0x40},
|
||||||
.uid_len = 4,
|
.uid_len = 4,
|
||||||
.atqa = {0x00, 0x04},
|
.atqa = {0x00, 0x04},
|
||||||
.sak = 0x20,
|
.sak = 0x20,
|
||||||
.device = NfcDeviceNfca,
|
.type = FuriHalNfcTypeA,
|
||||||
.protocol = NfcDeviceProtocolEMV,
|
|
||||||
};
|
};
|
||||||
// Test RX data
|
|
||||||
const uint8_t debug_rx[] = {
|
|
||||||
0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
|
|
||||||
0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
|
||||||
0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
|
|
||||||
0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
|
|
||||||
0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
|
||||||
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
|
|
||||||
0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
|
|
||||||
0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
|
|
||||||
0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
|
|
||||||
0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
|
|
||||||
0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
|
||||||
0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
|
|
||||||
0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
|
|
||||||
0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
|
|
||||||
0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
|
|
||||||
0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
|
|
||||||
0x88, 0x00};
|
|
||||||
// Test TX data
|
|
||||||
const uint8_t debug_tx[] = {
|
|
||||||
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
|
|
||||||
0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
|
|
||||||
0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
|
|
||||||
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
|
||||||
0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
|
|
||||||
0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
|
|
||||||
0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
|
|
||||||
0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
|
|
||||||
0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
|
|
||||||
0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
|
|
||||||
0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
|
|
||||||
0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
|
|
||||||
0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
|
|
||||||
0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
|
|
||||||
0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
|
|
||||||
0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
|
|
||||||
0x00, 0x00};
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
|
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
|
||||||
FURI_LOG_D(TAG, "POS terminal detected");
|
FURI_LOG_D(TAG, "POS terminal detected");
|
||||||
// Read data from POS terminal
|
if(emv_card_emulation(&tx_rx)) {
|
||||||
err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
|
FURI_LOG_D(TAG, "EMV card emulated");
|
||||||
if(err == ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Received Select PPSE");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Error in 1st data exchange: select PPSE");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
FURI_LOG_D(TAG, "Transive SELECT PPSE ANS");
|
|
||||||
tx_len = emv_select_ppse_ans(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err == ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Received Select APP");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Error in 2nd data exchange: select APP");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Transive SELECT APP ANS");
|
|
||||||
tx_len = emv_select_app_ans(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err == ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Received PDOL");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Error in 3rd data exchange: receive PDOL");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Transive PDOL ANS");
|
|
||||||
tx_len = emv_get_proc_opt_ans(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err == ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Transive PDOL ANS");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Error in 4rd data exchange: Transive PDOL ANS");
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
|
|
||||||
FURI_LOG_D(TAG, "Failed long message test");
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Correct debug message received");
|
|
||||||
tx_len = sizeof(debug_tx);
|
|
||||||
err = furi_hal_nfc_data_exchange(
|
|
||||||
(uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err == ERR_NONE) {
|
|
||||||
FURI_LOG_D(TAG, "Transive Debug message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Can't find reader");
|
FURI_LOG_D(TAG, "Can't find reader");
|
||||||
}
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
osDelay(20);
|
osDelay(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) {
|
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
rfalNfcDevice* dev_list;
|
MfUltralightReader reader = {};
|
||||||
uint8_t dev_cnt = 0;
|
MfUltralightData data = {};
|
||||||
uint8_t tx_buff[255] = {};
|
|
||||||
uint16_t tx_len = 0;
|
|
||||||
uint8_t* rx_buff;
|
|
||||||
uint16_t* rx_len;
|
|
||||||
MifareUlDevice mf_ul_read;
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
NfcDeviceData* result = nfc_worker->dev_data;
|
||||||
nfc_device_data_clear(result);
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
memset(&mf_ul_read, 0, sizeof(mf_ul_read));
|
|
||||||
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
|
|
||||||
if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA &&
|
|
||||||
mf_ul_check_card_type(
|
|
||||||
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
|
|
||||||
dev_list[0].dev.nfca.sensRes.platformInfo,
|
|
||||||
dev_list[0].dev.nfca.selRes.sak)) {
|
|
||||||
// Get Mifare Ultralight version
|
|
||||||
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Reading tag version");
|
|
||||||
tx_len = mf_ul_prepare_get_version(tx_buff);
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
|
||||||
if(err == ERR_NONE) {
|
|
||||||
mf_ul_parse_get_version_response(rx_buff, &mf_ul_read);
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
"Mifare Ultralight Type: %d, Pages: %d",
|
|
||||||
mf_ul_read.data.type,
|
|
||||||
mf_ul_read.pages_to_read);
|
|
||||||
FURI_LOG_D(TAG, "Reading signature ...");
|
|
||||||
tx_len = mf_ul_prepare_read_signature(tx_buff);
|
|
||||||
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
|
|
||||||
FURI_LOG_D(TAG, "Failed reading signature");
|
|
||||||
memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature));
|
|
||||||
} else {
|
|
||||||
mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read);
|
|
||||||
}
|
|
||||||
} else if(err == ERR_TIMEOUT) {
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
"Card doesn't respond to GET VERSION command. Setting default read parameters");
|
|
||||||
err = ERR_NONE;
|
|
||||||
mf_ul_set_default_version(&mf_ul_read);
|
|
||||||
// Reinit device
|
|
||||||
furi_hal_nfc_deactivate();
|
|
||||||
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
|
|
||||||
FURI_LOG_D(TAG, "Lost connection. Restarting search");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG, "Error getting Mifare Ultralight version. Error code: %d", err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mf_ul_read.support_fast_read) {
|
|
||||||
FURI_LOG_D(TAG, "Reading pages ...");
|
|
||||||
tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1);
|
|
||||||
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
|
|
||||||
FURI_LOG_D(TAG, "Failed reading pages");
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
mf_ul_parse_fast_read_response(
|
|
||||||
rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading 3 counters ...");
|
|
||||||
for(uint8_t i = 0; i < 3; i++) {
|
|
||||||
tx_len = mf_ul_prepare_read_cnt(tx_buff, i);
|
|
||||||
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
|
|
||||||
FURI_LOG_W(TAG, "Failed reading Counter %d", i);
|
|
||||||
mf_ul_read.data.counter[i] = 0;
|
|
||||||
} else {
|
|
||||||
mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Checking tearing flags ...");
|
|
||||||
for(uint8_t i = 0; i < 3; i++) {
|
|
||||||
tx_len = mf_ul_prepare_check_tearing(tx_buff, i);
|
|
||||||
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
|
|
||||||
FURI_LOG_D(TAG, "Error checking tearing flag %d", i);
|
|
||||||
mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT;
|
|
||||||
} else {
|
|
||||||
mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// READ card with READ command (4 pages at a time)
|
|
||||||
for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) {
|
|
||||||
FURI_LOG_D(TAG, "Reading pages %d - %d ...", page, page + 3);
|
|
||||||
tx_len = mf_ul_prepare_read(tx_buff, page);
|
|
||||||
if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) {
|
|
||||||
FURI_LOG_D(TAG, "Read pages %d - %d failed", page, page + 3);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
mf_ul_parse_read_response(rx_buff, page, &mf_ul_read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill result data
|
|
||||||
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
|
|
||||||
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
|
|
||||||
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
|
|
||||||
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
|
|
||||||
result->nfc_data.protocol = NfcDeviceProtocolMifareUl;
|
|
||||||
memcpy(
|
|
||||||
result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
|
|
||||||
result->mf_ul_data = mf_ul_read.data;
|
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
|
||||||
|
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
||||||
|
if(nfc_data->type == FuriHalNfcTypeA &&
|
||||||
|
mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
|
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading");
|
||||||
|
if(mf_ul_read_card(&tx_rx, &reader, &data)) {
|
||||||
|
result->protocol = NfcDeviceProtocolMifareUl;
|
||||||
|
result->mf_ul_data = data;
|
||||||
// Notify caller and exit
|
// Notify caller and exit
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight");
|
FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Can't find any tags");
|
FURI_LOG_D(TAG, "Can't find any tags");
|
||||||
}
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
|
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
|
||||||
NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data;
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
MifareUlDevice mf_ul_emulate;
|
MfUltralightEmulator emulator = {};
|
||||||
mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data);
|
mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
|
||||||
furi_hal_nfc_emulate_nfca(
|
furi_hal_nfc_emulate_nfca(
|
||||||
nfc_common->uid,
|
nfc_data->uid,
|
||||||
nfc_common->uid_len,
|
nfc_data->uid_len,
|
||||||
nfc_common->atqa,
|
nfc_data->atqa,
|
||||||
nfc_common->sak,
|
nfc_data->sak,
|
||||||
mf_ul_prepare_emulation_response,
|
mf_ul_prepare_emulation_response,
|
||||||
&mf_ul_emulate,
|
&emulator,
|
||||||
5000);
|
5000);
|
||||||
// Check if data was modified
|
// Check if data was modified
|
||||||
if(mf_ul_emulate.data_changed) {
|
if(emulator.data_changed) {
|
||||||
nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
|
nfc_worker->dev_data->mf_ul_data = emulator.data;
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
}
|
}
|
||||||
mf_ul_emulate.data_changed = false;
|
emulator.data_changed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
||||||
furi_assert(nfc_worker->callback);
|
furi_assert(nfc_worker->callback);
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
rfalNfcDevice* dev;
|
|
||||||
NfcDeviceCommonData* nfc_common;
|
|
||||||
uint8_t dev_cnt = 0;
|
|
||||||
FuriHalNfcTxRxContext tx_rx_ctx = {};
|
FuriHalNfcTxRxContext tx_rx_ctx = {};
|
||||||
MfClassicAuthContext auth_ctx = {};
|
MfClassicAuthContext auth_ctx = {};
|
||||||
MfClassicReader reader = {};
|
MfClassicReader reader = {};
|
||||||
@@ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
uint16_t curr_sector = 0;
|
uint16_t curr_sector = 0;
|
||||||
uint8_t total_sectors = 0;
|
uint8_t total_sectors = 0;
|
||||||
NfcWorkerEvent event;
|
NfcWorkerEvent event;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
// Open dictionary
|
// Open dictionary
|
||||||
nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
|
nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
|
||||||
@@ -710,14 +356,13 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
|
|
||||||
// Detect Mifare Classic card
|
// Detect Mifare Classic card
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
||||||
if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
|
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
||||||
dev = &dev_list[0];
|
|
||||||
if(mf_classic_get_type(
|
if(mf_classic_get_type(
|
||||||
dev->nfcid,
|
nfc_data->uid,
|
||||||
dev->nfcidLen,
|
nfc_data->uid_len,
|
||||||
dev->dev.nfca.sensRes.anticollisionInfo,
|
nfc_data->atqa[0],
|
||||||
dev->dev.nfca.sensRes.platformInfo,
|
nfc_data->atqa[1],
|
||||||
dev->dev.nfca.selRes.sak,
|
nfc_data->sak,
|
||||||
&reader)) {
|
&reader)) {
|
||||||
total_sectors = mf_classic_get_total_sectors_num(&reader);
|
total_sectors = mf_classic_get_total_sectors_num(&reader);
|
||||||
if(reader.type == MfClassicType1k) {
|
if(reader.type == MfClassicType1k) {
|
||||||
@@ -745,7 +390,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
|
mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
|
||||||
bool sector_key_found = false;
|
bool sector_key_found = false;
|
||||||
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
|
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
|
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
|
||||||
if(!card_found_notified) {
|
if(!card_found_notified) {
|
||||||
if(reader.type == MfClassicType1k) {
|
if(reader.type == MfClassicType1k) {
|
||||||
@@ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
uint8_t sectors_read =
|
uint8_t sectors_read =
|
||||||
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
|
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
|
||||||
if(sectors_read) {
|
if(sectors_read) {
|
||||||
dev = &dev_list[0];
|
|
||||||
nfc_common = &nfc_worker->dev_data->nfc_data;
|
|
||||||
nfc_common->uid_len = dev->dev.nfca.nfcId1Len;
|
|
||||||
nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo;
|
|
||||||
nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo;
|
|
||||||
nfc_common->sak = dev->dev.nfca.selRes.sak;
|
|
||||||
nfc_common->protocol = NfcDeviceProtocolMifareClassic;
|
|
||||||
memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len);
|
|
||||||
event = NfcWorkerEventSuccess;
|
event = NfcWorkerEventSuccess;
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||||
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
|
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
|
||||||
} else {
|
} else {
|
||||||
event = NfcWorkerEventFail;
|
event = NfcWorkerEventFail;
|
||||||
@@ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|||||||
stream_free(nfc_worker->dict_stream);
|
stream_free(nfc_worker->dict_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode nfc_exchange_full(
|
|
||||||
uint8_t* tx_buff,
|
|
||||||
uint16_t tx_len,
|
|
||||||
uint8_t* rx_buff,
|
|
||||||
uint16_t rx_cap,
|
|
||||||
uint16_t* rx_len) {
|
|
||||||
ReturnCode err;
|
|
||||||
uint8_t* part_buff;
|
|
||||||
uint16_t* part_len;
|
|
||||||
|
|
||||||
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false);
|
|
||||||
if(*part_len > rx_cap) {
|
|
||||||
return ERR_OVERRUN;
|
|
||||||
}
|
|
||||||
memcpy(rx_buff, part_buff, *part_len);
|
|
||||||
*rx_len = *part_len;
|
|
||||||
while(err == ERR_NONE && rx_buff[0] == 0xAF) {
|
|
||||||
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false);
|
|
||||||
if(*part_len > rx_cap - *rx_len) {
|
|
||||||
return ERR_OVERRUN;
|
|
||||||
}
|
|
||||||
if(*part_len == 0) {
|
|
||||||
return ERR_PROTO;
|
|
||||||
}
|
|
||||||
memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1);
|
|
||||||
*rx_buff = *part_buff;
|
|
||||||
*rx_len += *part_len - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
rfalNfcDevice* dev_list;
|
|
||||||
uint8_t dev_cnt = 0;
|
|
||||||
uint8_t tx_buff[64] = {};
|
uint8_t tx_buff[64] = {};
|
||||||
uint16_t tx_len = 0;
|
uint16_t tx_len = 0;
|
||||||
uint8_t rx_buff[512] = {};
|
uint8_t rx_buff[512] = {};
|
||||||
@@ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
NfcDeviceData* result = nfc_worker->dev_data;
|
||||||
nfc_device_data_clear(result);
|
nfc_device_data_clear(result);
|
||||||
MifareDesfireData* data = &result->mf_df_data;
|
MifareDesfireData* data = &result->mf_df_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) {
|
if(!furi_hal_nfc_detect(nfc_data, 300)) {
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
memset(data, 0, sizeof(MifareDesfireData));
|
memset(data, 0, sizeof(MifareDesfireData));
|
||||||
if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA ||
|
if(nfc_data->type != FuriHalNfcTypeA ||
|
||||||
!mf_df_check_card_type(
|
!mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
dev_list[0].dev.nfca.sensRes.anticollisionInfo,
|
|
||||||
dev_list[0].dev.nfca.sensRes.platformInfo,
|
|
||||||
dev_list[0].dev.nfca.selRes.sak)) {
|
|
||||||
FURI_LOG_D(TAG, "Tag is not DESFire");
|
FURI_LOG_D(TAG, "Tag is not DESFire");
|
||||||
osDelay(100);
|
osDelay(100);
|
||||||
continue;
|
continue;
|
||||||
@@ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
|
|
||||||
FURI_LOG_D(TAG, "Found DESFire tag");
|
FURI_LOG_D(TAG, "Found DESFire tag");
|
||||||
|
|
||||||
// Fill non-DESFire result data
|
result->protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len;
|
|
||||||
result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
|
|
||||||
result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
|
|
||||||
result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak;
|
|
||||||
result->nfc_data.device = NfcDeviceNfca;
|
|
||||||
result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
|
|
||||||
memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len);
|
|
||||||
|
|
||||||
// Get DESFire version
|
// Get DESFire version
|
||||||
tx_len = mf_df_prepare_get_version(tx_buff);
|
tx_len = mf_df_prepare_get_version(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err);
|
||||||
continue;
|
continue;
|
||||||
@@ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_len = mf_df_prepare_get_free_memory(tx_buff);
|
tx_len = mf_df_prepare_get_free_memory(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err == ERR_NONE) {
|
if(err == ERR_NONE) {
|
||||||
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
|
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
|
||||||
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
|
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
|
||||||
@@ -935,7 +530,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_len = mf_df_prepare_get_key_settings(tx_buff);
|
tx_len = mf_df_prepare_get_key_settings(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
|
FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
&data->master_key_settings->key_version_head;
|
&data->master_key_settings->key_version_head;
|
||||||
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
|
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
|
||||||
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
|
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err =
|
||||||
|
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
|
||||||
continue;
|
continue;
|
||||||
@@ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_len = mf_df_prepare_get_application_ids(tx_buff);
|
tx_len = mf_df_prepare_get_application_ids(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
|
|
||||||
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
|
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
|
||||||
tx_len = mf_df_prepare_select_application(tx_buff, app->id);
|
tx_len = mf_df_prepare_select_application(tx_buff, app->id);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
|
if(!mf_df_parse_select_application_response(rx_buff, rx_len)) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tx_len = mf_df_prepare_get_key_settings(tx_buff);
|
tx_len = mf_df_prepare_get_key_settings(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
|
MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
|
||||||
for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
|
for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
|
||||||
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
|
tx_len = mf_df_prepare_get_key_version(tx_buff, key_id);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(
|
||||||
|
tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err);
|
||||||
continue;
|
continue;
|
||||||
@@ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx_len = mf_df_prepare_get_file_ids(tx_buff);
|
tx_len = mf_df_prepare_get_file_ids(tx_buff);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err);
|
||||||
} else {
|
} else {
|
||||||
@@ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
|
|
||||||
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
||||||
tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
|
tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id);
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err =
|
||||||
|
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
|
FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err);
|
||||||
continue;
|
continue;
|
||||||
@@ -1054,7 +652,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
|
tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
err =
|
||||||
|
furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len);
|
||||||
if(err != ERR_NONE) {
|
if(err != ERR_NONE) {
|
||||||
FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
|
FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err);
|
||||||
continue;
|
continue;
|
||||||
@@ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_field(NfcWorker* nfc_worker) {
|
|
||||||
furi_hal_nfc_field_on();
|
|
||||||
while(nfc_worker->state == NfcWorkerStateField) {
|
|
||||||
osDelay(50);
|
|
||||||
}
|
|
||||||
furi_hal_nfc_field_off();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ typedef enum {
|
|||||||
NfcWorkerStateDetect,
|
NfcWorkerStateDetect,
|
||||||
NfcWorkerStateEmulate,
|
NfcWorkerStateEmulate,
|
||||||
NfcWorkerStateReadEMVApp,
|
NfcWorkerStateReadEMVApp,
|
||||||
NfcWorkerStateReadEMV,
|
NfcWorkerStateReadEMVData,
|
||||||
NfcWorkerStateEmulateApdu,
|
NfcWorkerStateEmulateApdu,
|
||||||
NfcWorkerStateField,
|
NfcWorkerStateField,
|
||||||
NfcWorkerStateReadMifareUl,
|
NfcWorkerStateReadMifareUltralight,
|
||||||
NfcWorkerStateEmulateMifareUl,
|
NfcWorkerStateEmulateMifareUltralight,
|
||||||
NfcWorkerStateReadMifareClassic,
|
NfcWorkerStateReadMifareClassic,
|
||||||
NfcWorkerStateReadMifareDesfire,
|
NfcWorkerStateReadMifareDesfire,
|
||||||
// Transition
|
// Transition
|
||||||
|
|||||||
@@ -4,19 +4,8 @@
|
|||||||
#include "nfc_worker.h"
|
#include "nfc_worker.h"
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <lib/toolbox/stream/file_stream.h>
|
#include <lib/toolbox/stream/file_stream.h>
|
||||||
|
|
||||||
#include <rfal_analogConfig.h>
|
|
||||||
#include <rfal_rf.h>
|
|
||||||
#include <rfal_nfc.h>
|
|
||||||
#include <rfal_nfca.h>
|
|
||||||
#include <rfal_nfcb.h>
|
|
||||||
#include <rfal_nfcf.h>
|
|
||||||
#include <rfal_nfcv.h>
|
|
||||||
#include <st25r3916.h>
|
|
||||||
#include <st25r3916_irq.h>
|
|
||||||
|
|
||||||
struct NfcWorker {
|
struct NfcWorker {
|
||||||
FuriThread* thread;
|
FuriThread* thread;
|
||||||
Storage* storage;
|
Storage* storage;
|
||||||
@@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker);
|
|||||||
|
|
||||||
void nfc_worker_emulate(NfcWorker* nfc_worker);
|
void nfc_worker_emulate(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_field(NfcWorker* nfc_worker);
|
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
|
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
|
|||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
|
if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Run Compatible App",
|
"Run Compatible App",
|
||||||
@@ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == SubmenuIndexRunApp) {
|
if(event.event == SubmenuIndexRunApp) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
|
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
|
||||||
if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
|
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
||||||
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
|
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
||||||
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
|
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
||||||
} else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) {
|
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start)
|
|||||||
ADD_SCENE(nfc, read_card, ReadCard)
|
ADD_SCENE(nfc, read_card, ReadCard)
|
||||||
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
||||||
ADD_SCENE(nfc, card_menu, CardMenu)
|
ADD_SCENE(nfc, card_menu, CardMenu)
|
||||||
ADD_SCENE(nfc, not_implemented, NotImplemented)
|
|
||||||
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
||||||
ADD_SCENE(nfc, save_name, SaveName)
|
ADD_SCENE(nfc, save_name, SaveName)
|
||||||
ADD_SCENE(nfc, save_success, SaveSuccess)
|
ADD_SCENE(nfc, save_success, SaveSuccess)
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ enum SubmenuDebugIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_debug_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_debug_on_enter(void* context) {
|
void nfc_scene_debug_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_debug_on_exit(void* context) {
|
void nfc_scene_debug_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
|
void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
if(type == InputTypeShort) {
|
if(type == InputTypeShort) {
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_delete_on_enter(void* context) {
|
void nfc_scene_delete_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup Custom Widget view
|
// Setup Custom Widget view
|
||||||
char delete_str[64];
|
char temp_str[64];
|
||||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
|
snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name);
|
||||||
widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
|
widget_add_text_box_element(
|
||||||
|
nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false);
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
|
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
|
nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
|
||||||
char uid_str[32];
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
|
||||||
if(data->uid_len == 4) {
|
if(data->uid_len == 4) {
|
||||||
snprintf(
|
snprintf(
|
||||||
uid_str,
|
temp_str,
|
||||||
sizeof(uid_str),
|
sizeof(temp_str),
|
||||||
"UID: %02X %02X %02X %02X",
|
"UID: %02X %02X %02X %02X",
|
||||||
data->uid[0],
|
data->uid[0],
|
||||||
data->uid[1],
|
data->uid[1],
|
||||||
@@ -31,8 +31,8 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
data->uid[3]);
|
data->uid[3]);
|
||||||
} else if(data->uid_len == 7) {
|
} else if(data->uid_len == 7) {
|
||||||
snprintf(
|
snprintf(
|
||||||
uid_str,
|
temp_str,
|
||||||
sizeof(uid_str),
|
sizeof(temp_str),
|
||||||
"UID: %02X %02X %02X %02X %02X %02X %02X",
|
"UID: %02X %02X %02X %02X %02X %02X %02X",
|
||||||
data->uid[0],
|
data->uid[0],
|
||||||
data->uid[1],
|
data->uid[1],
|
||||||
@@ -42,12 +42,13 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
data->uid[5],
|
data->uid[5],
|
||||||
data->uid[6]);
|
data->uid[6]);
|
||||||
}
|
}
|
||||||
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, uid_str);
|
widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str);
|
||||||
|
|
||||||
const char* protocol_name = NULL;
|
const char* protocol_name = NULL;
|
||||||
if(data->protocol == NfcDeviceProtocolEMV) {
|
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
||||||
protocol_name = nfc_guess_protocol(data->protocol);
|
if(protocol == NfcDeviceProtocolEMV) {
|
||||||
} else if(data->protocol == NfcDeviceProtocolMifareUl) {
|
protocol_name = nfc_guess_protocol(protocol);
|
||||||
|
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||||
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
|
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
|
||||||
}
|
}
|
||||||
if(protocol_name) {
|
if(protocol_name) {
|
||||||
@@ -56,18 +57,17 @@ void nfc_scene_delete_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
// TODO change dinamically
|
// TODO change dinamically
|
||||||
widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
|
widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A");
|
||||||
char sak_str[16];
|
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
|
||||||
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
|
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||||
widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str);
|
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
|
||||||
char atqa_str[16];
|
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str);
|
||||||
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
|
|
||||||
widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, atqa_str);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
@@ -79,14 +79,14 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneStart);
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_delete_on_exit(void* context) {
|
void nfc_scene_delete_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
widget_reset(nfc->widget);
|
widget_reset(nfc->widget);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_delete_success_popup_callback(void* context) {
|
void nfc_scene_delete_success_popup_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_delete_success_on_enter(void* context) {
|
void nfc_scene_delete_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
@@ -20,27 +20,21 @@ void nfc_scene_delete_success_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventViewExit) {
|
if(event.event == NfcCustomEventViewExit) {
|
||||||
return scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneStart);
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_delete_success_on_exit(void* context) {
|
void nfc_scene_delete_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
popup_set_callback(popup, NULL);
|
|
||||||
popup_set_context(popup, NULL);
|
|
||||||
popup_set_timeout(popup, 0);
|
|
||||||
popup_disable_timeout(popup);
|
|
||||||
}
|
}
|
||||||
@@ -36,19 +36,19 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
(nfc->dev->format == NfcDeviceSaveFormatBankCard);
|
(nfc->dev->format == NfcDeviceSaveFormatBankCard);
|
||||||
// Setup Custom Widget view
|
// Setup Custom Widget view
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name);
|
nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false);
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
|
nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
|
||||||
if(data_display_supported) {
|
if(data_display_supported) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
|
nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
|
||||||
}
|
}
|
||||||
char uid_str[32];
|
char temp_str[32];
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
if(data->uid_len == 4) {
|
if(data->uid_len == 4) {
|
||||||
snprintf(
|
snprintf(
|
||||||
uid_str,
|
temp_str,
|
||||||
sizeof(uid_str),
|
sizeof(temp_str),
|
||||||
"UID: %02X %02X %02X %02X",
|
"UID: %02X %02X %02X %02X",
|
||||||
data->uid[0],
|
data->uid[0],
|
||||||
data->uid[1],
|
data->uid[1],
|
||||||
@@ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
data->uid[3]);
|
data->uid[3]);
|
||||||
} else if(data->uid_len == 7) {
|
} else if(data->uid_len == 7) {
|
||||||
snprintf(
|
snprintf(
|
||||||
uid_str,
|
temp_str,
|
||||||
sizeof(uid_str),
|
sizeof(temp_str),
|
||||||
"UID: %02X %02X %02X %02X %02X %02X %02X",
|
"UID: %02X %02X %02X %02X %02X %02X %02X",
|
||||||
data->uid[0],
|
data->uid[0],
|
||||||
data->uid[1],
|
data->uid[1],
|
||||||
@@ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
data->uid[5],
|
data->uid[5],
|
||||||
data->uid[6]);
|
data->uid[6]);
|
||||||
}
|
}
|
||||||
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str);
|
widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str);
|
||||||
|
|
||||||
const char* protocol_name = NULL;
|
const char* protocol_name = NULL;
|
||||||
if(data->protocol == NfcDeviceProtocolEMV ||
|
NfcProtocol protocol = nfc->dev->dev_data.protocol;
|
||||||
data->protocol == NfcDeviceProtocolMifareDesfire) {
|
if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
protocol_name = nfc_guess_protocol(data->protocol);
|
protocol_name = nfc_guess_protocol(protocol);
|
||||||
} else if(data->protocol == NfcDeviceProtocolMifareUl) {
|
} else if(protocol == NfcDeviceProtocolMifareUl) {
|
||||||
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
|
protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false);
|
||||||
} else if(data->protocol == NfcDeviceProtocolMifareClassic) {
|
} else if(protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
|
protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type);
|
||||||
}
|
}
|
||||||
if(protocol_name) {
|
if(protocol_name) {
|
||||||
@@ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
// TODO change dinamically
|
// TODO change dinamically
|
||||||
widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
|
widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A");
|
||||||
char sak_str[16];
|
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak);
|
||||||
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak);
|
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||||
widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str);
|
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
|
||||||
char atqa_str[16];
|
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str);
|
||||||
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]);
|
|
||||||
widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
|
|
||||||
|
|
||||||
// Setup Data View
|
// Setup Data View
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
|
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
|
||||||
@@ -99,7 +97,7 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
dialog_ex_set_context(dialog_ex, nfc);
|
dialog_ex_set_context(dialog_ex, nfc);
|
||||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
|
dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
||||||
TextBox* text_box = nfc->text_box;
|
TextBox* text_box = nfc->text_box;
|
||||||
text_box_set_font(text_box, TextBoxFontHex);
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
|
for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
|
||||||
@@ -130,7 +128,7 @@ void nfc_scene_device_info_on_enter(void* context) {
|
|||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
|
nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
||||||
BankCard* bank_card = nfc->bank_card;
|
BankCard* bank_card = nfc->bank_card;
|
||||||
bank_card_set_name(bank_card, emv_data->name);
|
bank_card_set_name(bank_card, emv_data->name);
|
||||||
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
|
bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
|
||||||
@@ -212,21 +210,16 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_device_info_on_exit(void* context) {
|
void nfc_scene_device_info_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear Custom Widget
|
// Clear views
|
||||||
widget_reset(nfc->widget);
|
widget_reset(nfc->widget);
|
||||||
|
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
|
if(nfc->dev->format == NfcDeviceSaveFormatUid) {
|
||||||
// Clear Dialog
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
|
||||||
dialog_ex_reset(dialog_ex);
|
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
// Clear TextBox
|
|
||||||
text_box_reset(nfc->text_box);
|
text_box_reset(nfc->text_box);
|
||||||
string_reset(nfc->text_box_store);
|
string_reset(nfc->text_box_store);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
// Clear Bank Card
|
|
||||||
bank_card_clear(nfc->bank_card);
|
bank_card_clear(nfc->bank_card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,34 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
|
void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
|
|
||||||
popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
|
popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
|
||||||
|
|
||||||
// Setup and start worker
|
// Setup and start worker
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
|
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
if(event.type == SceneManagerEventTypeTick) {
|
||||||
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
|
void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_reset(popup);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
#define NFC_MF_UL_DATA_CHANGED (1UL)
|
#define NFC_MF_UL_DATA_CHANGED (1UL)
|
||||||
|
|
||||||
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
|
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
|
void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -26,14 +27,14 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
|
|||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulateMifareUl,
|
NfcWorkerStateEmulateMifareUltralight,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_emulate_mifare_ul_worker_callback,
|
nfc_emulate_mifare_ul_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
if(event.type == SceneManagerEventTypeTick) {
|
||||||
@@ -55,11 +56,8 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
|
void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NfcSceneEmulateUidStateWidget,
|
NfcSceneEmulateUidStateWidget,
|
||||||
NfcSceneEmulateUidStateTextBox,
|
NfcSceneEmulateUidStateTextBox,
|
||||||
@@ -28,7 +30,7 @@ void nfc_emulate_uid_textbox_callback(void* context) {
|
|||||||
|
|
||||||
// Add widget with device name or inform that data received
|
// Add widget with device name or inform that data received
|
||||||
static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
|
static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
Widget* widget = nfc->widget;
|
Widget* widget = nfc->widget;
|
||||||
widget_reset(widget);
|
widget_reset(widget);
|
||||||
string_t info_str;
|
string_t info_str;
|
||||||
@@ -45,7 +47,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
|
|||||||
}
|
}
|
||||||
string_strim(info_str);
|
string_strim(info_str);
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
widget, 56, 43, 70, 21, AlignLeft, AlignTop, string_get_cstr(info_str));
|
widget, 56, 43, 70, 21, AlignLeft, AlignTop, string_get_cstr(info_str), true);
|
||||||
string_clear(info_str);
|
string_clear(info_str);
|
||||||
if(data_received) {
|
if(data_received) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
@@ -95,13 +97,15 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
|
|||||||
nfc_scene_emulate_uid_widget_config(nfc, true);
|
nfc_scene_emulate_uid_widget_config(nfc, true);
|
||||||
}
|
}
|
||||||
// Update TextBox data
|
// Update TextBox data
|
||||||
|
if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) {
|
||||||
string_cat_printf(nfc->text_box_store, "R:");
|
string_cat_printf(nfc->text_box_store, "R:");
|
||||||
for(uint16_t i = 0; i < reader_data->size; i++) {
|
for(uint16_t i = 0; i < reader_data->size; i++) {
|
||||||
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
|
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
|
||||||
}
|
}
|
||||||
string_push_back(nfc->text_box_store, '\n');
|
string_push_back(nfc->text_box_store, '\n');
|
||||||
memset(reader_data, 0, sizeof(NfcReaderRequestData));
|
|
||||||
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
|
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
|
||||||
|
}
|
||||||
|
memset(reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_field_on_enter(void* context) {
|
void nfc_scene_field_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
furi_hal_nfc_field_on();
|
furi_hal_nfc_field_on();
|
||||||
|
|
||||||
@@ -23,12 +23,9 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_field_on_exit(void* context) {
|
void nfc_scene_field_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
notification_internal_message(nfc->notifications, &sequence_reset_blue);
|
|
||||||
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_reset(popup);
|
|
||||||
|
|
||||||
furi_hal_nfc_field_off();
|
furi_hal_nfc_field_off();
|
||||||
|
notification_internal_message(nfc->notifications, &sequence_reset_blue);
|
||||||
|
popup_reset(nfc->popup);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_file_select_on_enter(void* context) {
|
void nfc_scene_file_select_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
// Process file_select return
|
// Process file_select return
|
||||||
if(nfc_file_select(nfc->dev)) {
|
if(nfc_file_select(nfc->dev)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
||||||
if(!app) {
|
if(!app) {
|
||||||
@@ -73,7 +73,8 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -96,24 +97,24 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
|
|||||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state & 1) {
|
if(state & 1) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
|
nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_on_exit(void* context) {
|
void nfc_scene_mifare_desfire_app_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear views
|
||||||
text_box_reset(nfc->text_box);
|
text_box_reset(nfc->text_box);
|
||||||
string_reset(nfc->text_box_store);
|
string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t inde
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
@@ -61,7 +61,8 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
|||||||
nfc->scene_manager,
|
nfc->scene_manager,
|
||||||
NfcSceneMifareDesfireData,
|
NfcSceneMifareDesfireData,
|
||||||
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
|
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
|
||||||
return true;
|
consumed = true;
|
||||||
} else {
|
} else {
|
||||||
uint16_t index = event.event - SubmenuIndexDynamic;
|
uint16_t index = event.event - SubmenuIndexDynamic;
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
@@ -84,25 +85,25 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
|||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
|
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state >= MifareDesfireDataStateItem) {
|
if(state >= MifareDesfireDataStateItem) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
|
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_data_on_exit(void* context) {
|
void nfc_scene_mifare_desfire_data_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear views
|
||||||
text_box_reset(nfc->text_box);
|
text_box_reset(nfc->text_box);
|
||||||
string_reset(nfc->text_box_store);
|
string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ enum SubmenuIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -24,7 +24,8 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexSave) {
|
if(event.event == SubmenuIndexSave) {
|
||||||
@@ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
|
|||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
|
void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ enum SubmenuIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -26,7 +26,8 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexSave) {
|
if(event.event == SubmenuIndexSave) {
|
||||||
@@ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
|
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
return scene_manager_search_and_switch_to_previous_scene(
|
consumed =
|
||||||
nfc->scene_manager, NfcSceneStart);
|
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_on_exit(void* context) {
|
void nfc_scene_mifare_ul_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
|
|
||||||
void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) {
|
|
||||||
Nfc* nfc = (Nfc*)context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_not_implemented_on_enter(void* context) {
|
|
||||||
Nfc* nfc = (Nfc*)context;
|
|
||||||
|
|
||||||
// TODO Set data from worker
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
|
||||||
dialog_ex_set_header(dialog_ex, "Not implemented", 60, 24, AlignCenter, AlignCenter);
|
|
||||||
dialog_ex_set_context(dialog_ex, nfc);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_not_implemented_dialog_callback);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = (Nfc*)context;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == DialogExResultLeft) {
|
|
||||||
return scene_manager_previous_scene(nfc->scene_manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_not_implemented_on_exit(void* context) {
|
|
||||||
Nfc* nfc = (Nfc*)context;
|
|
||||||
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
|
||||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
|
||||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_context(dialog_ex, NULL);
|
|
||||||
}
|
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
|
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_card_on_enter(void* context) {
|
void nfc_scene_read_card_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -22,29 +22,26 @@ void nfc_scene_read_card_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_card_on_exit(void* context) {
|
void nfc_scene_read_card_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback(
|
|||||||
void* context) {
|
void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
if(type == InputTypeShort) {
|
if(type == InputTypeShort) {
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_card_success_on_enter(void* context) {
|
void nfc_scene_read_card_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
string_t data_str;
|
string_t data_str;
|
||||||
string_t uid_str;
|
string_t uid_str;
|
||||||
string_init(data_str);
|
string_init(data_str);
|
||||||
@@ -24,9 +26,9 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
Widget* widget = nfc->widget;
|
Widget* widget = nfc->widget;
|
||||||
string_set_str(data_str, nfc_get_dev_type(data->device));
|
string_set_str(data_str, nfc_get_dev_type(data->type));
|
||||||
string_set_str(uid_str, "UID:");
|
string_set_str(uid_str, "UID:");
|
||||||
for(uint8_t i = 0; i < data->uid_len; i++) {
|
for(uint8_t i = 0; i < data->uid_len; i++) {
|
||||||
string_cat_printf(uid_str, " %02X", data->uid[i]);
|
string_cat_printf(uid_str, " %02X", data->uid[i]);
|
||||||
@@ -34,7 +36,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
|
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
|
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
|
||||||
if(data->device == NfcDeviceNfca) {
|
if(data->type == FuriHalNfcTypeA) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
|
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
|
||||||
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
|
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
|
||||||
@@ -44,7 +46,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
string_printf(
|
string_printf(
|
||||||
data_str,
|
data_str,
|
||||||
"%s\nATQA: %02X%02X SAK: %02X",
|
"%s\nATQA: %02X%02X SAK: %02X",
|
||||||
nfc_guess_protocol(data->protocol),
|
nfc_guess_protocol(nfc->dev->dev_data.protocol),
|
||||||
data->atqa[0],
|
data->atqa[0],
|
||||||
data->atqa[1],
|
data->atqa[1],
|
||||||
data->sak);
|
data->sak);
|
||||||
@@ -66,14 +68,14 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
} else if(data->device == NfcDeviceNfca && event.event == GuiButtonTypeRight) {
|
} else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
|
||||||
@@ -84,6 +86,8 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_card_success_on_exit(void* context) {
|
void nfc_scene_read_card_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
widget_reset(nfc->widget);
|
widget_reset(nfc->widget);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
|
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_on_enter(void* context) {
|
void nfc_scene_read_emv_app_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -26,31 +26,30 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_on_exit(void* context) {
|
void nfc_scene_read_emv_app_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,38 @@
|
|||||||
#include "../helpers/nfc_emv_parser.h"
|
#include "../helpers/nfc_emv_parser.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
|
void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) {
|
if(type == InputTypeShort) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_success_on_enter(void* context) {
|
void nfc_scene_read_emv_app_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
||||||
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
Widget* widget = nfc->widget;
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
widget_add_button_element(
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "Run app");
|
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc);
|
||||||
dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter);
|
widget_add_button_element(
|
||||||
dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21);
|
widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc);
|
||||||
// Display UID and AID
|
widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App");
|
||||||
|
widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21);
|
||||||
|
// Display UID
|
||||||
|
string_t temp_str;
|
||||||
|
string_init_printf(temp_str, "UID:");
|
||||||
|
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
||||||
|
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
||||||
|
}
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
|
||||||
|
string_reset(temp_str);
|
||||||
|
// Display application
|
||||||
|
string_printf(temp_str, "App: ");
|
||||||
string_t aid;
|
string_t aid;
|
||||||
string_init(aid);
|
string_init(aid);
|
||||||
bool aid_found =
|
bool aid_found =
|
||||||
@@ -32,19 +43,11 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
|
|||||||
string_cat_printf(aid, "%02X", emv_data->aid[i]);
|
string_cat_printf(aid, "%02X", emv_data->aid[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nfc_text_store_set(
|
string_cat(temp_str, aid);
|
||||||
nfc,
|
widget_add_string_element(
|
||||||
NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT
|
widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
|
||||||
"Application:\n%s",
|
string_clear(temp_str);
|
||||||
nfc_data->uid[0],
|
|
||||||
nfc_data->uid[1],
|
|
||||||
nfc_data->uid[2],
|
|
||||||
nfc_data->uid[3],
|
|
||||||
string_get_cstr(aid));
|
|
||||||
string_clear(aid);
|
string_clear(aid);
|
||||||
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
|
|
||||||
dialog_ex_set_context(dialog_ex, nfc);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_emv_app_success_dialog_callback);
|
|
||||||
|
|
||||||
// Send notification
|
// Send notification
|
||||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
|
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
|
||||||
@@ -54,32 +57,27 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
|
|||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == DialogExResultLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
return scene_manager_previous_scene(nfc->scene_manager);
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
} else if(event.event == DialogExResultRight) {
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_success_on_exit(void* context) {
|
void nfc_scene_read_emv_app_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
// Clear views
|
||||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
widget_reset(nfc->widget);
|
||||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_context(dialog_ex, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
|
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_on_enter(void* context) {
|
void nfc_scene_read_emv_data_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
|
|||||||
// Start worker
|
// Start worker
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateReadEMV,
|
NfcWorkerStateReadEMVData,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_read_emv_data_worker_callback,
|
nfc_read_emv_data_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_on_exit(void* context) {
|
void nfc_scene_read_emv_data_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback(
|
|||||||
GuiButtonType result,
|
GuiButtonType result,
|
||||||
InputType type,
|
InputType type,
|
||||||
void* context) {
|
void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
if(type == InputTypeShort) {
|
if(type == InputTypeShort) {
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
||||||
NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Setup Custom Widget view
|
// Setup Custom Widget view
|
||||||
@@ -78,25 +78,23 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
|||||||
string_clear(disp_currency);
|
string_clear(disp_currency);
|
||||||
}
|
}
|
||||||
string_clear(currency_name);
|
string_clear(currency_name);
|
||||||
|
char temp_str[32];
|
||||||
// Add ATQA
|
// Add ATQA
|
||||||
char atqa_str[16];
|
snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
|
||||||
snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
|
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str);
|
||||||
widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str);
|
|
||||||
// Add UID
|
// Add UID
|
||||||
char uid_str[32];
|
|
||||||
snprintf(
|
snprintf(
|
||||||
uid_str,
|
temp_str,
|
||||||
sizeof(uid_str),
|
sizeof(temp_str),
|
||||||
"UID: %02X %02X %02X %02X",
|
"UID: %02X %02X %02X %02X",
|
||||||
nfc_data->uid[0],
|
nfc_data->uid[0],
|
||||||
nfc_data->uid[1],
|
nfc_data->uid[1],
|
||||||
nfc_data->uid[2],
|
nfc_data->uid[2],
|
||||||
nfc_data->uid[3]);
|
nfc_data->uid[3]);
|
||||||
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str);
|
widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||||
// Add SAK
|
// Add SAK
|
||||||
char sak_str[16];
|
snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak);
|
||||||
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
|
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str);
|
||||||
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
|
|
||||||
// Add expiration date
|
// Add expiration date
|
||||||
if(emv_data->exp_mon) {
|
if(emv_data->exp_mon) {
|
||||||
char exp_str[16];
|
char exp_str[16];
|
||||||
@@ -117,28 +115,30 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
return scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||||
} else if(event.event == GuiButtonTypeRight) {
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
nfc->dev->format = NfcDeviceSaveFormatBankCard;
|
nfc->dev->format = NfcDeviceSaveFormatBankCard;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
return scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_success_on_exit(void* context) {
|
void nfc_scene_read_emv_data_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
widget_reset(nfc->widget);
|
widget_reset(nfc->widget);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
|
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_on_enter(void* context) {
|
void nfc_scene_read_mifare_desfire_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -26,31 +26,28 @@ void nfc_scene_read_mifare_desfire_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
} else if(event.type == SceneManagerEventTypeTick) {
|
||||||
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_on_exit(void* context) {
|
void nfc_scene_read_mifare_desfire_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
|
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
@@ -67,9 +67,9 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
|||||||
|
|
||||||
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
uint32_t state =
|
uint32_t state =
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
|
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
|
||||||
@@ -98,9 +98,8 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
|
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clean dialog
|
// Clean dialog
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
dialog_ex_reset(dialog_ex);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
|
|||||||
// Start worker
|
// Start worker
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateReadMifareUl,
|
NfcWorkerStateReadMifareUltralight,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_read_mifare_ul_worker_callback,
|
nfc_read_mifare_ul_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
@@ -43,6 +43,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
void nfc_scene_read_mifare_ul_on_exit(void* context) {
|
void nfc_scene_read_mifare_ul_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
// Clear view
|
// Clear view
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
|
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
// Send notification
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
|
||||||
// Setup dialog view
|
// Setup dialog view
|
||||||
NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "More");
|
dialog_ex_set_right_button_text(dialog_ex, "More");
|
||||||
@@ -69,9 +69,9 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
|||||||
|
|
||||||
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
uint32_t state =
|
uint32_t state =
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
|
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
|
||||||
@@ -99,14 +99,10 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
|
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clean dialog
|
// Clean views
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
dialog_ex_reset(dialog_ex);
|
text_box_reset(nfc->text_box);
|
||||||
|
|
||||||
// Clean TextBox
|
|
||||||
TextBox* text_box = nfc->text_box;
|
|
||||||
text_box_reset(text_box);
|
|
||||||
string_reset(nfc->text_box_store);
|
string_reset(nfc->text_box_store);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_restore_original_popup_callback(void* context) {
|
void nfc_scene_restore_original_popup_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_restore_original_on_enter(void* context) {
|
void nfc_scene_restore_original_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
@@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -32,15 +32,8 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_restore_original_on_exit(void* context) {
|
void nfc_scene_restore_original_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
popup_set_callback(popup, NULL);
|
|
||||||
popup_set_context(popup, NULL);
|
|
||||||
popup_set_timeout(popup, 0);
|
|
||||||
popup_disable_timeout(popup);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
|
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
|
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
|
void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||||
@@ -29,28 +27,23 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == DialogExResultLeft) {
|
if(event.event == DialogExResultLeft) {
|
||||||
return scene_manager_previous_scene(nfc->scene_manager);
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
} else if(event.event == DialogExResultRight) {
|
} else if(event.event == DialogExResultRight) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
|
void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
// Clean view
|
||||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
|
||||||
dialog_ex_set_context(dialog_ex, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
#include <gui/modules/validators.h>
|
#include <gui/modules/validators.h>
|
||||||
|
|
||||||
void nfc_scene_save_name_text_input_callback(void* context) {
|
void nfc_scene_save_name_text_input_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_save_name_on_enter(void* context) {
|
void nfc_scene_save_name_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
TextInput* text_input = nfc->text_input;
|
TextInput* text_input = nfc->text_input;
|
||||||
@@ -37,7 +37,8 @@ void nfc_scene_save_name_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventTextInputDone) {
|
if(event.event == NfcCustomEventTextInputDone) {
|
||||||
@@ -50,18 +51,18 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
|
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
|
||||||
if(nfc_device_save(nfc->dev, nfc->text_store)) {
|
if(nfc_device_save(nfc->dev, nfc->text_store)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
return true;
|
consumed = true;
|
||||||
} else {
|
} else {
|
||||||
return scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneStart);
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_save_name_on_exit(void* context) {
|
void nfc_scene_save_name_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
void* validator_context = text_input_get_validator_callback_context(nfc->text_input);
|
void* validator_context = text_input_get_validator_callback_context(nfc->text_input);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_scene_save_success_popup_callback(void* context) {
|
void nfc_scene_save_success_popup_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_save_success_on_enter(void* context) {
|
void nfc_scene_save_success_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcSave);
|
DOLPHIN_DEED(DolphinDeedNfcSave);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
@@ -22,7 +22,7 @@ void nfc_scene_save_success_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -47,15 +47,8 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_save_success_on_exit(void* context) {
|
void nfc_scene_save_success_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
Popup* popup = nfc->popup;
|
popup_reset(nfc->popup);
|
||||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
|
||||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 0, NULL);
|
|
||||||
popup_set_callback(popup, NULL);
|
|
||||||
popup_set_context(popup, NULL);
|
|
||||||
popup_set_timeout(popup, 0);
|
|
||||||
popup_disable_timeout(popup);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ enum SubmenuIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_saved_menu_on_enter(void* context) {
|
void nfc_scene_saved_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatUid ||
|
if(nfc->dev->format == NfcDeviceSaveFormatUid ||
|
||||||
@@ -56,7 +56,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -92,7 +92,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_saved_menu_on_exit(void* context) {
|
void nfc_scene_saved_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_set_atqa_byte_input_callback(void* context) {
|
void nfc_scene_set_atqa_byte_input_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_atqa_on_enter(void* context) {
|
void nfc_scene_set_atqa_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
ByteInput* byte_input = nfc->byte_input;
|
ByteInput* byte_input = nfc->byte_input;
|
||||||
@@ -23,19 +23,20 @@ void nfc_scene_set_atqa_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventByteInputDone) {
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_atqa_on_exit(void* context) {
|
void nfc_scene_set_atqa_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
void nfc_scene_set_sak_byte_input_callback(void* context) {
|
void nfc_scene_set_sak_byte_input_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_sak_on_enter(void* context) {
|
void nfc_scene_set_sak_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
ByteInput* byte_input = nfc->byte_input;
|
ByteInput* byte_input = nfc->byte_input;
|
||||||
@@ -23,19 +23,20 @@ void nfc_scene_set_sak_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventByteInputDone) {
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_sak_on_exit(void* context) {
|
void nfc_scene_set_sak_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ enum SubmenuIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_type_on_enter(void* context) {
|
void nfc_scene_set_type_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
@@ -24,26 +24,27 @@ void nfc_scene_set_type_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexNFCA7) {
|
if(event.event == SubmenuIndexNFCA7) {
|
||||||
nfc->dev->dev_data.nfc_data.uid_len = 7;
|
nfc->dev->dev_data.nfc_data.uid_len = 7;
|
||||||
nfc->dev->format = NfcDeviceSaveFormatUid;
|
nfc->dev->format = NfcDeviceSaveFormatUid;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexNFCA4) {
|
} else if(event.event == SubmenuIndexNFCA4) {
|
||||||
nfc->dev->dev_data.nfc_data.uid_len = 4;
|
nfc->dev->dev_data.nfc_data.uid_len = 4;
|
||||||
nfc->dev->format = NfcDeviceSaveFormatUid;
|
nfc->dev->format = NfcDeviceSaveFormatUid;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_type_on_exit(void* context) {
|
void nfc_scene_set_type_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_scene_set_uid_byte_input_callback(void* context) {
|
void nfc_scene_set_uid_byte_input_callback(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_uid_on_enter(void* context) {
|
void nfc_scene_set_uid_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
ByteInput* byte_input = nfc->byte_input;
|
ByteInput* byte_input = nfc->byte_input;
|
||||||
@@ -26,19 +26,20 @@ void nfc_scene_set_uid_on_enter(void* context) {
|
|||||||
|
|
||||||
bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventByteInputDone) {
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
DOLPHIN_DEED(DolphinDeedNfcAdd);
|
DOLPHIN_DEED(DolphinDeedNfcAdd);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_set_uid_on_exit(void* context) {
|
void nfc_scene_set_uid_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ enum SubmenuIndex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_start_on_enter(void* context) {
|
void nfc_scene_start_on_enter(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
@@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_start_on_exit(void* context) {
|
void nfc_scene_start_on_exit(void* context) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
submenu_reset(nfc->submenu);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ void subghz_scene_delete_raw_on_enter(void* context) {
|
|||||||
char delete_str[64];
|
char delete_str[64];
|
||||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name);
|
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name);
|
||||||
widget_add_text_box_element(
|
widget_add_text_box_element(
|
||||||
subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
|
subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false);
|
||||||
|
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
|
subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
|
||||||
|
|||||||
@@ -236,7 +236,15 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) {
|
|||||||
elements_button_center(canvas, "Send");
|
elements_button_center(canvas, "Send");
|
||||||
elements_button_right(canvas, "More");
|
elements_button_right(canvas, "More");
|
||||||
elements_text_box(
|
elements_text_box(
|
||||||
canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name));
|
canvas,
|
||||||
|
4,
|
||||||
|
12,
|
||||||
|
110,
|
||||||
|
44,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
string_get_cstr(model->file_name),
|
||||||
|
true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzReadRAWStatusTX:
|
case SubGhzReadRAWStatusTX:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ static const char* update_task_stage_descr[] = {
|
|||||||
[UpdateTaskStageRadioCommit] = "Applying radio stack",
|
[UpdateTaskStageRadioCommit] = "Applying radio stack",
|
||||||
[UpdateTaskStageLfsBackup] = "Backing up LFS",
|
[UpdateTaskStageLfsBackup] = "Backing up LFS",
|
||||||
[UpdateTaskStageLfsRestore] = "Restoring LFS",
|
[UpdateTaskStageLfsRestore] = "Restoring LFS",
|
||||||
[UpdateTaskStageAssetsUpdate] = "Updating assets",
|
[UpdateTaskStageResourcesUpdate] = "Updating resources",
|
||||||
[UpdateTaskStageCompleted] = "Completed!",
|
[UpdateTaskStageCompleted] = "Completed!",
|
||||||
[UpdateTaskStageError] = "Error",
|
[UpdateTaskStageError] = "Error",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ typedef enum {
|
|||||||
UpdateTaskStageRadioCommit,
|
UpdateTaskStageRadioCommit,
|
||||||
UpdateTaskStageLfsBackup,
|
UpdateTaskStageLfsBackup,
|
||||||
UpdateTaskStageLfsRestore,
|
UpdateTaskStageLfsRestore,
|
||||||
UpdateTaskStageAssetsUpdate,
|
UpdateTaskStageResourcesUpdate,
|
||||||
UpdateTaskStageCompleted,
|
UpdateTaskStageCompleted,
|
||||||
UpdateTaskStageError,
|
UpdateTaskStageError,
|
||||||
} UpdateTaskStage;
|
} UpdateTaskStage;
|
||||||
|
|||||||
@@ -166,14 +166,13 @@ static bool update_task_post_update(UpdateTask* update_task) {
|
|||||||
.total_files = 0,
|
.total_files = 0,
|
||||||
.processed_files = 0,
|
.processed_files = 0,
|
||||||
};
|
};
|
||||||
update_task_set_progress(update_task, UpdateTaskStageAssetsUpdate, 0);
|
update_task_set_progress(update_task, UpdateTaskStageResourcesUpdate, 0);
|
||||||
|
|
||||||
path_concat(
|
path_concat(
|
||||||
string_get_cstr(update_task->update_path),
|
string_get_cstr(update_task->update_path),
|
||||||
string_get_cstr(update_task->manifest->resource_bundle),
|
string_get_cstr(update_task->manifest->resource_bundle),
|
||||||
file_path);
|
file_path);
|
||||||
|
|
||||||
update_task_set_progress(update_task, UpdateTaskStageProgress, 0);
|
|
||||||
TarArchive* archive = tar_archive_alloc(update_task->storage);
|
TarArchive* archive = tar_archive_alloc(update_task->storage);
|
||||||
tar_archive_set_file_callback(archive, update_task_resource_unpack_cb, &progress);
|
tar_archive_set_file_callback(archive, update_task_resource_unpack_cb, &progress);
|
||||||
success = tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ);
|
success = tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ);
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ PROJECT_ROOT = $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..)
|
|||||||
include $(PROJECT_ROOT)/assets/assets.mk
|
include $(PROJECT_ROOT)/assets/assets.mk
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: icons protobuf dolphin
|
all: icons protobuf dolphin manifest
|
||||||
|
|
||||||
$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER)
|
$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILER)
|
||||||
@echo "\tASSETS\t\t" $@
|
@echo "\tASSETS\t\t" $@
|
||||||
@$(ASSETS_COMPILLER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)"
|
@$(ASSETS_COMPILER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)"
|
||||||
|
|
||||||
.PHONY: icons
|
.PHONY: icons
|
||||||
icons: $(ASSETS)
|
icons: $(ASSETS)
|
||||||
@@ -22,11 +22,15 @@ protobuf: $(PROTOBUF)
|
|||||||
|
|
||||||
$(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR)
|
$(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR)
|
||||||
@echo "\tDOLPHIN blocking"
|
@echo "\tDOLPHIN blocking"
|
||||||
@$(ASSETS_COMPILLER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
|
@$(ASSETS_COMPILER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
|
||||||
@echo "\tDOLPHIN internal"
|
@echo "\tDOLPHIN internal"
|
||||||
@$(ASSETS_COMPILLER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
|
@$(ASSETS_COMPILER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)"
|
||||||
@echo "\tDOLPHIN external"
|
@echo "\tDOLPHIN external"
|
||||||
@$(ASSETS_COMPILLER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)"
|
@$(ASSETS_COMPILER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)"
|
||||||
|
|
||||||
|
.PHONY: manifest
|
||||||
|
manifest:
|
||||||
|
$(ASSETS_COMPILER) manifest $(RESOURCES_DIR)
|
||||||
|
|
||||||
.PHONY: dolphin
|
.PHONY: dolphin
|
||||||
dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR)
|
dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR)
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
ASSETS_DIR := $(PROJECT_ROOT)/assets
|
ASSETS_DIR := $(PROJECT_ROOT)/assets
|
||||||
ASSETS_COMPILLER := $(PROJECT_ROOT)/scripts/assets.py
|
ASSETS_COMPILER := $(PROJECT_ROOT)/scripts/assets.py
|
||||||
ASSETS_COMPILED_DIR := $(ASSETS_DIR)/compiled
|
ASSETS_COMPILED_DIR := $(ASSETS_DIR)/compiled
|
||||||
ASSETS_SOURCE_DIR := $(ASSETS_DIR)/icons
|
ASSETS_SOURCE_DIR := $(ASSETS_DIR)/icons
|
||||||
|
|
||||||
ASSETS_SOURCES += $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate')
|
ASSETS_SOURCES += $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate')
|
||||||
ASSETS += $(ASSETS_COMPILED_DIR)/assets_icons.c
|
ASSETS += $(ASSETS_COMPILED_DIR)/assets_icons.c
|
||||||
|
|
||||||
|
RESOURCES_DIR := $(ASSETS_DIR)/resources
|
||||||
|
RESOURCES_MANIFEST := $(RESOURCES_DIR)/Manifest
|
||||||
|
RESOURCES_FILES := $(shell find $(RESOURCES_DIR) ! -name Manifest -type f)
|
||||||
|
|
||||||
DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin
|
DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin
|
||||||
DOLPHIN_INTERNAL_OUTPUT_DIR := $(ASSETS_COMPILED_DIR)
|
DOLPHIN_INTERNAL_OUTPUT_DIR := $(ASSETS_COMPILED_DIR)
|
||||||
DOLPHIN_EXTERNAL_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin
|
DOLPHIN_EXTERNAL_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin
|
||||||
|
|||||||
240
assets/resources/Manifest
Normal file
240
assets/resources/Manifest
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
V:0
|
||||||
|
T:1650389893
|
||||||
|
D:badusb
|
||||||
|
D:dolphin
|
||||||
|
D:infrared
|
||||||
|
D:nfc
|
||||||
|
D:subghz
|
||||||
|
D:u2f
|
||||||
|
F:bb8ffef2d052f171760ce3dc5220cbad:1591:badusb/demo_macos.txt
|
||||||
|
F:e538ad2ce5a06ec45e1b5b24824901b1:1552:badusb/demo_windows.txt
|
||||||
|
D:dolphin/L1_Boxing_128x64
|
||||||
|
D:dolphin/L1_Cry_128x64
|
||||||
|
D:dolphin/L1_Furippa1_128x64
|
||||||
|
D:dolphin/L1_Laptop_128x51
|
||||||
|
D:dolphin/L1_Leaving_sad_128x64
|
||||||
|
D:dolphin/L1_Mad_fist_128x64
|
||||||
|
D:dolphin/L1_Read_books_128x64
|
||||||
|
D:dolphin/L1_Recording_128x51
|
||||||
|
D:dolphin/L1_Sleep_128x64
|
||||||
|
D:dolphin/L1_Waves_128x50
|
||||||
|
D:dolphin/L2_Furippa2_128x64
|
||||||
|
D:dolphin/L2_Hacking_pc_128x64
|
||||||
|
D:dolphin/L2_Soldering_128x64
|
||||||
|
D:dolphin/L3_Furippa3_128x64
|
||||||
|
D:dolphin/L3_Hijack_radio_128x64
|
||||||
|
D:dolphin/L3_Lab_research_128x54
|
||||||
|
F:d1148ab5354eaf4fa7f959589d840932:1563:dolphin/manifest.txt
|
||||||
|
F:d37be8444102ec5cde5fe3a85d55b57d:481:dolphin/L1_Boxing_128x64/frame_0.bm
|
||||||
|
F:54fb07443bc153ded9589b74d23b4263:461:dolphin/L1_Boxing_128x64/frame_1.bm
|
||||||
|
F:e007afe130d699c715b99ce8e5b407bd:531:dolphin/L1_Boxing_128x64/frame_2.bm
|
||||||
|
F:a999a9a6c76c66158f1aa5ccb56de7c9:437:dolphin/L1_Boxing_128x64/frame_3.bm
|
||||||
|
F:ec6af9cb451ab16c0fa62e95e8134b49:459:dolphin/L1_Boxing_128x64/frame_4.bm
|
||||||
|
F:2aa0c1e7bf1131b9dc172aa595ec01f2:450:dolphin/L1_Boxing_128x64/frame_5.bm
|
||||||
|
F:bbc8f750d17d156438c5cfe1122ec7f4:442:dolphin/L1_Boxing_128x64/frame_6.bm
|
||||||
|
F:f6e51ada3e3285e330714dab5b4277dd:418:dolphin/L1_Boxing_128x64/meta.txt
|
||||||
|
F:ab33a6f37209541f3db938d1cfe1706f:889:dolphin/L1_Cry_128x64/frame_0.bm
|
||||||
|
F:1b3fdeb404af0f7402caa5a5e091a8f8:911:dolphin/L1_Cry_128x64/frame_1.bm
|
||||||
|
F:4db644b173af72f3d371d2bd81f76b05:910:dolphin/L1_Cry_128x64/frame_2.bm
|
||||||
|
F:cd4c0ef67a8e514edecd9600242db068:923:dolphin/L1_Cry_128x64/frame_3.bm
|
||||||
|
F:ee02e9589e0714d3e2bc0d93aa294ccb:894:dolphin/L1_Cry_128x64/frame_4.bm
|
||||||
|
F:7703a7d9745d13b45d73ce4b86b4cdc8:940:dolphin/L1_Cry_128x64/frame_5.bm
|
||||||
|
F:ee6de6a0ed903317c4948cb445e0a9a8:915:dolphin/L1_Cry_128x64/frame_6.bm
|
||||||
|
F:a3892e45826c66f48d3d64fb81521446:934:dolphin/L1_Cry_128x64/frame_7.bm
|
||||||
|
F:680b12cc4dad722d6583b7e710bfc297:516:dolphin/L1_Cry_128x64/meta.txt
|
||||||
|
F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_0.bm
|
||||||
|
F:5669bee57c7b3d93a1665dd87fd5372a:325:dolphin/L1_Furippa1_128x64/frame_1.bm
|
||||||
|
F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L1_Furippa1_128x64/frame_10.bm
|
||||||
|
F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L1_Furippa1_128x64/frame_11.bm
|
||||||
|
F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L1_Furippa1_128x64/frame_12.bm
|
||||||
|
F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L1_Furippa1_128x64/frame_13.bm
|
||||||
|
F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L1_Furippa1_128x64/frame_14.bm
|
||||||
|
F:535c0eca62703eb7df36f17334a6191b:719:dolphin/L1_Furippa1_128x64/frame_15.bm
|
||||||
|
F:7c03af85ade9b791755f3a4d106c2b7c:458:dolphin/L1_Furippa1_128x64/frame_16.bm
|
||||||
|
F:41b8fea16ad8705f4594e6119eade395:400:dolphin/L1_Furippa1_128x64/frame_17.bm
|
||||||
|
F:2db7fd3da5208a8e41902ae27cf41702:333:dolphin/L1_Furippa1_128x64/frame_18.bm
|
||||||
|
F:7e47428442e0f04959fc6afde979936e:351:dolphin/L1_Furippa1_128x64/frame_2.bm
|
||||||
|
F:0eb187078f169d7a852e97ecf430aea0:324:dolphin/L1_Furippa1_128x64/frame_3.bm
|
||||||
|
F:967c402971a442a5bf28eba804bb3ff4:387:dolphin/L1_Furippa1_128x64/frame_4.bm
|
||||||
|
F:175cb930fba0fc86f54a3a109b741708:390:dolphin/L1_Furippa1_128x64/frame_5.bm
|
||||||
|
F:f8c3ee1ab657549d1d00c1c72d8d2ff5:407:dolphin/L1_Furippa1_128x64/frame_6.bm
|
||||||
|
F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_7.bm
|
||||||
|
F:8f649ff34b224f4e564644a4494c54ed:283:dolphin/L1_Furippa1_128x64/frame_8.bm
|
||||||
|
F:3ec3c40d26bf8d3e691b1335d20d4ec0:312:dolphin/L1_Furippa1_128x64/frame_9.bm
|
||||||
|
F:ebe088426d184cf6651288accd21add6:241:dolphin/L1_Furippa1_128x64/meta.txt
|
||||||
|
F:d02fdfd1a3b89da00d2acf32bd09da80:555:dolphin/L1_Laptop_128x51/frame_0.bm
|
||||||
|
F:7e29ea503d41023fa3895d15458f106d:557:dolphin/L1_Laptop_128x51/frame_1.bm
|
||||||
|
F:eb55e0629de873f537d8412ced528eb4:560:dolphin/L1_Laptop_128x51/frame_2.bm
|
||||||
|
F:1516472ab3c140dd5bd4d089caa44747:556:dolphin/L1_Laptop_128x51/frame_3.bm
|
||||||
|
F:61172f89cf0a17bd7f978edccdeed166:560:dolphin/L1_Laptop_128x51/frame_4.bm
|
||||||
|
F:9d54913928c7e9477b6b8a43f3767621:554:dolphin/L1_Laptop_128x51/frame_5.bm
|
||||||
|
F:5243d6272bbb213e9c17af07ee011402:553:dolphin/L1_Laptop_128x51/frame_6.bm
|
||||||
|
F:aa68e0f28f117891ba0f4d7613224fc6:560:dolphin/L1_Laptop_128x51/frame_7.bm
|
||||||
|
F:9ef1935ab29fe70bbc517f4b602547d7:403:dolphin/L1_Laptop_128x51/meta.txt
|
||||||
|
F:6ce34e62c5bf4764a4163101afe63e60:514:dolphin/L1_Leaving_sad_128x64/frame_0.bm
|
||||||
|
F:19a0e0c518d222d91d24b8712ab6bb80:526:dolphin/L1_Leaving_sad_128x64/frame_1.bm
|
||||||
|
F:837bfb424c8d8a3bfbda7d6a28ba5a5c:316:dolphin/L1_Leaving_sad_128x64/frame_10.bm
|
||||||
|
F:1a69b6f63a96e0958837ea8b21db3966:294:dolphin/L1_Leaving_sad_128x64/frame_11.bm
|
||||||
|
F:c3ea827593a4563d544dfb7e99d73885:322:dolphin/L1_Leaving_sad_128x64/frame_12.bm
|
||||||
|
F:1e3842669191fe9599f830ac133e0751:542:dolphin/L1_Leaving_sad_128x64/frame_2.bm
|
||||||
|
F:9161660e6827bd776a15eefa2a8add19:557:dolphin/L1_Leaving_sad_128x64/frame_3.bm
|
||||||
|
F:d01a79fdb4f84397d82bf9927aeb71e0:488:dolphin/L1_Leaving_sad_128x64/frame_4.bm
|
||||||
|
F:316e30ef319c080fab2a79c21e526319:469:dolphin/L1_Leaving_sad_128x64/frame_5.bm
|
||||||
|
F:09a812d59b60b5fe7724057daa14ad60:499:dolphin/L1_Leaving_sad_128x64/frame_6.bm
|
||||||
|
F:9eb07b76cc864a0ce2918d68e41d4500:486:dolphin/L1_Leaving_sad_128x64/frame_7.bm
|
||||||
|
F:cf8c4cc4abbd700b096037b7ebfd0e31:403:dolphin/L1_Leaving_sad_128x64/frame_8.bm
|
||||||
|
F:889728ded689203aa82193e573912d18:317:dolphin/L1_Leaving_sad_128x64/frame_9.bm
|
||||||
|
F:2bff1f09ad1e9059a60e08990ca1d414:477:dolphin/L1_Leaving_sad_128x64/meta.txt
|
||||||
|
F:c31a882e95ed5c69fd63226db2188710:520:dolphin/L1_Mad_fist_128x64/frame_0.bm
|
||||||
|
F:740326828f6ba6e29373943ba835e77f:540:dolphin/L1_Mad_fist_128x64/frame_1.bm
|
||||||
|
F:0c9693dda040fd73ca6d773a10924bd8:542:dolphin/L1_Mad_fist_128x64/frame_10.bm
|
||||||
|
F:425c1d101debd1e9502db2628640b704:505:dolphin/L1_Mad_fist_128x64/frame_11.bm
|
||||||
|
F:aa576f7dbd14ec682f6c50314165fb14:501:dolphin/L1_Mad_fist_128x64/frame_12.bm
|
||||||
|
F:712335eabefb8c7bb7fb2f4301419c10:500:dolphin/L1_Mad_fist_128x64/frame_13.bm
|
||||||
|
F:b6e11711ea4dcc2e64f267d888f91baf:515:dolphin/L1_Mad_fist_128x64/frame_2.bm
|
||||||
|
F:61bdd22a2b1e67efe093b6acf7dfadce:538:dolphin/L1_Mad_fist_128x64/frame_3.bm
|
||||||
|
F:20ae06a3ce7a07656e578edb024e2b3f:512:dolphin/L1_Mad_fist_128x64/frame_4.bm
|
||||||
|
F:45cf2bd55365a7328df39fe98a496cc9:519:dolphin/L1_Mad_fist_128x64/frame_5.bm
|
||||||
|
F:4b8840eebb3a4a1ead69a7130816047e:524:dolphin/L1_Mad_fist_128x64/frame_6.bm
|
||||||
|
F:0de4497a5fbf80cc93e523465c5e3122:515:dolphin/L1_Mad_fist_128x64/frame_7.bm
|
||||||
|
F:32d8ddeb19bfa415fe283666b1e323a2:517:dolphin/L1_Mad_fist_128x64/frame_8.bm
|
||||||
|
F:a42a0578c2d0411500fb3485a3beb536:526:dolphin/L1_Mad_fist_128x64/frame_9.bm
|
||||||
|
F:10a521c78168a5928c859494e2a61cd2:349:dolphin/L1_Mad_fist_128x64/meta.txt
|
||||||
|
F:61565b7be9a69a60ce2dbae0273df347:653:dolphin/L1_Read_books_128x64/frame_0.bm
|
||||||
|
F:cf5a2d423540e3af37e789d70c9c1fbf:653:dolphin/L1_Read_books_128x64/frame_1.bm
|
||||||
|
F:c91935861979d024e6637b8810889878:650:dolphin/L1_Read_books_128x64/frame_2.bm
|
||||||
|
F:0c007a30f396f3e7a0ded2b24080357d:646:dolphin/L1_Read_books_128x64/frame_3.bm
|
||||||
|
F:323a52816dd79d6d3186f451e26e06ad:650:dolphin/L1_Read_books_128x64/frame_4.bm
|
||||||
|
F:494f27958f4cea9b94d09cf27725c5cd:652:dolphin/L1_Read_books_128x64/frame_5.bm
|
||||||
|
F:a6a7491fe80255e1745c9f293da52805:646:dolphin/L1_Read_books_128x64/frame_6.bm
|
||||||
|
F:238497e6643fd491cd6002e98c615c05:647:dolphin/L1_Read_books_128x64/frame_7.bm
|
||||||
|
F:300651e8f53d9a29ae38d4b9292c73cf:643:dolphin/L1_Read_books_128x64/frame_8.bm
|
||||||
|
F:3d9568deeff646b677092902a98f9ceb:325:dolphin/L1_Read_books_128x64/meta.txt
|
||||||
|
F:2aba555567ab70cff003ded4138c6721:663:dolphin/L1_Recording_128x51/frame_0.bm
|
||||||
|
F:8456c6e86825957e5662e2f08eb6c116:657:dolphin/L1_Recording_128x51/frame_1.bm
|
||||||
|
F:2e4a1aca5afa5a6ab254884210875eb4:629:dolphin/L1_Recording_128x51/frame_10.bm
|
||||||
|
F:9f1cf96598e3d935879b1d0c97705778:659:dolphin/L1_Recording_128x51/frame_11.bm
|
||||||
|
F:409abfeca974e5649affcd1faafea988:628:dolphin/L1_Recording_128x51/frame_2.bm
|
||||||
|
F:66b2a5abf05acbf79f9943e01b8b8cec:654:dolphin/L1_Recording_128x51/frame_3.bm
|
||||||
|
F:d55c5ed28c2ff48f42ab30b420d64fa3:662:dolphin/L1_Recording_128x51/frame_4.bm
|
||||||
|
F:2ce12d8cfdd953c9dadb9459c580a320:622:dolphin/L1_Recording_128x51/frame_5.bm
|
||||||
|
F:da631e3837fcdf3ee9e6abdf17fb764b:664:dolphin/L1_Recording_128x51/frame_6.bm
|
||||||
|
F:604a7cdac2491c9bc2e88b9e91c99dcc:626:dolphin/L1_Recording_128x51/frame_7.bm
|
||||||
|
F:fc94649dc98244dd9a0ab7fe62721d3c:663:dolphin/L1_Recording_128x51/frame_8.bm
|
||||||
|
F:b2475ab8ee26cbd9a403ee603520bd35:661:dolphin/L1_Recording_128x51/frame_9.bm
|
||||||
|
F:a7c2b3b420706712149cc2426c68df4f:219:dolphin/L1_Recording_128x51/meta.txt
|
||||||
|
F:9858fd34b55cebcb9be50c5710212a13:580:dolphin/L1_Sleep_128x64/frame_0.bm
|
||||||
|
F:e47ef8c846083b8fde028b1724861444:589:dolphin/L1_Sleep_128x64/frame_1.bm
|
||||||
|
F:9749bd05b47fd07cc3a41ab201f86bf4:582:dolphin/L1_Sleep_128x64/frame_2.bm
|
||||||
|
F:edf11266b20b846ace622e41cd36906b:597:dolphin/L1_Sleep_128x64/frame_3.bm
|
||||||
|
F:8fbb96a9d809d85fa6bad931fe4e6fe2:510:dolphin/L1_Sleep_128x64/meta.txt
|
||||||
|
F:283b41f1b2c581c510ff176293b7288a:443:dolphin/L1_Waves_128x50/frame_0.bm
|
||||||
|
F:c9fc5127e1d8a4217b6b177716725ba0:448:dolphin/L1_Waves_128x50/frame_1.bm
|
||||||
|
F:8e0797bf26d5d8d3cbeb99798c222b80:463:dolphin/L1_Waves_128x50/frame_2.bm
|
||||||
|
F:da02b1deb3119b31f2b8f182d5bf3242:472:dolphin/L1_Waves_128x50/frame_3.bm
|
||||||
|
F:8e6fb4133acbda7e5bb9adad0aed306c:620:dolphin/L1_Waves_128x50/meta.txt
|
||||||
|
F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_0.bm
|
||||||
|
F:9e628f5e154f12d6c57b13befed1f5f6:385:dolphin/L2_Furippa2_128x64/frame_1.bm
|
||||||
|
F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L2_Furippa2_128x64/frame_10.bm
|
||||||
|
F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L2_Furippa2_128x64/frame_11.bm
|
||||||
|
F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L2_Furippa2_128x64/frame_12.bm
|
||||||
|
F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L2_Furippa2_128x64/frame_13.bm
|
||||||
|
F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L2_Furippa2_128x64/frame_14.bm
|
||||||
|
F:e3c92103f403857b502081d3b058e53a:740:dolphin/L2_Furippa2_128x64/frame_15.bm
|
||||||
|
F:432669d796bbf7be1d14f5b7db036a92:533:dolphin/L2_Furippa2_128x64/frame_16.bm
|
||||||
|
F:53485c6b465c80a1ce8ddf03c4976039:451:dolphin/L2_Furippa2_128x64/frame_17.bm
|
||||||
|
F:333b75b16c088428a28259c931630fb9:397:dolphin/L2_Furippa2_128x64/frame_18.bm
|
||||||
|
F:ed02d68380382361f3f01cbf01d13b0c:402:dolphin/L2_Furippa2_128x64/frame_2.bm
|
||||||
|
F:b0ba042d7b60dc5681182b1d4005f0a2:374:dolphin/L2_Furippa2_128x64/frame_3.bm
|
||||||
|
F:518a84fa5a4e9e7f84246d5d82e87f15:440:dolphin/L2_Furippa2_128x64/frame_4.bm
|
||||||
|
F:9b7b0ae6f4f55d30cb43b0465216aa25:449:dolphin/L2_Furippa2_128x64/frame_5.bm
|
||||||
|
F:03b153949b0dae2efe1fc5f0dc57a0ef:466:dolphin/L2_Furippa2_128x64/frame_6.bm
|
||||||
|
F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_7.bm
|
||||||
|
F:a8433f451cf3efc4ce2fb04a38c1f84f:319:dolphin/L2_Furippa2_128x64/frame_8.bm
|
||||||
|
F:d32a11bf9779d57191c1e59fe69cf83d:317:dolphin/L2_Furippa2_128x64/frame_9.bm
|
||||||
|
F:ebe088426d184cf6651288accd21add6:241:dolphin/L2_Furippa2_128x64/meta.txt
|
||||||
|
F:af4ec0085c29732085c51b18dc97bc27:543:dolphin/L2_Hacking_pc_128x64/frame_0.bm
|
||||||
|
F:eb141965fb6fb9f8b28766bac92abe1a:545:dolphin/L2_Hacking_pc_128x64/frame_1.bm
|
||||||
|
F:f7b33d3541dab08aaf4e8375e262b982:548:dolphin/L2_Hacking_pc_128x64/frame_2.bm
|
||||||
|
F:03634d90c54fd235aa76c0f9f794c80b:608:dolphin/L2_Hacking_pc_128x64/frame_3.bm
|
||||||
|
F:4c77406302f3fb74f8bdba568097082a:609:dolphin/L2_Hacking_pc_128x64/frame_4.bm
|
||||||
|
F:b0d1783358094534ac95b3455124d5fe:409:dolphin/L2_Hacking_pc_128x64/meta.txt
|
||||||
|
F:584c92e6fb15e99389b84d567e6d4d02:699:dolphin/L2_Soldering_128x64/frame_0.bm
|
||||||
|
F:3fa01b93460379204b6d14f43573b4f3:688:dolphin/L2_Soldering_128x64/frame_1.bm
|
||||||
|
F:6fad29757d4b7231b1d0ec53d0529b45:699:dolphin/L2_Soldering_128x64/frame_10.bm
|
||||||
|
F:e82c83e5a03abf4f6a1efd0a0f1ca33a:689:dolphin/L2_Soldering_128x64/frame_2.bm
|
||||||
|
F:7f9f310e22ef85af225dd1aefa2c47ba:689:dolphin/L2_Soldering_128x64/frame_3.bm
|
||||||
|
F:1ff31af6f90f07c0cdfa3283f52a5adc:693:dolphin/L2_Soldering_128x64/frame_4.bm
|
||||||
|
F:1a8f25aff949860cc6ffc79b4f48d5dd:696:dolphin/L2_Soldering_128x64/frame_5.bm
|
||||||
|
F:dbaa75feb8aebaf9b1cc5201c29952b8:712:dolphin/L2_Soldering_128x64/frame_6.bm
|
||||||
|
F:ee356bd981fba90c402d8e08d3015792:732:dolphin/L2_Soldering_128x64/frame_7.bm
|
||||||
|
F:09d5c5a685df606562d407bb9dac798e:705:dolphin/L2_Soldering_128x64/frame_8.bm
|
||||||
|
F:5451816e73bad029b3b9f3f55d294582:698:dolphin/L2_Soldering_128x64/frame_9.bm
|
||||||
|
F:c38ffad11987faf5ba6e363ead705e78:319:dolphin/L2_Soldering_128x64/meta.txt
|
||||||
|
F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_0.bm
|
||||||
|
F:8cf20e07d84fd6a1157ba932beca70ea:438:dolphin/L3_Furippa3_128x64/frame_1.bm
|
||||||
|
F:018344c951691b7b1d77c1c6729d3e42:559:dolphin/L3_Furippa3_128x64/frame_10.bm
|
||||||
|
F:07008e2508064ab7a8467802472a9803:728:dolphin/L3_Furippa3_128x64/frame_11.bm
|
||||||
|
F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L3_Furippa3_128x64/frame_12.bm
|
||||||
|
F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L3_Furippa3_128x64/frame_13.bm
|
||||||
|
F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L3_Furippa3_128x64/frame_14.bm
|
||||||
|
F:e333224a4bed87b606df57a252ed4887:741:dolphin/L3_Furippa3_128x64/frame_15.bm
|
||||||
|
F:a20a6abfbd66fc3f92c66adacc4444a3:559:dolphin/L3_Furippa3_128x64/frame_16.bm
|
||||||
|
F:c1e051dce6b90e4f69b4792d0356a6b3:492:dolphin/L3_Furippa3_128x64/frame_17.bm
|
||||||
|
F:377f3621507c6590120cbc1c8ca92999:445:dolphin/L3_Furippa3_128x64/frame_18.bm
|
||||||
|
F:81f09c0fcd2bddb8a107a199e7149230:463:dolphin/L3_Furippa3_128x64/frame_2.bm
|
||||||
|
F:ed7fd1ada1070493462c1899f7372baf:424:dolphin/L3_Furippa3_128x64/frame_3.bm
|
||||||
|
F:e5fb2cdc4e08d6abff3191d37a1007ed:499:dolphin/L3_Furippa3_128x64/frame_4.bm
|
||||||
|
F:923a05250e5a93c7db7bbbf48448d164:504:dolphin/L3_Furippa3_128x64/frame_5.bm
|
||||||
|
F:1e9628db28a9a908c4a4b24cb16c5d20:521:dolphin/L3_Furippa3_128x64/frame_6.bm
|
||||||
|
F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_7.bm
|
||||||
|
F:f1ec6e12daba9490f9e2e0e308ae3f83:419:dolphin/L3_Furippa3_128x64/frame_8.bm
|
||||||
|
F:106997120ad4cd23bd51e6f26bd7d74d:435:dolphin/L3_Furippa3_128x64/frame_9.bm
|
||||||
|
F:ebe088426d184cf6651288accd21add6:241:dolphin/L3_Furippa3_128x64/meta.txt
|
||||||
|
F:42970030123b2468984785fea7c60318:524:dolphin/L3_Hijack_radio_128x64/frame_0.bm
|
||||||
|
F:491c6d8ef21e48ca0f6b5fbd269c820b:527:dolphin/L3_Hijack_radio_128x64/frame_1.bm
|
||||||
|
F:ff499c8716c5f7fc1110a5ee82bda20c:550:dolphin/L3_Hijack_radio_128x64/frame_10.bm
|
||||||
|
F:ee39d82d6efc6a6992d19b6d75a6c509:572:dolphin/L3_Hijack_radio_128x64/frame_11.bm
|
||||||
|
F:5d14e8cb9d67bf8f597d6c749d07a135:539:dolphin/L3_Hijack_radio_128x64/frame_12.bm
|
||||||
|
F:9461004b75a34a36097668159c4cabe6:579:dolphin/L3_Hijack_radio_128x64/frame_13.bm
|
||||||
|
F:c925d4b1dff9c81463944cf930d7da8d:526:dolphin/L3_Hijack_radio_128x64/frame_2.bm
|
||||||
|
F:f98ed80cfab3a94b580be81654401c89:529:dolphin/L3_Hijack_radio_128x64/frame_3.bm
|
||||||
|
F:97ba548c27732be9e05fb8f7be8204ce:571:dolphin/L3_Hijack_radio_128x64/frame_4.bm
|
||||||
|
F:524932eb2391057fc1dea7237c7086e3:574:dolphin/L3_Hijack_radio_128x64/frame_5.bm
|
||||||
|
F:8eb9672f719926ac9c4c158575f388cd:524:dolphin/L3_Hijack_radio_128x64/frame_6.bm
|
||||||
|
F:7ca93fbab93bc278d4a11089d624a07b:655:dolphin/L3_Hijack_radio_128x64/frame_7.bm
|
||||||
|
F:37b4368f0b7235f3a7347bf499541666:645:dolphin/L3_Hijack_radio_128x64/frame_8.bm
|
||||||
|
F:ea9c3d7bab4756c2916369d5e130fa71:611:dolphin/L3_Hijack_radio_128x64/frame_9.bm
|
||||||
|
F:8583743f18a12ff647d3478e7aebdad6:230:dolphin/L3_Hijack_radio_128x64/meta.txt
|
||||||
|
F:f5f02a9df03bba734bdb7ed3297795f0:611:dolphin/L3_Lab_research_128x54/frame_0.bm
|
||||||
|
F:8f9655ad286464159443922d00e45620:614:dolphin/L3_Lab_research_128x54/frame_1.bm
|
||||||
|
F:7793b1bc107d4ea2e311e92dc16bf946:576:dolphin/L3_Lab_research_128x54/frame_10.bm
|
||||||
|
F:f24b8409f9dc770f3845424fe0ab489e:585:dolphin/L3_Lab_research_128x54/frame_11.bm
|
||||||
|
F:4ea93c4482dac43f40b67cc308f21e6d:571:dolphin/L3_Lab_research_128x54/frame_12.bm
|
||||||
|
F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_13.bm
|
||||||
|
F:79719219aaebc95ea525def9173cabf5:618:dolphin/L3_Lab_research_128x54/frame_2.bm
|
||||||
|
F:05572cfd756704acd6ce9d6c15d03fc0:608:dolphin/L3_Lab_research_128x54/frame_3.bm
|
||||||
|
F:a26604a0d5427d5cf62a7a911a68b16c:615:dolphin/L3_Lab_research_128x54/frame_4.bm
|
||||||
|
F:9edc345fe53017970f93dc680818e63e:618:dolphin/L3_Lab_research_128x54/frame_5.bm
|
||||||
|
F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_6.bm
|
||||||
|
F:5442895c85f769349288aa3df0990f9d:585:dolphin/L3_Lab_research_128x54/frame_7.bm
|
||||||
|
F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm
|
||||||
|
F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm
|
||||||
|
F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt
|
||||||
|
D:infrared/assets
|
||||||
|
F:5b16e1a59daf3ef1d0fc95b3b5596d67:74300:infrared/assets/tv.ir
|
||||||
|
D:nfc/assets
|
||||||
|
F:c6826a621d081d68309e4be424d3d974:4715:nfc/assets/aid.nfc
|
||||||
|
F:86efbebdf41bb6bf15cc51ef88f069d5:2565:nfc/assets/country_code.nfc
|
||||||
|
F:41b4f08774249014cb8d3dffa5f5c07d:1757:nfc/assets/currency_code.nfc
|
||||||
|
F:c60e862919731b0bd538a1001bbc1098:17453:nfc/assets/mf_classic_dict.nfc
|
||||||
|
D:subghz/assets
|
||||||
|
F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo
|
||||||
|
F:610a0ffa2479a874f2060eb2348104c5:2712:subghz/assets/keeloq_mfcodes
|
||||||
|
F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user
|
||||||
|
F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s
|
||||||
|
F:00e967e5c558e44a0651bb821d5cf1d0:414:subghz/assets/setting_frequency_analyzer_user
|
||||||
|
F:16e8c7cb4a13f26ea55b2b0a59f9cc7a:554:subghz/assets/setting_user
|
||||||
|
D:u2f/assets
|
||||||
|
F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der
|
||||||
|
F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f
|
||||||
@@ -48,13 +48,12 @@ void furi_hal_nfc_exit_sleep() {
|
|||||||
rfalLowPowerModeStop();
|
rfalLowPowerModeStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_nfc_detect(
|
bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) {
|
||||||
rfalNfcDevice** dev_list,
|
furi_assert(nfc_data);
|
||||||
uint8_t* dev_cnt,
|
|
||||||
uint32_t timeout,
|
rfalNfcDevice* dev_list = NULL;
|
||||||
bool deactivate) {
|
uint8_t dev_cnt = 0;
|
||||||
furi_assert(dev_list);
|
bool detected = false;
|
||||||
furi_assert(dev_cnt);
|
|
||||||
|
|
||||||
rfalLowPowerModeStop();
|
rfalLowPowerModeStop();
|
||||||
rfalNfcState state = rfalNfcGetState();
|
rfalNfcState state = rfalNfcGetState();
|
||||||
@@ -77,9 +76,13 @@ bool furi_hal_nfc_detect(
|
|||||||
|
|
||||||
uint32_t start = DWT->CYCCNT;
|
uint32_t start = DWT->CYCCNT;
|
||||||
rfalNfcDiscover(¶ms);
|
rfalNfcDiscover(¶ms);
|
||||||
while(state != RFAL_NFC_STATE_ACTIVATED) {
|
while(true) {
|
||||||
rfalNfcWorker();
|
rfalNfcWorker();
|
||||||
state = rfalNfcGetState();
|
state = rfalNfcGetState();
|
||||||
|
if(state == RFAL_NFC_STATE_ACTIVATED) {
|
||||||
|
detected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
FURI_LOG_T(TAG, "Current state %d", state);
|
FURI_LOG_T(TAG, "Current state %d", state);
|
||||||
if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
|
if(state == RFAL_NFC_STATE_POLL_ACTIVATION) {
|
||||||
start = DWT->CYCCNT;
|
start = DWT->CYCCNT;
|
||||||
@@ -91,16 +94,42 @@ bool furi_hal_nfc_detect(
|
|||||||
if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
|
if(DWT->CYCCNT - start > timeout * clocks_in_ms) {
|
||||||
rfalNfcDeactivate(true);
|
rfalNfcDeactivate(true);
|
||||||
FURI_LOG_T(TAG, "Timeout");
|
FURI_LOG_T(TAG, "Timeout");
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
osThreadYield();
|
osThreadYield();
|
||||||
}
|
}
|
||||||
rfalNfcGetDevicesFound(dev_list, dev_cnt);
|
rfalNfcGetDevicesFound(&dev_list, &dev_cnt);
|
||||||
if(deactivate) {
|
if(detected) {
|
||||||
rfalNfcDeactivate(false);
|
if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) {
|
||||||
rfalLowPowerModeStart();
|
nfc_data->type = FuriHalNfcTypeA;
|
||||||
|
nfc_data->atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo;
|
||||||
|
nfc_data->atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo;
|
||||||
|
nfc_data->sak = dev_list[0].dev.nfca.selRes.sak;
|
||||||
|
uint8_t* cuid_start = dev_list[0].nfcid;
|
||||||
|
if(dev_list[0].nfcidLen == 7) {
|
||||||
|
cuid_start = &dev_list[0].nfcid[3];
|
||||||
}
|
}
|
||||||
return true;
|
nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) |
|
||||||
|
(cuid_start[3]);
|
||||||
|
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) {
|
||||||
|
nfc_data->type = FuriHalNfcTypeB;
|
||||||
|
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) {
|
||||||
|
nfc_data->type = FuriHalNfcTypeF;
|
||||||
|
} else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) {
|
||||||
|
nfc_data->type = FuriHalNfcTypeV;
|
||||||
|
}
|
||||||
|
if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_RF) {
|
||||||
|
nfc_data->interface = FuriHalNfcInterfaceRf;
|
||||||
|
} else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) {
|
||||||
|
nfc_data->interface = FuriHalNfcInterfaceIsoDep;
|
||||||
|
} else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_NFCDEP) {
|
||||||
|
nfc_data->interface = FuriHalNfcInterfaceNfcDep;
|
||||||
|
}
|
||||||
|
nfc_data->uid_len = dev_list[0].nfcidLen;
|
||||||
|
memcpy(nfc_data->uid, dev_list[0].nfcid, nfc_data->uid_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return detected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
|
bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) {
|
||||||
@@ -326,12 +355,6 @@ bool furi_hal_nfc_emulate_nfca(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) {
|
|
||||||
ReturnCode ret =
|
|
||||||
rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT);
|
|
||||||
return ret == ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnCode furi_hal_nfc_data_exchange(
|
ReturnCode furi_hal_nfc_data_exchange(
|
||||||
uint8_t* tx_buff,
|
uint8_t* tx_buff,
|
||||||
uint16_t tx_len,
|
uint16_t tx_len,
|
||||||
@@ -370,6 +393,22 @@ ReturnCode furi_hal_nfc_data_exchange(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) {
|
||||||
|
uint32_t flags = 0;
|
||||||
|
|
||||||
|
if(type == FuriHalNfcTxRxTypeRxNoCrc) {
|
||||||
|
flags = RFAL_TXRX_FLAGS_CRC_RX_KEEP;
|
||||||
|
} else if(type == FuriHalNfcTxRxTypeRxKeepPar) {
|
||||||
|
flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
|
||||||
|
RFAL_TXRX_FLAGS_PAR_RX_KEEP;
|
||||||
|
} else if(type == FuriHalNfcTxRxTypeRaw) {
|
||||||
|
flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP |
|
||||||
|
RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t furi_hal_nfc_data_and_parity_to_bitstream(
|
static uint16_t furi_hal_nfc_data_and_parity_to_bitstream(
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint16_t len,
|
uint16_t len,
|
||||||
@@ -420,8 +459,8 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity(
|
|||||||
return curr_byte;
|
return curr_byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
|
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) {
|
||||||
furi_assert(tx_rx_ctx);
|
furi_assert(tx_rx);
|
||||||
|
|
||||||
ReturnCode ret;
|
ReturnCode ret;
|
||||||
rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
|
rfalNfcState state = RFAL_NFC_STATE_ACTIVATED;
|
||||||
@@ -431,26 +470,18 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
|
|||||||
uint16_t* temp_rx_bits = NULL;
|
uint16_t* temp_rx_bits = NULL;
|
||||||
|
|
||||||
// Prepare data for FIFO if necessary
|
// Prepare data for FIFO if necessary
|
||||||
if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
|
uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type);
|
||||||
|
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
|
||||||
temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream(
|
temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream(
|
||||||
tx_rx_ctx->tx_data, tx_rx_ctx->tx_bits / 8, tx_rx_ctx->tx_parity, temp_tx_buff);
|
tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity, temp_tx_buff);
|
||||||
ret = rfalNfcDataExchangeCustomStart(
|
ret = rfalNfcDataExchangeCustomStart(
|
||||||
temp_tx_buff,
|
temp_tx_buff, temp_tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
|
||||||
temp_tx_bits,
|
|
||||||
&temp_rx_buff,
|
|
||||||
&temp_rx_bits,
|
|
||||||
RFAL_FWT_NONE,
|
|
||||||
tx_rx_ctx->tx_rx_type);
|
|
||||||
} else {
|
} else {
|
||||||
ret = rfalNfcDataExchangeCustomStart(
|
ret = rfalNfcDataExchangeCustomStart(
|
||||||
tx_rx_ctx->tx_data,
|
tx_rx->tx_data, tx_rx->tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags);
|
||||||
tx_rx_ctx->tx_bits,
|
|
||||||
&temp_rx_buff,
|
|
||||||
&temp_rx_bits,
|
|
||||||
RFAL_FWT_NONE,
|
|
||||||
tx_rx_ctx->tx_rx_type);
|
|
||||||
}
|
}
|
||||||
if(ret != ERR_NONE) {
|
if(ret != ERR_NONE) {
|
||||||
|
FURI_LOG_E(TAG, "Failed to start data exchange");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint32_t start = DWT->CYCCNT;
|
uint32_t start = DWT->CYCCNT;
|
||||||
@@ -459,28 +490,64 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) {
|
|||||||
state = rfalNfcGetState();
|
state = rfalNfcGetState();
|
||||||
ret = rfalNfcDataExchangeGetStatus();
|
ret = rfalNfcDataExchangeGetStatus();
|
||||||
if(ret == ERR_BUSY) {
|
if(ret == ERR_BUSY) {
|
||||||
if(DWT->CYCCNT - start > 4 * clocks_in_ms) {
|
if(DWT->CYCCNT - start > timeout_ms * clocks_in_ms) {
|
||||||
|
FURI_LOG_D(TAG, "Timeout during data exchange");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
start = DWT->CYCCNT;
|
start = DWT->CYCCNT;
|
||||||
}
|
}
|
||||||
taskYIELD();
|
osThreadYield();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) {
|
if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) {
|
||||||
tx_rx_ctx->rx_bits =
|
tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity(
|
||||||
8 * furi_hal_nfc_bitstream_to_data_and_parity(
|
temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity);
|
||||||
temp_rx_buff, *temp_rx_bits, tx_rx_ctx->rx_data, tx_rx_ctx->rx_parity);
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(tx_rx_ctx->rx_data, temp_rx_buff, *temp_rx_bits / 8);
|
memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURI_HAL_NFC_DATA_BUFF_SIZE));
|
||||||
|
tx_rx->rx_bits = *temp_rx_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_nfc_deactivate() {
|
ReturnCode furi_hal_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_bits;
|
||||||
|
uint16_t part_len_bytes;
|
||||||
|
|
||||||
|
err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false);
|
||||||
|
part_len_bytes = *part_len_bits / 8;
|
||||||
|
if(part_len_bytes > rx_cap) {
|
||||||
|
return ERR_OVERRUN;
|
||||||
|
}
|
||||||
|
memcpy(rx_buff, part_buff, part_len_bytes);
|
||||||
|
*rx_len = part_len_bytes;
|
||||||
|
while(err == ERR_NONE && rx_buff[0] == 0xAF) {
|
||||||
|
err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false);
|
||||||
|
part_len_bytes = *part_len_bits / 8;
|
||||||
|
if(part_len_bytes > rx_cap - *rx_len) {
|
||||||
|
return ERR_OVERRUN;
|
||||||
|
}
|
||||||
|
if(part_len_bytes == 0) {
|
||||||
|
return ERR_PROTO;
|
||||||
|
}
|
||||||
|
memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1);
|
||||||
|
*rx_buff = *part_buff;
|
||||||
|
*rx_len += part_len_bytes - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_hal_nfc_sleep() {
|
||||||
rfalNfcDeactivate(false);
|
rfalNfcDeactivate(false);
|
||||||
rfalLowPowerModeStart();
|
rfalLowPowerModeStart();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,32 +15,31 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FURI_HAL_NFC_UID_MAX_LEN 10
|
#define FURI_HAL_NFC_UID_MAX_LEN 10
|
||||||
#define FURI_HAL_NFC_DATA_BUFF_SIZE (64)
|
#define FURI_HAL_NFC_DATA_BUFF_SIZE (256)
|
||||||
#define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
|
#define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8)
|
||||||
|
|
||||||
#define FURI_HAL_NFC_TXRX_DEFAULT \
|
#define FURI_HAL_NFC_TXRX_DEFAULT \
|
||||||
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
|
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
|
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
|
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
|
|
||||||
|
|
||||||
#define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC \
|
#define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC \
|
||||||
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
|
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
|
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
|
|
||||||
|
|
||||||
#define FURI_HAL_NFC_TXRX_WITH_PAR \
|
#define FURI_HAL_NFC_TXRX_WITH_PAR \
|
||||||
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
|
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO)
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \
|
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
|
|
||||||
|
|
||||||
#define FURI_HAL_NFC_TXRX_RAW \
|
#define FURI_HAL_NFC_TXRX_RAW \
|
||||||
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \
|
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE)
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE | \
|
|
||||||
(uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
|
typedef enum {
|
||||||
|
FuriHalNfcTxRxTypeDefault,
|
||||||
|
FuriHalNfcTxRxTypeRxNoCrc,
|
||||||
|
FuriHalNfcTxRxTypeRxKeepPar,
|
||||||
|
FuriHalNfcTxRxTypeRaw,
|
||||||
|
} FuriHalNfcTxRxType;
|
||||||
|
|
||||||
typedef bool (*FuriHalNfcEmulateCallback)(
|
typedef bool (*FuriHalNfcEmulateCallback)(
|
||||||
uint8_t* buff_rx,
|
uint8_t* buff_rx,
|
||||||
@@ -50,6 +49,29 @@ typedef bool (*FuriHalNfcEmulateCallback)(
|
|||||||
uint32_t* flags,
|
uint32_t* flags,
|
||||||
void* context);
|
void* context);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalNfcTypeA,
|
||||||
|
FuriHalNfcTypeB,
|
||||||
|
FuriHalNfcTypeF,
|
||||||
|
FuriHalNfcTypeV,
|
||||||
|
} FuriHalNfcType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FuriHalNfcInterfaceRf,
|
||||||
|
FuriHalNfcInterfaceIsoDep,
|
||||||
|
FuriHalNfcInterfaceNfcDep,
|
||||||
|
} FuriHalNfcInterface;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuriHalNfcType type;
|
||||||
|
FuriHalNfcInterface interface;
|
||||||
|
uint8_t uid_len;
|
||||||
|
uint8_t uid[10];
|
||||||
|
uint32_t cuid;
|
||||||
|
uint8_t atqa[2];
|
||||||
|
uint8_t sak;
|
||||||
|
} FuriHalNfcDevData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
|
uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
|
||||||
uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
|
uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
|
||||||
@@ -57,7 +79,7 @@ typedef struct {
|
|||||||
uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
|
uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE];
|
||||||
uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
|
uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE];
|
||||||
uint16_t rx_bits;
|
uint16_t rx_bits;
|
||||||
uint32_t tx_rx_type;
|
FuriHalNfcTxRxType tx_rx_type;
|
||||||
} FuriHalNfcTxRxContext;
|
} FuriHalNfcTxRxContext;
|
||||||
|
|
||||||
/** Init nfc
|
/** Init nfc
|
||||||
@@ -95,11 +117,7 @@ void furi_hal_nfc_exit_sleep();
|
|||||||
*
|
*
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool furi_hal_nfc_detect(
|
bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout);
|
||||||
rfalNfcDevice** dev_list,
|
|
||||||
uint8_t* dev_cnt,
|
|
||||||
uint32_t timeout,
|
|
||||||
bool deactivate);
|
|
||||||
|
|
||||||
/** Activate NFC-A tag
|
/** Activate NFC-A tag
|
||||||
*
|
*
|
||||||
@@ -138,15 +156,6 @@ bool furi_hal_nfc_emulate_nfca(
|
|||||||
void* context,
|
void* context,
|
||||||
uint32_t timeout);
|
uint32_t timeout);
|
||||||
|
|
||||||
/** Get first command from reader after activation in emulation mode
|
|
||||||
*
|
|
||||||
* @param rx_buff pointer to receive buffer
|
|
||||||
* @param rx_len receive buffer length
|
|
||||||
*
|
|
||||||
* @return true on success
|
|
||||||
*/
|
|
||||||
bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len);
|
|
||||||
|
|
||||||
/** NFC data exchange
|
/** NFC data exchange
|
||||||
*
|
*
|
||||||
* @param tx_buff transmit buffer
|
* @param tx_buff transmit buffer
|
||||||
@@ -170,11 +179,28 @@ ReturnCode furi_hal_nfc_data_exchange(
|
|||||||
*
|
*
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx);
|
bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms);
|
||||||
|
|
||||||
|
/** NFC data full exhange
|
||||||
|
*
|
||||||
|
* @param tx_buff transmit buffer
|
||||||
|
* @param tx_len transmit buffer length
|
||||||
|
* @param rx_buff receive buffer
|
||||||
|
* @param rx_cap receive buffer capacity
|
||||||
|
* @param rx_len receive buffer length
|
||||||
|
*
|
||||||
|
* @return ST ReturnCode
|
||||||
|
*/
|
||||||
|
ReturnCode furi_hal_nfc_exchange_full(
|
||||||
|
uint8_t* tx_buff,
|
||||||
|
uint16_t tx_len,
|
||||||
|
uint8_t* rx_buff,
|
||||||
|
uint16_t rx_cap,
|
||||||
|
uint16_t* rx_len);
|
||||||
|
|
||||||
/** NFC deactivate and start sleep
|
/** NFC deactivate and start sleep
|
||||||
*/
|
*/
|
||||||
void furi_hal_nfc_deactivate();
|
void furi_hal_nfc_sleep();
|
||||||
|
|
||||||
void furi_hal_nfc_stop();
|
void furi_hal_nfc_stop();
|
||||||
|
|
||||||
|
|||||||
@@ -3015,7 +3015,7 @@ ReturnCode rfalIsoDepGetApduTransceiveStatus(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update output param rxLen */
|
/* Update output param rxLen */
|
||||||
*gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos;
|
*gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos * 8;
|
||||||
|
|
||||||
/* Wait for following I-Block or APDU TxRx has finished */
|
/* Wait for following I-Block or APDU TxRx has finished */
|
||||||
return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);
|
return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE);
|
||||||
|
|||||||
@@ -725,9 +725,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
|
|||||||
{
|
{
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_INTERFACE_RF:
|
case RFAL_NFC_INTERFACE_RF:
|
||||||
ctx.rxBuf = gNfcDev.rxBuf.rfBuf, ctx.rxBufLen = sizeof(gNfcDev.rxBuf.rfBuf),
|
ctx.rxBuf = gNfcDev.rxBuf.rfBuf;
|
||||||
ctx.rxRcvdLen = &gNfcDev.rxLen, ctx.txBuf = txData, ctx.txBufLen = txDataLen,
|
ctx.rxBufLen = 8 * sizeof(gNfcDev.rxBuf.rfBuf);
|
||||||
ctx.flags = flags, ctx.fwt = fwt, *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
|
ctx.rxRcvdLen = &gNfcDev.rxLen;
|
||||||
|
ctx.txBuf = txData;
|
||||||
|
ctx.txBufLen = txDataLen;
|
||||||
|
ctx.flags = flags;
|
||||||
|
ctx.fwt = fwt;
|
||||||
|
*rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf;
|
||||||
*rvdLen = (uint16_t*)&gNfcDev.rxLen;
|
*rvdLen = (uint16_t*)&gNfcDev.rxLen;
|
||||||
err = rfalStartTransceive(&ctx);
|
err = rfalStartTransceive(&ctx);
|
||||||
break;
|
break;
|
||||||
@@ -736,13 +741,14 @@ ReturnCode rfalNfcDataExchangeCustomStart(
|
|||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
case RFAL_NFC_INTERFACE_ISODEP: {
|
case RFAL_NFC_INTERFACE_ISODEP: {
|
||||||
rfalIsoDepApduTxRxParam isoDepTxRx;
|
rfalIsoDepApduTxRxParam isoDepTxRx;
|
||||||
|
uint16_t tx_bytes = txDataLen / 8;
|
||||||
|
|
||||||
if(txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
|
if(tx_bytes > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) {
|
||||||
return ERR_NOMEM;
|
return ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(txDataLen > 0U) {
|
if(tx_bytes > 0U) {
|
||||||
ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen);
|
ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, tx_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
|
isoDepTxRx.DID = RFAL_ISODEP_NO_DID;
|
||||||
@@ -751,7 +757,7 @@ ReturnCode rfalNfcDataExchangeCustomStart(
|
|||||||
isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
|
isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT;
|
||||||
isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
|
isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT;
|
||||||
isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
|
isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf;
|
||||||
isoDepTxRx.txBufLen = txDataLen;
|
isoDepTxRx.txBufLen = tx_bytes;
|
||||||
isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
|
isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf;
|
||||||
isoDepTxRx.rxLen = &gNfcDev.rxLen;
|
isoDepTxRx.rxLen = &gNfcDev.rxLen;
|
||||||
isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;
|
isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf;
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
#include "emv_decoder.h"
|
#include "emv.h"
|
||||||
|
|
||||||
|
#include <furi/common_defines.h>
|
||||||
|
|
||||||
|
#define TAG "Emv"
|
||||||
|
|
||||||
const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information
|
const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information
|
||||||
const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type
|
const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type
|
||||||
@@ -69,19 +73,6 @@ static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_prepare_select_ppse(uint8_t* dest) {
|
|
||||||
const uint8_t emv_select_ppse[] = {
|
|
||||||
0x00, 0xA4, // SELECT ppse
|
|
||||||
0x04, 0x00, // P1:By name, P2: empty
|
|
||||||
0x0e, // Lc: Data length
|
|
||||||
0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
|
|
||||||
0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
|
|
||||||
0x00 // Le
|
|
||||||
};
|
|
||||||
memcpy(dest, emv_select_ppse, sizeof(emv_select_ppse));
|
|
||||||
return sizeof(emv_select_ppse);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
bool app_aid_found = false;
|
bool app_aid_found = false;
|
||||||
@@ -89,7 +80,7 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
|
|||||||
while(i < len) {
|
while(i < len) {
|
||||||
if(buff[i] == EMV_TAG_APP_TEMPLATE) {
|
if(buff[i] == EMV_TAG_APP_TEMPLATE) {
|
||||||
uint8_t app_len = buff[++i];
|
uint8_t app_len = buff[++i];
|
||||||
for(uint16_t j = i; j < i + app_len; j++) {
|
for(uint16_t j = i; j < MIN(i + app_len, len - 1); j++) {
|
||||||
if(buff[j] == EMV_TAG_AID) {
|
if(buff[j] == EMV_TAG_AID) {
|
||||||
app_aid_found = true;
|
app_aid_found = true;
|
||||||
app->aid_len = buff[j + 1];
|
app->aid_len = buff[j + 1];
|
||||||
@@ -105,7 +96,59 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app)
|
|||||||
return app_aid_found;
|
return app_aid_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) {
|
bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||||
|
bool app_aid_found = false;
|
||||||
|
const uint8_t emv_select_ppse_cmd[] = {
|
||||||
|
0x00, 0xA4, // SELECT ppse
|
||||||
|
0x04, 0x00, // P1:By name, P2: empty
|
||||||
|
0x0e, // Lc: Data length
|
||||||
|
0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
|
||||||
|
0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
|
||||||
|
0x00 // Le
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(tx_rx->tx_data, emv_select_ppse_cmd, sizeof(emv_select_ppse_cmd));
|
||||||
|
tx_rx->tx_bits = sizeof(emv_select_ppse_cmd) * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Send select PPSE");
|
||||||
|
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||||
|
if(emv_decode_ppse_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
|
||||||
|
app_aid_found = true;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to parse application");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed select PPSE");
|
||||||
|
}
|
||||||
|
|
||||||
|
return app_aid_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
||||||
|
uint16_t i = 0;
|
||||||
|
bool decode_success = false;
|
||||||
|
|
||||||
|
while(i < len) {
|
||||||
|
if(buff[i] == EMV_TAG_CARD_NAME) {
|
||||||
|
uint8_t name_len = buff[i + 1];
|
||||||
|
emv_parse_TLV((uint8_t*)app->name, buff, &i);
|
||||||
|
app->name[name_len] = '\0';
|
||||||
|
app->name_found = true;
|
||||||
|
decode_success = true;
|
||||||
|
} else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
|
||||||
|
i++;
|
||||||
|
app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
|
||||||
|
decode_success = true;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decode_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||||
|
bool select_app_success = false;
|
||||||
const uint8_t emv_select_header[] = {
|
const uint8_t emv_select_header[] = {
|
||||||
0x00,
|
0x00,
|
||||||
0xA4, // SELECT application
|
0xA4, // SELECT application
|
||||||
@@ -113,33 +156,29 @@ uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) {
|
|||||||
0x00 // P1:By name, P2:First or only occurence
|
0x00 // P1:By name, P2:First or only occurence
|
||||||
};
|
};
|
||||||
uint16_t size = sizeof(emv_select_header);
|
uint16_t size = sizeof(emv_select_header);
|
||||||
|
|
||||||
// Copy header
|
// Copy header
|
||||||
memcpy(dest, emv_select_header, size);
|
memcpy(tx_rx->tx_data, emv_select_header, size);
|
||||||
// Copy AID
|
// Copy AID
|
||||||
dest[size++] = app->aid_len;
|
tx_rx->tx_data[size++] = app->aid_len;
|
||||||
memcpy(&dest[size], app->aid, app->aid_len);
|
memcpy(&tx_rx->tx_data[size], app->aid, app->aid_len);
|
||||||
size += app->aid_len;
|
size += app->aid_len;
|
||||||
dest[size++] = 0;
|
tx_rx->tx_data[size++] = 0x00;
|
||||||
return size;
|
tx_rx->tx_bits = size * 8;
|
||||||
}
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
|
||||||
bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
FURI_LOG_D(TAG, "Start application");
|
||||||
uint16_t i = 0;
|
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||||
bool found_name = false;
|
if(emv_decode_select_app_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
|
||||||
|
select_app_success = true;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to read PAN or PDOL");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to start application");
|
||||||
|
}
|
||||||
|
|
||||||
while(i < len) {
|
return select_app_success;
|
||||||
if(buff[i] == EMV_TAG_CARD_NAME) {
|
|
||||||
uint8_t name_len = buff[i + 1];
|
|
||||||
emv_parse_TLV((uint8_t*)app->name, buff, &i);
|
|
||||||
app->name[name_len] = '\0';
|
|
||||||
found_name = true;
|
|
||||||
} else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) {
|
|
||||||
i++;
|
|
||||||
app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return found_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
|
static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
|
||||||
@@ -175,53 +214,56 @@ static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) {
|
|||||||
return dest->size;
|
return dest->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app) {
|
static bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
||||||
// Get processing option header
|
bool card_num_read = false;
|
||||||
const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
|
|
||||||
uint16_t size = sizeof(emv_gpo_header);
|
|
||||||
// Copy header
|
|
||||||
memcpy(dest, emv_gpo_header, size);
|
|
||||||
APDU pdol_data = {0, {0}};
|
|
||||||
// Prepare and copy pdol parameters
|
|
||||||
emv_prepare_pdol(&pdol_data, &app->pdol);
|
|
||||||
dest[size++] = 0x02 + pdol_data.size;
|
|
||||||
dest[size++] = 0x83;
|
|
||||||
dest[size++] = pdol_data.size;
|
|
||||||
memcpy(dest + size, pdol_data.data, pdol_data.size);
|
|
||||||
size += pdol_data.size;
|
|
||||||
dest[size++] = 0;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
|
||||||
for(uint16_t i = 0; i < len; i++) {
|
for(uint16_t i = 0; i < len; i++) {
|
||||||
if(buff[i] == EMV_TAG_CARD_NUM) {
|
if(buff[i] == EMV_TAG_CARD_NUM) {
|
||||||
app->card_number_len = 8;
|
app->card_number_len = 8;
|
||||||
memcpy(app->card_number, &buff[i + 2], app->card_number_len);
|
memcpy(app->card_number, &buff[i + 2], app->card_number_len);
|
||||||
return true;
|
card_num_read = true;
|
||||||
} else if(buff[i] == EMV_TAG_AFL) {
|
} else if(buff[i] == EMV_TAG_AFL) {
|
||||||
app->afl.size = emv_parse_TLV(app->afl.data, buff, &i);
|
app->afl.size = emv_parse_TLV(app->afl.data, buff, &i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return card_num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num) {
|
static bool emv_get_processing_options(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||||
const uint8_t sfi_param = (sfi << 3) | (1 << 2);
|
bool card_num_read = false;
|
||||||
const uint8_t emv_sfi_header[] = {
|
const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00};
|
||||||
0x00,
|
uint16_t size = sizeof(emv_gpo_header);
|
||||||
0xB2, // READ RECORD
|
|
||||||
record_num,
|
// Copy header
|
||||||
sfi_param, // P1:record_number and P2:SFI
|
memcpy(tx_rx->tx_data, emv_gpo_header, size);
|
||||||
0x00 // Le
|
APDU pdol_data = {0, {0}};
|
||||||
};
|
// Prepare and copy pdol parameters
|
||||||
uint16_t size = sizeof(emv_sfi_header);
|
emv_prepare_pdol(&pdol_data, &app->pdol);
|
||||||
memcpy(dest, emv_sfi_header, size);
|
tx_rx->tx_data[size++] = 0x02 + pdol_data.size;
|
||||||
return size;
|
tx_rx->tx_data[size++] = 0x83;
|
||||||
|
tx_rx->tx_data[size++] = pdol_data.size;
|
||||||
|
memcpy(tx_rx->tx_data + size, pdol_data.data, pdol_data.size);
|
||||||
|
size += pdol_data.size;
|
||||||
|
tx_rx->tx_data[size++] = 0;
|
||||||
|
tx_rx->tx_bits = size * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Get proccessing options");
|
||||||
|
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||||
|
if(emv_decode_get_proc_opt(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
|
||||||
|
card_num_read = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to get processing options");
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
static bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) {
|
||||||
bool pan_parsed = false;
|
bool pan_parsed = false;
|
||||||
|
|
||||||
for(uint16_t i = 0; i < len; i++) {
|
for(uint16_t i = 0; i < len; i++) {
|
||||||
if(buff[i] == EMV_TAG_PAN) {
|
if(buff[i] == EMV_TAG_PAN) {
|
||||||
if(buff[i + 1] == 8 || buff[i + 1] == 10) {
|
if(buff[i + 1] == 8 || buff[i + 1] == 10) {
|
||||||
@@ -240,20 +282,118 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app
|
|||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pan_parsed;
|
return pan_parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_select_ppse_ans(uint8_t* buff) {
|
static bool emv_read_sfi_record(
|
||||||
memcpy(buff, select_ppse_ans, sizeof(select_ppse_ans));
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
return sizeof(select_ppse_ans);
|
EmvApplication* app,
|
||||||
|
uint8_t sfi,
|
||||||
|
uint8_t record_num) {
|
||||||
|
bool card_num_read = false;
|
||||||
|
uint8_t sfi_param = (sfi << 3) | (1 << 2);
|
||||||
|
uint8_t emv_sfi_header[] = {
|
||||||
|
0x00,
|
||||||
|
0xB2, // READ RECORD
|
||||||
|
record_num, // P1:record_number
|
||||||
|
sfi_param, // P2:SFI
|
||||||
|
0x00 // Le
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(tx_rx->tx_data, emv_sfi_header, sizeof(emv_sfi_header));
|
||||||
|
tx_rx->tx_bits = sizeof(emv_sfi_header) * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
|
||||||
|
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||||
|
if(emv_decode_read_sfi_record(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) {
|
||||||
|
card_num_read = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_select_app_ans(uint8_t* buff) {
|
static bool emv_read_files(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) {
|
||||||
memcpy(buff, select_app_ans, sizeof(select_app_ans));
|
bool card_num_read = false;
|
||||||
return sizeof(select_app_ans);
|
|
||||||
|
if(app->afl.size == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Search PAN in SFI");
|
||||||
|
// Iterate through all files
|
||||||
|
for(size_t i = 0; i < app->afl.size; i += 4) {
|
||||||
|
uint8_t sfi = app->afl.data[i] >> 3;
|
||||||
|
uint8_t record_start = app->afl.data[i + 1];
|
||||||
|
uint8_t record_end = app->afl.data[i + 2];
|
||||||
|
// Iterate through all records in file
|
||||||
|
for(uint8_t record = record_start; record <= record_end; ++record) {
|
||||||
|
card_num_read |= emv_read_sfi_record(tx_rx, app, sfi, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_num_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t emv_get_proc_opt_ans(uint8_t* buff) {
|
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
|
||||||
memcpy(buff, pdol_ans, sizeof(pdol_ans));
|
furi_assert(tx_rx);
|
||||||
return sizeof(pdol_ans);
|
furi_assert(emv_app);
|
||||||
|
memset(emv_app, 0, sizeof(EmvApplication));
|
||||||
|
|
||||||
|
return emv_select_ppse(tx_rx, emv_app);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(emv_app);
|
||||||
|
bool card_num_read = false;
|
||||||
|
memset(emv_app, 0, sizeof(EmvApplication));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!emv_select_ppse(tx_rx, emv_app)) break;
|
||||||
|
if(!emv_select_app(tx_rx, emv_app)) break;
|
||||||
|
if(emv_get_processing_options(tx_rx, emv_app)) {
|
||||||
|
card_num_read = true;
|
||||||
|
} else {
|
||||||
|
card_num_read = emv_read_files(tx_rx, emv_app);
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return card_num_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
bool emulation_complete = false;
|
||||||
|
memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext));
|
||||||
|
|
||||||
|
do {
|
||||||
|
FURI_LOG_D(TAG, "Read select PPSE command");
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
|
||||||
|
|
||||||
|
memcpy(tx_rx->tx_data, select_ppse_ans, sizeof(select_ppse_ans));
|
||||||
|
tx_rx->tx_bits = sizeof(select_ppse_ans) * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
FURI_LOG_D(TAG, "Send select PPSE answer and read select App command");
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
|
||||||
|
|
||||||
|
memcpy(tx_rx->tx_data, select_app_ans, sizeof(select_app_ans));
|
||||||
|
tx_rx->tx_bits = sizeof(select_app_ans) * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
FURI_LOG_D(TAG, "Send select App answer and read get PDOL command");
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
|
||||||
|
|
||||||
|
memcpy(tx_rx->tx_data, pdol_ans, sizeof(pdol_ans));
|
||||||
|
tx_rx->tx_bits = sizeof(pdol_ans) * 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
FURI_LOG_D(TAG, "Send get PDOL answer");
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
|
||||||
|
|
||||||
|
emulation_complete = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return emulation_complete;
|
||||||
}
|
}
|
||||||
87
lib/nfc_protocols/emv.h
Executable file
87
lib/nfc_protocols/emv.h
Executable file
@@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
|
||||||
|
#define MAX_APDU_LEN 255
|
||||||
|
|
||||||
|
#define EMV_TAG_APP_TEMPLATE 0x61
|
||||||
|
#define EMV_TAG_AID 0x4F
|
||||||
|
#define EMV_TAG_PRIORITY 0x87
|
||||||
|
#define EMV_TAG_PDOL 0x9F38
|
||||||
|
#define EMV_TAG_CARD_NAME 0x50
|
||||||
|
#define EMV_TAG_FCI 0xBF0C
|
||||||
|
#define EMV_TAG_LOG_CTRL 0x9F4D
|
||||||
|
#define EMV_TAG_CARD_NUM 0x57
|
||||||
|
#define EMV_TAG_PAN 0x5A
|
||||||
|
#define EMV_TAG_AFL 0x94
|
||||||
|
#define EMV_TAG_EXP_DATE 0x5F24
|
||||||
|
#define EMV_TAG_COUNTRY_CODE 0x5F28
|
||||||
|
#define EMV_TAG_CURRENCY_CODE 0x9F42
|
||||||
|
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
|
||||||
|
|
||||||
|
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;
|
||||||
|
} EmvData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t tag;
|
||||||
|
uint8_t data[];
|
||||||
|
} PDOLValue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t size;
|
||||||
|
uint8_t data[MAX_APDU_LEN];
|
||||||
|
} APDU;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t priority;
|
||||||
|
uint8_t aid[16];
|
||||||
|
uint8_t aid_len;
|
||||||
|
char name[32];
|
||||||
|
bool name_found;
|
||||||
|
uint8_t card_number[10];
|
||||||
|
uint8_t card_number_len;
|
||||||
|
uint8_t exp_month;
|
||||||
|
uint8_t exp_year;
|
||||||
|
uint16_t country_code;
|
||||||
|
uint16_t currency_code;
|
||||||
|
APDU pdol;
|
||||||
|
APDU afl;
|
||||||
|
} EmvApplication;
|
||||||
|
|
||||||
|
/** Read bank card data
|
||||||
|
* @note Search EMV Application, start it, try to read AID, PAN, card name,
|
||||||
|
* expiration date, currency and country codes
|
||||||
|
*
|
||||||
|
* @param tx_rx FuriHalNfcTxRxContext instance
|
||||||
|
* @param emv_app EmvApplication instance
|
||||||
|
*
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
|
||||||
|
|
||||||
|
/** Search for EMV Application
|
||||||
|
*
|
||||||
|
* @param tx_rx FuriHalNfcTxRxContext instance
|
||||||
|
* @param emv_app EmvApplication instance
|
||||||
|
*
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app);
|
||||||
|
|
||||||
|
/** Emulate bank card
|
||||||
|
* @note Answer to application selection and PDOL
|
||||||
|
*
|
||||||
|
* @param tx_rx FuriHalNfcTxRxContext instance
|
||||||
|
*
|
||||||
|
* @return true on success
|
||||||
|
*/
|
||||||
|
bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx);
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define MAX_APDU_LEN 255
|
|
||||||
|
|
||||||
#define EMV_TAG_APP_TEMPLATE 0x61
|
|
||||||
#define EMV_TAG_AID 0x4F
|
|
||||||
#define EMV_TAG_PRIORITY 0x87
|
|
||||||
#define EMV_TAG_PDOL 0x9F38
|
|
||||||
#define EMV_TAG_CARD_NAME 0x50
|
|
||||||
#define EMV_TAG_FCI 0xBF0C
|
|
||||||
#define EMV_TAG_LOG_CTRL 0x9F4D
|
|
||||||
#define EMV_TAG_CARD_NUM 0x57
|
|
||||||
#define EMV_TAG_PAN 0x5A
|
|
||||||
#define EMV_TAG_AFL 0x94
|
|
||||||
#define EMV_TAG_EXP_DATE 0x5F24
|
|
||||||
#define EMV_TAG_COUNTRY_CODE 0x5F28
|
|
||||||
#define EMV_TAG_CURRENCY_CODE 0x9F42
|
|
||||||
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t tag;
|
|
||||||
uint8_t data[];
|
|
||||||
} PDOLValue;
|
|
||||||
|
|
||||||
extern const PDOLValue* const pdol_values[];
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t size;
|
|
||||||
uint8_t data[MAX_APDU_LEN];
|
|
||||||
} APDU;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t priority;
|
|
||||||
uint8_t aid[16];
|
|
||||||
uint8_t aid_len;
|
|
||||||
char name[32];
|
|
||||||
uint8_t card_number[10];
|
|
||||||
uint8_t card_number_len;
|
|
||||||
uint8_t exp_month;
|
|
||||||
uint8_t exp_year;
|
|
||||||
uint16_t country_code;
|
|
||||||
uint16_t currency_code;
|
|
||||||
APDU pdol;
|
|
||||||
APDU afl;
|
|
||||||
} EmvApplication;
|
|
||||||
|
|
||||||
/* Terminal emulation */
|
|
||||||
uint16_t emv_prepare_select_ppse(uint8_t* dest);
|
|
||||||
bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app);
|
|
||||||
|
|
||||||
uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app);
|
|
||||||
bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app);
|
|
||||||
|
|
||||||
uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app);
|
|
||||||
bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app);
|
|
||||||
|
|
||||||
uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num);
|
|
||||||
bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app);
|
|
||||||
|
|
||||||
/* Card emulation */
|
|
||||||
uint16_t emv_select_ppse_ans(uint8_t* buff);
|
|
||||||
uint16_t emv_select_app_ans(uint8_t* buff);
|
|
||||||
uint16_t emv_get_proc_opt_ans(uint8_t* buff);
|
|
||||||
@@ -116,17 +116,15 @@ static bool mf_classic_auth(
|
|||||||
tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
|
tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD;
|
||||||
}
|
}
|
||||||
tx_rx->tx_data[1] = block;
|
tx_rx->tx_data[1] = block;
|
||||||
tx_rx->tx_rx_type = FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC;
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc;
|
||||||
tx_rx->tx_bits = 2 * 8;
|
tx_rx->tx_bits = 2 * 8;
|
||||||
if(!furi_hal_nfc_tx_rx(tx_rx)) break;
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
|
||||||
|
|
||||||
uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
|
uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4);
|
||||||
crypto1_init(crypto, key);
|
crypto1_init(crypto, key);
|
||||||
crypto1_word(crypto, nt ^ cuid, 0);
|
crypto1_word(crypto, nt ^ cuid, 0);
|
||||||
uint8_t nr[4] = {};
|
uint8_t nr[4] = {};
|
||||||
// uint8_t parity = 0;
|
|
||||||
nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
|
nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr);
|
||||||
// uint8_t nr_ar[8] = {};
|
|
||||||
for(uint8_t i = 0; i < 4; i++) {
|
for(uint8_t i = 0; i < 4; i++) {
|
||||||
tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
|
tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i];
|
||||||
tx_rx->tx_parity[0] |=
|
tx_rx->tx_parity[0] |=
|
||||||
@@ -140,9 +138,9 @@ static bool mf_classic_auth(
|
|||||||
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
|
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01)
|
||||||
<< (7 - i));
|
<< (7 - i));
|
||||||
}
|
}
|
||||||
tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
|
||||||
tx_rx->tx_bits = 8 * 8;
|
tx_rx->tx_bits = 8 * 8;
|
||||||
if(!furi_hal_nfc_tx_rx(tx_rx)) break;
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) break;
|
||||||
if(tx_rx->rx_bits == 32) {
|
if(tx_rx->rx_bits == 32) {
|
||||||
crypto1_word(crypto, 0, 0);
|
crypto1_word(crypto, 0, 0);
|
||||||
auth_success = true;
|
auth_success = true;
|
||||||
@@ -178,7 +176,7 @@ bool mf_classic_auth_attempt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(need_halt) {
|
if(need_halt) {
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
|
furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,9 +218,9 @@ bool mf_classic_read_block(
|
|||||||
((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
|
((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i);
|
||||||
}
|
}
|
||||||
tx_rx->tx_bits = 4 * 9;
|
tx_rx->tx_bits = 4 * 9;
|
||||||
tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW;
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw;
|
||||||
|
|
||||||
if(furi_hal_nfc_tx_rx(tx_rx)) {
|
if(furi_hal_nfc_tx_rx(tx_rx, 4)) {
|
||||||
if(tx_rx->rx_bits == 8 * 18) {
|
if(tx_rx->rx_bits == 8 * 18) {
|
||||||
for(uint8_t i = 0; i < 18; i++) {
|
for(uint8_t i = 0; i < 18; i++) {
|
||||||
block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
|
block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i];
|
||||||
@@ -248,7 +246,7 @@ bool mf_classic_read_sector(
|
|||||||
uint8_t first_block;
|
uint8_t first_block;
|
||||||
bool sector_read = false;
|
bool sector_read = false;
|
||||||
|
|
||||||
furi_hal_nfc_deactivate();
|
furi_hal_nfc_sleep();
|
||||||
do {
|
do {
|
||||||
// Activate card
|
// Activate card
|
||||||
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
|
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
|
||||||
|
|||||||
17
lib/nfc_protocols/mifare_common.c
Normal file
17
lib/nfc_protocols/mifare_common.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "mifare_common.h"
|
||||||
|
|
||||||
|
MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
||||||
|
MifareType type = MifareTypeUnknown;
|
||||||
|
|
||||||
|
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
||||||
|
type = MifareTypeUltralight;
|
||||||
|
} else if(
|
||||||
|
((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08)) ||
|
||||||
|
((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18))) {
|
||||||
|
type = MifareTypeClassic;
|
||||||
|
} else if(ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20) {
|
||||||
|
type = MifareTypeDesfire;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
12
lib/nfc_protocols/mifare_common.h
Normal file
12
lib/nfc_protocols/mifare_common.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MifareTypeUnknown,
|
||||||
|
MifareTypeUltralight,
|
||||||
|
MifareTypeClassic,
|
||||||
|
MifareTypeDesfire,
|
||||||
|
} MifareType;
|
||||||
|
|
||||||
|
MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "mifare_ultralight.h"
|
#include "mifare_ultralight.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal_nfc.h>
|
|
||||||
|
#define TAG "MfUltralight"
|
||||||
|
|
||||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
||||||
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
||||||
@@ -9,187 +10,204 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_get_version(uint8_t* dest) {
|
static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) {
|
||||||
dest[0] = MF_UL_GET_VERSION_CMD;
|
data->type = MfUltralightTypeUnknown;
|
||||||
return 1;
|
reader->pages_to_read = 16;
|
||||||
|
reader->support_fast_read = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
|
bool mf_ultralight_read_version(
|
||||||
MfUltralightVersion* version = (MfUltralightVersion*)buff;
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion));
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data) {
|
||||||
|
bool version_read = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
FURI_LOG_D(TAG, "Reading version");
|
||||||
|
tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD;
|
||||||
|
tx_rx->tx_bits = 8;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
|
||||||
|
FURI_LOG_D(TAG, "Failed reading version");
|
||||||
|
mf_ul_set_default_version(reader, data);
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
furi_hal_nfc_activate_nfca(300, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MfUltralightVersion* version = (MfUltralightVersion*)tx_rx->rx_data;
|
||||||
|
data->version = *version;
|
||||||
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
|
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
|
||||||
mf_ul_read->data.type = MfUltralightTypeUL11;
|
data->type = MfUltralightTypeUL11;
|
||||||
mf_ul_read->pages_to_read = 20;
|
reader->pages_to_read = 20;
|
||||||
mf_ul_read->support_fast_read = true;
|
reader->support_fast_read = true;
|
||||||
} else if(version->storage_size == 0x0E) {
|
} else if(version->storage_size == 0x0E) {
|
||||||
mf_ul_read->data.type = MfUltralightTypeUL21;
|
data->type = MfUltralightTypeUL21;
|
||||||
mf_ul_read->pages_to_read = 41;
|
reader->pages_to_read = 41;
|
||||||
mf_ul_read->support_fast_read = true;
|
reader->support_fast_read = true;
|
||||||
} else if(version->storage_size == 0x0F) {
|
} else if(version->storage_size == 0x0F) {
|
||||||
mf_ul_read->data.type = MfUltralightTypeNTAG213;
|
data->type = MfUltralightTypeNTAG213;
|
||||||
mf_ul_read->pages_to_read = 45;
|
reader->pages_to_read = 45;
|
||||||
mf_ul_read->support_fast_read = false;
|
reader->support_fast_read = false;
|
||||||
} else if(version->storage_size == 0x11) {
|
} else if(version->storage_size == 0x11) {
|
||||||
mf_ul_read->data.type = MfUltralightTypeNTAG215;
|
data->type = MfUltralightTypeNTAG215;
|
||||||
mf_ul_read->pages_to_read = 135;
|
reader->pages_to_read = 135;
|
||||||
mf_ul_read->support_fast_read = false;
|
reader->support_fast_read = false;
|
||||||
} else if(version->storage_size == 0x13) {
|
} else if(version->storage_size == 0x13) {
|
||||||
mf_ul_read->data.type = MfUltralightTypeNTAG216;
|
data->type = MfUltralightTypeNTAG216;
|
||||||
mf_ul_read->pages_to_read = 231;
|
reader->pages_to_read = 231;
|
||||||
mf_ul_read->support_fast_read = false;
|
reader->support_fast_read = false;
|
||||||
} else {
|
} else {
|
||||||
mf_ul_set_default_version(mf_ul_read);
|
mf_ul_set_default_version(reader, data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
version_read = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return version_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) {
|
bool mf_ultralight_read_pages(
|
||||||
mf_ul_read->data.type = MfUltralightTypeUnknown;
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
mf_ul_read->pages_to_read = 16;
|
MfUltralightReader* reader,
|
||||||
mf_ul_read->support_fast_read = false;
|
MfUltralightData* data) {
|
||||||
}
|
uint8_t pages_read_cnt = 0;
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) {
|
for(size_t i = 0; i < reader->pages_to_read; i += 4) {
|
||||||
dest[0] = MF_UL_READ_CMD;
|
FURI_LOG_D(TAG, "Reading pages %d - %d", i, i + 3);
|
||||||
dest[1] = start_page;
|
tx_rx->tx_data[0] = MF_UL_READ_CMD;
|
||||||
return 2;
|
tx_rx->tx_data[1] = i;
|
||||||
}
|
tx_rx->tx_bits = 16;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) {
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
|
||||||
uint8_t pages_read = 4;
|
FURI_LOG_D(TAG, "Failed to read pages %d - %d", i, i + 3);
|
||||||
uint8_t page_read_count = mf_ul_read->pages_read + pages_read;
|
break;
|
||||||
if(page_read_count > mf_ul_read->pages_to_read) {
|
|
||||||
pages_read -= page_read_count - mf_ul_read->pages_to_read;
|
|
||||||
}
|
}
|
||||||
mf_ul_read->pages_read += pages_read;
|
if(i + 4 <= reader->pages_to_read) {
|
||||||
mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
|
pages_read_cnt = 4;
|
||||||
memcpy(&mf_ul_read->data.data[page_addr * 4], buff, pages_read * 4);
|
} else {
|
||||||
}
|
pages_read_cnt = reader->pages_to_read - reader->pages_read;
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) {
|
|
||||||
dest[0] = MF_UL_FAST_READ_CMD;
|
|
||||||
dest[1] = start_page;
|
|
||||||
dest[2] = end_page;
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mf_ul_parse_fast_read_response(
|
|
||||||
uint8_t* buff,
|
|
||||||
uint8_t start_page,
|
|
||||||
uint8_t end_page,
|
|
||||||
MifareUlDevice* mf_ul_read) {
|
|
||||||
mf_ul_read->pages_read = end_page - start_page + 1;
|
|
||||||
mf_ul_read->data.data_size = mf_ul_read->pages_read * 4;
|
|
||||||
memcpy(mf_ul_read->data.data, buff, mf_ul_read->data.data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read_signature(uint8_t* dest) {
|
|
||||||
dest[0] = MF_UL_READ_SIG;
|
|
||||||
dest[1] = 0;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read) {
|
|
||||||
memcpy(mf_ul_read->data.signature, buff, sizeof(mf_ul_read->data.signature));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index) {
|
|
||||||
if(cnt_index > 2) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
dest[0] = MF_UL_READ_CNT;
|
reader->pages_read += pages_read_cnt;
|
||||||
dest[1] = cnt_index;
|
data->data_size = reader->pages_read * 4;
|
||||||
return 2;
|
memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4);
|
||||||
}
|
|
||||||
|
|
||||||
void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) {
|
|
||||||
// Reverse LSB sequence
|
|
||||||
if(cnt_index < 3) {
|
|
||||||
mf_ul_read->data.counter[cnt_index] = (buff[2] << 16) | (buff[1] << 8) | (buff[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value) {
|
|
||||||
if(cnt_index > 2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dest[0] = MF_UL_INC_CNT;
|
|
||||||
dest[1] = cnt_index;
|
|
||||||
dest[2] = (uint8_t)value;
|
|
||||||
dest[3] = (uint8_t)(value >> 8);
|
|
||||||
dest[4] = (uint8_t)(value >> 16);
|
|
||||||
dest[5] = 0;
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index) {
|
|
||||||
if(cnt_index > 2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dest[0] = MF_UL_CHECK_TEARING;
|
|
||||||
dest[1] = cnt_index;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mf_ul_parse_check_tearing_response(
|
|
||||||
uint8_t* buff,
|
|
||||||
uint8_t cnt_index,
|
|
||||||
MifareUlDevice* mf_ul_read) {
|
|
||||||
if(cnt_index < 2) {
|
|
||||||
mf_ul_read->data.tearing[cnt_index] = buff[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) {
|
|
||||||
if(page_addr < 2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dest[0] = MF_UL_WRITE;
|
|
||||||
dest[1] = page_addr;
|
|
||||||
dest[2] = (uint8_t)(data >> 24);
|
|
||||||
dest[3] = (uint8_t)(data >> 16);
|
|
||||||
dest[4] = (uint8_t)(data >> 8);
|
|
||||||
dest[5] = (uint8_t)data;
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) {
|
|
||||||
mf_ul_emulate->data = *data;
|
|
||||||
mf_ul_emulate->auth_data = NULL;
|
|
||||||
mf_ul_emulate->data_changed = false;
|
|
||||||
mf_ul_emulate->comp_write_cmd_started = false;
|
|
||||||
if(data->version.storage_size == 0) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeUnknown;
|
|
||||||
mf_ul_emulate->support_fast_read = false;
|
|
||||||
} else if(data->version.storage_size == 0x0B) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeUL11;
|
|
||||||
mf_ul_emulate->support_fast_read = true;
|
|
||||||
} else if(data->version.storage_size == 0x0E) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeUL21;
|
|
||||||
mf_ul_emulate->support_fast_read = true;
|
|
||||||
} else if(data->version.storage_size == 0x0F) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeNTAG213;
|
|
||||||
mf_ul_emulate->support_fast_read = true;
|
|
||||||
} else if(data->version.storage_size == 0x11) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeNTAG215;
|
|
||||||
mf_ul_emulate->support_fast_read = true;
|
|
||||||
} else if(data->version.storage_size == 0x13) {
|
|
||||||
mf_ul_emulate->data.type = MfUltralightTypeNTAG216;
|
|
||||||
mf_ul_emulate->support_fast_read = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
|
return reader->pages_read == reader->pages_to_read;
|
||||||
uint16_t pwd_page = (data->data_size / 4) - 2;
|
|
||||||
mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mf_ul_protect_auth_data_on_read_command(
|
bool mf_ultralight_fast_read_pages(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data) {
|
||||||
|
FURI_LOG_D(TAG, "Reading pages 0 - %d", reader->pages_to_read);
|
||||||
|
tx_rx->tx_data[0] = MF_UL_FAST_READ_CMD;
|
||||||
|
tx_rx->tx_data[1] = 0;
|
||||||
|
tx_rx->tx_data[2] = reader->pages_to_read - 1;
|
||||||
|
tx_rx->tx_bits = 24;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
if(furi_hal_nfc_tx_rx(tx_rx, 20)) {
|
||||||
|
reader->pages_read = reader->pages_to_read;
|
||||||
|
data->data_size = reader->pages_read * 4;
|
||||||
|
memcpy(data->data, tx_rx->rx_data, data->data_size);
|
||||||
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "Failed to read pages 0 - %d", reader->pages_to_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader->pages_read == reader->pages_to_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
|
||||||
|
bool signature_read = false;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Reading signature");
|
||||||
|
tx_rx->tx_data[0] = MF_UL_READ_SIG;
|
||||||
|
tx_rx->tx_data[1] = 0;
|
||||||
|
tx_rx->tx_bits = 16;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
if(furi_hal_nfc_tx_rx(tx_rx, 7)) {
|
||||||
|
memcpy(data->signature, tx_rx->rx_data, sizeof(data->signature));
|
||||||
|
signature_read = true;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "Failed redaing signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
|
||||||
|
uint8_t counter_read = 0;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Reading counters");
|
||||||
|
for(size_t i = 0; i < 3; i++) {
|
||||||
|
tx_rx->tx_data[0] = MF_UL_READ_CNT;
|
||||||
|
tx_rx->rx_data[1] = i;
|
||||||
|
tx_rx->tx_bits = 16;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
|
||||||
|
FURI_LOG_D(TAG, "Failed to read %d counter", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data->counter[i] = (tx_rx->rx_data[2] << 16) | (tx_rx->rx_data[1] << 8) |
|
||||||
|
tx_rx->rx_data[0];
|
||||||
|
counter_read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter_read == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
|
||||||
|
uint8_t flag_read = 0;
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Reading tearing flags");
|
||||||
|
for(size_t i = 0; i < 3; i++) {
|
||||||
|
tx_rx->tx_data[0] = MF_UL_CHECK_TEARING;
|
||||||
|
tx_rx->rx_data[1] = i;
|
||||||
|
tx_rx->tx_bits = 16;
|
||||||
|
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||||
|
if(!furi_hal_nfc_tx_rx(tx_rx, 4)) {
|
||||||
|
FURI_LOG_D(TAG, "Failed to read %d tearing flag", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data->tearing[i] = tx_rx->rx_data[0];
|
||||||
|
flag_read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag_read == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_ul_read_card(
|
||||||
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data) {
|
||||||
|
furi_assert(tx_rx);
|
||||||
|
furi_assert(reader);
|
||||||
|
furi_assert(data);
|
||||||
|
|
||||||
|
bool card_read = false;
|
||||||
|
|
||||||
|
// Read Mifare Ultralight version
|
||||||
|
if(mf_ultralight_read_version(tx_rx, reader, data)) {
|
||||||
|
// Read Signature
|
||||||
|
mf_ultralight_read_signature(tx_rx, data);
|
||||||
|
}
|
||||||
|
// Read data blocks
|
||||||
|
if(reader->support_fast_read) {
|
||||||
|
mf_ultralight_read_counters(tx_rx, data);
|
||||||
|
mf_ultralight_read_tearing_flags(tx_rx, data);
|
||||||
|
}
|
||||||
|
card_read = mf_ultralight_read_pages(tx_rx, reader, data);
|
||||||
|
|
||||||
|
return card_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO rework
|
||||||
|
static void mf_ul_protect_auth_data_on_read_command(
|
||||||
uint8_t* tx_buff,
|
uint8_t* tx_buff,
|
||||||
uint8_t start_page,
|
uint8_t start_page,
|
||||||
uint8_t end_page,
|
uint8_t end_page,
|
||||||
MifareUlDevice* mf_ul_emulate) {
|
MfUltralightEmulator* emulator) {
|
||||||
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
|
if(emulator->data.type >= MfUltralightTypeNTAG213) {
|
||||||
uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2;
|
uint8_t pwd_page = (emulator->data.data_size / 4) - 2;
|
||||||
uint8_t pack_page = pwd_page + 1;
|
uint8_t pack_page = pwd_page + 1;
|
||||||
if((start_page <= pwd_page) && (end_page >= pwd_page)) {
|
if((start_page <= pwd_page) && (end_page >= pwd_page)) {
|
||||||
memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4);
|
memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4);
|
||||||
@@ -200,6 +218,31 @@ void mf_ul_protect_auth_data_on_read_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) {
|
||||||
|
emulator->data = *data;
|
||||||
|
emulator->auth_data = NULL;
|
||||||
|
emulator->data_changed = false;
|
||||||
|
emulator->comp_write_cmd_started = false;
|
||||||
|
if(data->type == MfUltralightTypeUnknown) {
|
||||||
|
emulator->support_fast_read = false;
|
||||||
|
} else if(data->type == MfUltralightTypeUL11) {
|
||||||
|
emulator->support_fast_read = true;
|
||||||
|
} else if(data->type == MfUltralightTypeUL21) {
|
||||||
|
emulator->support_fast_read = true;
|
||||||
|
} else if(data->type == MfUltralightTypeNTAG213) {
|
||||||
|
emulator->support_fast_read = false;
|
||||||
|
} else if(data->type == MfUltralightTypeNTAG215) {
|
||||||
|
emulator->support_fast_read = false;
|
||||||
|
} else if(data->type == MfUltralightTypeNTAG216) {
|
||||||
|
emulator->support_fast_read = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->type >= MfUltralightTypeNTAG213) {
|
||||||
|
uint16_t pwd_page = (data->data_size / 4) - 2;
|
||||||
|
emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool mf_ul_prepare_emulation_response(
|
bool mf_ul_prepare_emulation_response(
|
||||||
uint8_t* buff_rx,
|
uint8_t* buff_rx,
|
||||||
uint16_t buff_rx_len,
|
uint16_t buff_rx_len,
|
||||||
@@ -208,30 +251,30 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
uint32_t* data_type,
|
uint32_t* data_type,
|
||||||
void* context) {
|
void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
MifareUlDevice* mf_ul_emulate = context;
|
MfUltralightEmulator* emulator = context;
|
||||||
uint8_t cmd = buff_rx[0];
|
uint8_t cmd = buff_rx[0];
|
||||||
uint16_t page_num = mf_ul_emulate->data.data_size / 4;
|
uint16_t page_num = emulator->data.data_size / 4;
|
||||||
uint16_t tx_bytes = 0;
|
uint16_t tx_bytes = 0;
|
||||||
uint16_t tx_bits = 0;
|
uint16_t tx_bits = 0;
|
||||||
bool command_parsed = false;
|
bool command_parsed = false;
|
||||||
|
|
||||||
// Check composite commands
|
// Check composite commands
|
||||||
if(mf_ul_emulate->comp_write_cmd_started) {
|
if(emulator->comp_write_cmd_started) {
|
||||||
// Compatibility write is the only one composit command
|
// Compatibility write is the only one composit command
|
||||||
if(buff_rx_len == 16) {
|
if(buff_rx_len == 16) {
|
||||||
memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4);
|
memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4);
|
||||||
mf_ul_emulate->data_changed = true;
|
emulator->data_changed = true;
|
||||||
// Send ACK message
|
// Send ACK message
|
||||||
buff_tx[0] = 0x0A;
|
buff_tx[0] = 0x0A;
|
||||||
tx_bits = 4;
|
tx_bits = 4;
|
||||||
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
*data_type = FURI_HAL_NFC_TXRX_RAW;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
mf_ul_emulate->comp_write_cmd_started = false;
|
emulator->comp_write_cmd_started = false;
|
||||||
} else if(cmd == MF_UL_GET_VERSION_CMD) {
|
} else if(cmd == MF_UL_GET_VERSION_CMD) {
|
||||||
if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) {
|
if(emulator->data.type != MfUltralightTypeUnknown) {
|
||||||
tx_bytes = sizeof(mf_ul_emulate->data.version);
|
tx_bytes = sizeof(emulator->data.version);
|
||||||
memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes);
|
memcpy(buff_tx, &emulator->data.version, tx_bytes);
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
@@ -242,28 +285,24 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
if(start_page + 4 > page_num) {
|
if(start_page + 4 > page_num) {
|
||||||
// Handle roll-over mechanism
|
// Handle roll-over mechanism
|
||||||
uint8_t end_pages_num = page_num - start_page;
|
uint8_t end_pages_num = page_num - start_page;
|
||||||
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4);
|
memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4);
|
||||||
memcpy(
|
memcpy(&buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4);
|
||||||
&buff_tx[end_pages_num * 4],
|
|
||||||
mf_ul_emulate->data.data,
|
|
||||||
(4 - end_pages_num) * 4);
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
|
memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
|
||||||
}
|
}
|
||||||
mf_ul_protect_auth_data_on_read_command(
|
mf_ul_protect_auth_data_on_read_command(
|
||||||
buff_tx, start_page, (start_page + 4), mf_ul_emulate);
|
buff_tx, start_page, (start_page + 4), emulator);
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
} else if(cmd == MF_UL_FAST_READ_CMD) {
|
} else if(cmd == MF_UL_FAST_READ_CMD) {
|
||||||
if(mf_ul_emulate->support_fast_read) {
|
if(emulator->support_fast_read) {
|
||||||
uint8_t start_page = buff_rx[1];
|
uint8_t start_page = buff_rx[1];
|
||||||
uint8_t end_page = buff_rx[2];
|
uint8_t end_page = buff_rx[2];
|
||||||
if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) {
|
if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) {
|
||||||
tx_bytes = ((end_page + 1) - start_page) * 4;
|
tx_bytes = ((end_page + 1) - start_page) * 4;
|
||||||
memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
|
memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes);
|
||||||
mf_ul_protect_auth_data_on_read_command(
|
mf_ul_protect_auth_data_on_read_command(buff_tx, start_page, end_page, emulator);
|
||||||
buff_tx, start_page, end_page, mf_ul_emulate);
|
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
@@ -271,8 +310,8 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
} else if(cmd == MF_UL_WRITE) {
|
} else if(cmd == MF_UL_WRITE) {
|
||||||
uint8_t write_page = buff_rx[1];
|
uint8_t write_page = buff_rx[1];
|
||||||
if((write_page > 1) && (write_page < page_num - 2)) {
|
if((write_page > 1) && (write_page < page_num - 2)) {
|
||||||
memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4);
|
memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4);
|
||||||
mf_ul_emulate->data_changed = true;
|
emulator->data_changed = true;
|
||||||
// ACK
|
// ACK
|
||||||
buff_tx[0] = 0x0A;
|
buff_tx[0] = 0x0A;
|
||||||
tx_bits = 4;
|
tx_bits = 4;
|
||||||
@@ -282,8 +321,8 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
} else if(cmd == MF_UL_COMP_WRITE) {
|
} else if(cmd == MF_UL_COMP_WRITE) {
|
||||||
uint8_t write_page = buff_rx[1];
|
uint8_t write_page = buff_rx[1];
|
||||||
if((write_page > 1) && (write_page < page_num - 2)) {
|
if((write_page > 1) && (write_page < page_num - 2)) {
|
||||||
mf_ul_emulate->comp_write_cmd_started = true;
|
emulator->comp_write_cmd_started = true;
|
||||||
mf_ul_emulate->comp_write_page_addr = write_page;
|
emulator->comp_write_page_addr = write_page;
|
||||||
// ACK
|
// ACK
|
||||||
buff_tx[0] = 0x0A;
|
buff_tx[0] = 0x0A;
|
||||||
tx_bits = 4;
|
tx_bits = 4;
|
||||||
@@ -293,9 +332,9 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
} else if(cmd == MF_UL_READ_CNT) {
|
} else if(cmd == MF_UL_READ_CNT) {
|
||||||
uint8_t cnt_num = buff_rx[1];
|
uint8_t cnt_num = buff_rx[1];
|
||||||
if(cnt_num < 3) {
|
if(cnt_num < 3) {
|
||||||
buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16;
|
buff_tx[0] = emulator->data.counter[cnt_num] >> 16;
|
||||||
buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
|
buff_tx[1] = emulator->data.counter[cnt_num] >> 8;
|
||||||
buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
|
buff_tx[2] = emulator->data.counter[cnt_num];
|
||||||
tx_bytes = 3;
|
tx_bytes = 3;
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
@@ -303,9 +342,9 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
} else if(cmd == MF_UL_INC_CNT) {
|
} else if(cmd == MF_UL_INC_CNT) {
|
||||||
uint8_t cnt_num = buff_rx[1];
|
uint8_t cnt_num = buff_rx[1];
|
||||||
uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
|
uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16));
|
||||||
if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
|
if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) {
|
||||||
mf_ul_emulate->data.counter[cnt_num] += inc;
|
emulator->data.counter[cnt_num] += inc;
|
||||||
mf_ul_emulate->data_changed = true;
|
emulator->data_changed = true;
|
||||||
// ACK
|
// ACK
|
||||||
buff_tx[0] = 0x0A;
|
buff_tx[0] = 0x0A;
|
||||||
tx_bits = 4;
|
tx_bits = 4;
|
||||||
@@ -313,14 +352,14 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
} else if(cmd == MF_UL_AUTH) {
|
} else if(cmd == MF_UL_AUTH) {
|
||||||
if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) {
|
if(emulator->data.type >= MfUltralightTypeNTAG213) {
|
||||||
if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) {
|
if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) {
|
||||||
buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0];
|
buff_tx[0] = emulator->auth_data->pack.raw[0];
|
||||||
buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1];
|
buff_tx[1] = emulator->auth_data->pack.raw[1];
|
||||||
tx_bytes = 2;
|
tx_bytes = 2;
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
} else if(!mf_ul_emulate->auth_data->pack.value) {
|
} else if(!emulator->auth_data->pack.value) {
|
||||||
buff_tx[0] = 0x80;
|
buff_tx[0] = 0x80;
|
||||||
buff_tx[1] = 0x80;
|
buff_tx[1] = 0x80;
|
||||||
tx_bytes = 2;
|
tx_bytes = 2;
|
||||||
@@ -331,15 +370,15 @@ bool mf_ul_prepare_emulation_response(
|
|||||||
} else if(cmd == MF_UL_READ_SIG) {
|
} else if(cmd == MF_UL_READ_SIG) {
|
||||||
// Check 2nd byte = 0x00 - RFU
|
// Check 2nd byte = 0x00 - RFU
|
||||||
if(buff_rx[1] == 0x00) {
|
if(buff_rx[1] == 0x00) {
|
||||||
tx_bytes = sizeof(mf_ul_emulate->data.signature);
|
tx_bytes = sizeof(emulator->data.signature);
|
||||||
memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes);
|
memcpy(buff_tx, emulator->data.signature, tx_bytes);
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
}
|
}
|
||||||
} else if(cmd == MF_UL_CHECK_TEARING) {
|
} else if(cmd == MF_UL_CHECK_TEARING) {
|
||||||
uint8_t cnt_num = buff_rx[1];
|
uint8_t cnt_num = buff_rx[1];
|
||||||
if(cnt_num < 3) {
|
if(cnt_num < 3) {
|
||||||
buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
|
buff_tx[0] = emulator->data.tearing[cnt_num];
|
||||||
tx_bytes = 1;
|
tx_bytes = 1;
|
||||||
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
*data_type = FURI_HAL_NFC_TXRX_DEFAULT;
|
||||||
command_parsed = true;
|
command_parsed = true;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <furi_hal_nfc.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define MF_UL_MAX_DUMP_SIZE 1024
|
#define MF_UL_MAX_DUMP_SIZE 1024
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ typedef struct {
|
|||||||
uint8_t tearing[3];
|
uint8_t tearing[3];
|
||||||
uint16_t data_size;
|
uint16_t data_size;
|
||||||
uint8_t data[MF_UL_MAX_DUMP_SIZE];
|
uint8_t data[MF_UL_MAX_DUMP_SIZE];
|
||||||
} MifareUlData;
|
} MfUltralightData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pwd[4];
|
uint8_t pwd[4];
|
||||||
@@ -70,52 +68,53 @@ typedef struct {
|
|||||||
uint8_t raw[2];
|
uint8_t raw[2];
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
} pack;
|
} pack;
|
||||||
} MifareUlAuthData;
|
} MfUltralightAuth;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pages_to_read;
|
uint8_t pages_to_read;
|
||||||
uint8_t pages_read;
|
uint8_t pages_read;
|
||||||
bool support_fast_read;
|
bool support_fast_read;
|
||||||
|
} MfUltralightReader;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MfUltralightData data;
|
||||||
|
bool support_fast_read;
|
||||||
bool data_changed;
|
bool data_changed;
|
||||||
MifareUlData data;
|
|
||||||
MifareUlAuthData* auth_data;
|
|
||||||
bool comp_write_cmd_started;
|
bool comp_write_cmd_started;
|
||||||
uint8_t comp_write_page_addr;
|
uint8_t comp_write_page_addr;
|
||||||
} MifareUlDevice;
|
MfUltralightAuth* auth_data;
|
||||||
|
} MfUltralightEmulator;
|
||||||
|
|
||||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
|
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_get_version(uint8_t* dest);
|
bool mf_ultralight_read_version(
|
||||||
void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
void mf_ul_set_default_version(MifareUlDevice* mf_ul_read);
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data);
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read_signature(uint8_t* dest);
|
bool mf_ultralight_read_pages(
|
||||||
void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read);
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data);
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index);
|
bool mf_ultralight_fast_read_pages(
|
||||||
void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read);
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
|
MfUltralightReader* reader,
|
||||||
|
MfUltralightData* data);
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value);
|
bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index);
|
bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
|
||||||
void mf_ul_parse_check_tearing_response(
|
|
||||||
uint8_t* buff,
|
|
||||||
uint8_t cnt_index,
|
|
||||||
MifareUlDevice* mf_ul_read);
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page);
|
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
|
||||||
void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read);
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page);
|
bool mf_ul_read_card(
|
||||||
void mf_ul_parse_fast_read_response(
|
FuriHalNfcTxRxContext* tx_rx,
|
||||||
uint8_t* buff,
|
MfUltralightReader* reader,
|
||||||
uint8_t start_page,
|
MfUltralightData* data);
|
||||||
uint8_t end_page,
|
|
||||||
MifareUlDevice* mf_ul_read);
|
|
||||||
|
|
||||||
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
|
void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data);
|
||||||
|
|
||||||
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
|
|
||||||
bool mf_ul_prepare_emulation_response(
|
bool mf_ul_prepare_emulation_response(
|
||||||
uint8_t* buff_rx,
|
uint8_t* buff_rx,
|
||||||
uint16_t buff_rx_len,
|
uint16_t buff_rx_len,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#define MANIFEST_KEY_RADIO_ADDRESS "Radio address"
|
#define MANIFEST_KEY_RADIO_ADDRESS "Radio address"
|
||||||
#define MANIFEST_KEY_RADIO_VERSION "Radio version"
|
#define MANIFEST_KEY_RADIO_VERSION "Radio version"
|
||||||
#define MANIFEST_KEY_RADIO_CRC "Radio CRC"
|
#define MANIFEST_KEY_RADIO_CRC "Radio CRC"
|
||||||
#define MANIFEST_KEY_ASSETS_FILE "Assets"
|
#define MANIFEST_KEY_ASSETS_FILE "Resources"
|
||||||
|
|
||||||
UpdateManifest* update_manifest_alloc() {
|
UpdateManifest* update_manifest_alloc() {
|
||||||
UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest));
|
UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest));
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ $(OBJ_DIR)/upload: $(OBJ_DIR)/$(PROJECT).bin
|
|||||||
dfu-util -d 0483:df11 -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS)
|
dfu-util -d 0483:df11 -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS)
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
|
||||||
.PHONY: flash
|
.PHONY: flash
|
||||||
flash: $(OBJ_DIR)/flash
|
flash: $(OBJ_DIR)/flash
|
||||||
|
|
||||||
|
|||||||
@@ -203,15 +203,12 @@ class Main(App):
|
|||||||
manifest_file = os.path.join(directory_path, "Manifest")
|
manifest_file = os.path.join(directory_path, "Manifest")
|
||||||
old_manifest = Manifest()
|
old_manifest = Manifest()
|
||||||
if os.path.exists(manifest_file):
|
if os.path.exists(manifest_file):
|
||||||
self.logger.info(
|
self.logger.info("old manifest is present, loading for compare")
|
||||||
f"old manifest is present, loading for compare and removing file"
|
|
||||||
)
|
|
||||||
old_manifest.load(manifest_file)
|
old_manifest.load(manifest_file)
|
||||||
os.unlink(manifest_file)
|
|
||||||
self.logger.info(f'Creating new Manifest for directory "{directory_path}"')
|
self.logger.info(f'Creating new Manifest for directory "{directory_path}"')
|
||||||
new_manifest = Manifest()
|
new_manifest = Manifest()
|
||||||
new_manifest.create(directory_path)
|
new_manifest.create(directory_path)
|
||||||
new_manifest.save(manifest_file)
|
|
||||||
self.logger.info(f"Comparing new manifest with old")
|
self.logger.info(f"Comparing new manifest with old")
|
||||||
only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest)
|
only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest)
|
||||||
for record in only_in_old:
|
for record in only_in_old:
|
||||||
@@ -220,6 +217,12 @@ class Main(App):
|
|||||||
self.logger.info(f"Changed: {record}")
|
self.logger.info(f"Changed: {record}")
|
||||||
for record in only_in_new:
|
for record in only_in_new:
|
||||||
self.logger.info(f"Only in new: {record}")
|
self.logger.info(f"Only in new: {record}")
|
||||||
|
if any((only_in_old, changed, only_in_new)):
|
||||||
|
self.logger.warning("Manifests are different, updating")
|
||||||
|
new_manifest.save(manifest_file)
|
||||||
|
else:
|
||||||
|
self.logger.info("Manifest is up-to-date!")
|
||||||
|
|
||||||
self.logger.info(f"Complete")
|
self.logger.info(f"Complete")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Main(App):
|
|||||||
self.parser_copy.add_argument("-t", dest="target", required=True)
|
self.parser_copy.add_argument("-t", dest="target", required=True)
|
||||||
self.parser_copy.add_argument("-p", dest="projects", nargs="+", required=True)
|
self.parser_copy.add_argument("-p", dest="projects", nargs="+", required=True)
|
||||||
self.parser_copy.add_argument("-s", dest="suffix", required=True)
|
self.parser_copy.add_argument("-s", dest="suffix", required=True)
|
||||||
self.parser_copy.add_argument("-a", dest="assets", required=False)
|
self.parser_copy.add_argument("-r", dest="resources", required=False)
|
||||||
self.parser_copy.add_argument(
|
self.parser_copy.add_argument(
|
||||||
"--bundlever",
|
"--bundlever",
|
||||||
dest="version",
|
dest="version",
|
||||||
@@ -79,16 +79,16 @@ class Main(App):
|
|||||||
self.args.version,
|
self.args.version,
|
||||||
"-t",
|
"-t",
|
||||||
self.args.target,
|
self.args.target,
|
||||||
"-dfu",
|
"--dfu",
|
||||||
self.get_dist_filepath(self.get_project_filename("firmware", "dfu")),
|
self.get_dist_filepath(self.get_project_filename("firmware", "dfu")),
|
||||||
"-stage",
|
"--stage",
|
||||||
self.get_dist_filepath(self.get_project_filename("updater", "bin")),
|
self.get_dist_filepath(self.get_project_filename("updater", "bin")),
|
||||||
]
|
]
|
||||||
if self.args.assets:
|
if self.args.resources:
|
||||||
bundle_args.extend(
|
bundle_args.extend(
|
||||||
(
|
(
|
||||||
"-a",
|
"-r",
|
||||||
self.args.assets,
|
self.args.resources,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import os
|
|||||||
from flipper.app import App
|
from flipper.app import App
|
||||||
from flipper.cube import CubeProgrammer
|
from flipper.cube import CubeProgrammer
|
||||||
|
|
||||||
STATEMENT = "AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE"
|
STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE"
|
||||||
|
|
||||||
|
|
||||||
class Main(App):
|
class Main(App):
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ class ManifestRecord:
|
|||||||
def toLine(self):
|
def toLine(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _unpack(self, manifest, key, type):
|
def _unpack(self, manifest, key, nodetype):
|
||||||
key, value = manifest.readline().split(":", 1)
|
key, value = manifest.readline().split(":", 1)
|
||||||
assert key == key
|
assert key == key
|
||||||
return type(value)
|
return nodetype(value)
|
||||||
|
|
||||||
|
|
||||||
MANIFEST_TAGS_RECORDS = {}
|
MANIFEST_TAGS_RECORDS = {}
|
||||||
@@ -94,7 +94,7 @@ class ManifestRecordFile(ManifestRecord):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def fromLine(line):
|
def fromLine(line):
|
||||||
data = line.split(":", 3)
|
data = line.split(":", 3)
|
||||||
return ManifestRecordFile(data[2], data[0], data[1])
|
return ManifestRecordFile(data[2], data[0], int(data[1]))
|
||||||
|
|
||||||
def toLine(self):
|
def toLine(self):
|
||||||
return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n"
|
return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n"
|
||||||
@@ -133,7 +133,7 @@ class Manifest:
|
|||||||
def addFile(self, path, md5, size):
|
def addFile(self, path, md5, size):
|
||||||
self.records.append(ManifestRecordFile(path, md5, size))
|
self.records.append(ManifestRecordFile(path, md5, size))
|
||||||
|
|
||||||
def create(self, directory_path):
|
def create(self, directory_path, ignore_files=["Manifest"]):
|
||||||
for root, dirs, files in os.walk(directory_path):
|
for root, dirs, files in os.walk(directory_path):
|
||||||
relative_root = root.replace(directory_path, "", 1)
|
relative_root = root.replace(directory_path, "", 1)
|
||||||
if relative_root.startswith("/"):
|
if relative_root.startswith("/"):
|
||||||
@@ -141,13 +141,16 @@ class Manifest:
|
|||||||
# process directories
|
# process directories
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
relative_dir_path = os.path.join(relative_root, dir)
|
relative_dir_path = os.path.join(relative_root, dir)
|
||||||
self.logger.info(f'Adding directory: "{relative_dir_path}"')
|
self.logger.debug(f'Adding directory: "{relative_dir_path}"')
|
||||||
self.addDirectory(relative_dir_path)
|
self.addDirectory(relative_dir_path)
|
||||||
# Process files
|
# Process files
|
||||||
for file in files:
|
for file in files:
|
||||||
relative_file_path = os.path.join(relative_root, file)
|
relative_file_path = os.path.join(relative_root, file)
|
||||||
|
if file in ignore_files:
|
||||||
|
self.logger.info(f'Skipping file "{relative_file_path}"')
|
||||||
|
continue
|
||||||
full_file_path = os.path.join(root, file)
|
full_file_path = os.path.join(root, file)
|
||||||
self.logger.info(f'Adding file: "{relative_file_path}"')
|
self.logger.debug(f'Adding file: "{relative_file_path}"')
|
||||||
self.addFile(
|
self.addFile(
|
||||||
relative_file_path,
|
relative_file_path,
|
||||||
file_md5(full_file_path),
|
file_md5(full_file_path),
|
||||||
@@ -155,7 +158,7 @@ class Manifest:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def toFsTree(self):
|
def toFsTree(self):
|
||||||
root = FsNode("", FsNode.Type.Directory)
|
root = FsNode("", FsNode.NodeType.Directory)
|
||||||
for record in self.records:
|
for record in self.records:
|
||||||
if isinstance(record, ManifestRecordDirectory):
|
if isinstance(record, ManifestRecordDirectory):
|
||||||
root.addDirectory(record.path)
|
root.addDirectory(record.path)
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ from collections import OrderedDict
|
|||||||
|
|
||||||
|
|
||||||
class FsNode:
|
class FsNode:
|
||||||
class Type(Enum):
|
class NodeType(Enum):
|
||||||
File = 0
|
File = 0
|
||||||
Directory = 1
|
Directory = 1
|
||||||
|
|
||||||
def __init__(self, name: str, type: "FsNode.Type", **kwargs):
|
def __init__(self, name: str, nodetype: "FsNode.Type", **kwargs):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = type
|
self.nodetype = nodetype
|
||||||
self.data = kwargs
|
self.data = kwargs
|
||||||
self.parent = None
|
self.parent = None
|
||||||
self.children = OrderedDict()
|
self.children = OrderedDict()
|
||||||
@@ -25,7 +25,7 @@ class FsNode:
|
|||||||
parent_node = self.traverse(fragments)
|
parent_node = self.traverse(fragments)
|
||||||
if not parent_node:
|
if not parent_node:
|
||||||
raise Exception(f"No parent node found for: {path}")
|
raise Exception(f"No parent node found for: {path}")
|
||||||
parent_node.addChild(FsNode(name, FsNode.Type.Directory))
|
parent_node.addChild(FsNode(name, FsNode.NodeType.Directory))
|
||||||
|
|
||||||
def addFile(self, path, md5, size):
|
def addFile(self, path, md5, size):
|
||||||
fragments = path.split("/")
|
fragments = path.split("/")
|
||||||
@@ -34,7 +34,7 @@ class FsNode:
|
|||||||
parent_node = self.traverse(fragments)
|
parent_node = self.traverse(fragments)
|
||||||
if not parent_node:
|
if not parent_node:
|
||||||
raise Exception(f"No parent node found for: {path}")
|
raise Exception(f"No parent node found for: {path}")
|
||||||
parent_node.addChild(FsNode(name, FsNode.Type.File, md5=md5, size=size))
|
parent_node.addChild(FsNode(name, FsNode.NodeType.File, md5=md5, size=size))
|
||||||
|
|
||||||
def getChild(self, name):
|
def getChild(self, name):
|
||||||
return self.children[name]
|
return self.children[name]
|
||||||
@@ -58,19 +58,37 @@ class FsNode:
|
|||||||
def dump(self):
|
def dump(self):
|
||||||
ret = {}
|
ret = {}
|
||||||
ret["name"] = (self.name,)
|
ret["name"] = (self.name,)
|
||||||
ret["type"] = (self.type,)
|
ret["type"] = (self.nodetype,)
|
||||||
ret["path"] = (self.getPath(),)
|
ret["path"] = (self.getPath(),)
|
||||||
if len(self.children):
|
if len(self.children):
|
||||||
ret["children"] = [node.dump() for node in self.children.values()]
|
ret["children"] = [node.dump() for node in self.children.values()]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def walk_nodes(node: FsNode):
|
||||||
|
yield node
|
||||||
|
for child in node.children.values():
|
||||||
|
yield from walk_nodes(child)
|
||||||
|
|
||||||
|
|
||||||
|
# Returns filenames: [only_in_left], [changed], [only_in_right]
|
||||||
def compare_fs_trees(left: FsNode, right: FsNode):
|
def compare_fs_trees(left: FsNode, right: FsNode):
|
||||||
# import pprint
|
# import pprint
|
||||||
# pprint.pprint(left.dump())
|
# pprint.pprint(left.dump())
|
||||||
# pprint.pprint(right.dump())
|
# pprint.pprint(right.dump())
|
||||||
|
left_dict = dict((node.getPath(), node) for node in walk_nodes(left))
|
||||||
|
right_dict = dict((node.getPath(), node) for node in walk_nodes(right))
|
||||||
|
|
||||||
only_in_left = []
|
left_names = set(left_dict.keys())
|
||||||
changed = []
|
right_names = set(right_dict.keys())
|
||||||
only_in_right = []
|
common_names = left_names.intersection(right_names)
|
||||||
return [], [], []
|
|
||||||
|
return (
|
||||||
|
list(left_names - right_names),
|
||||||
|
list(
|
||||||
|
name
|
||||||
|
for name in common_names
|
||||||
|
if left_dict[name].data != right_dict[name].data
|
||||||
|
),
|
||||||
|
list(right_names - left_names),
|
||||||
|
)
|
||||||
|
|||||||
@@ -10,8 +10,12 @@ import tarfile
|
|||||||
|
|
||||||
|
|
||||||
class Main(App):
|
class Main(App):
|
||||||
|
UPDATE_MANIFEST_NAME = "update.fuf"
|
||||||
|
|
||||||
# No compression, plain tar
|
# No compression, plain tar
|
||||||
ASSET_TAR_MODE = "w:"
|
RESOURCE_TAR_MODE = "w:"
|
||||||
|
RESOURCE_TAR_FORMAT = tarfile.USTAR_FORMAT
|
||||||
|
RESOURCE_FILE_NAME = "resources.tar"
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.subparsers = self.parser.add_subparsers(help="sub-command help")
|
self.subparsers = self.parser.add_subparsers(help="sub-command help")
|
||||||
@@ -24,17 +28,17 @@ class Main(App):
|
|||||||
self.parser_generate.add_argument("-d", dest="directory", required=True)
|
self.parser_generate.add_argument("-d", dest="directory", required=True)
|
||||||
self.parser_generate.add_argument("-v", dest="version", required=True)
|
self.parser_generate.add_argument("-v", dest="version", required=True)
|
||||||
self.parser_generate.add_argument("-t", dest="target", required=True)
|
self.parser_generate.add_argument("-t", dest="target", required=True)
|
||||||
self.parser_generate.add_argument("-dfu", dest="dfu", required=False)
|
self.parser_generate.add_argument("--dfu", dest="dfu", required=False)
|
||||||
self.parser_generate.add_argument("-a", dest="assets", required=False)
|
self.parser_generate.add_argument("-r", dest="resources", required=False)
|
||||||
self.parser_generate.add_argument("-stage", dest="stage", required=True)
|
self.parser_generate.add_argument("--stage", dest="stage", required=True)
|
||||||
self.parser_generate.add_argument(
|
self.parser_generate.add_argument(
|
||||||
"-radio", dest="radiobin", default="", required=False
|
"--radio", dest="radiobin", default="", required=False
|
||||||
)
|
)
|
||||||
self.parser_generate.add_argument(
|
self.parser_generate.add_argument(
|
||||||
"-radioaddr", dest="radioaddr", required=False
|
"--radioaddr", dest="radioaddr", required=False
|
||||||
)
|
)
|
||||||
self.parser_generate.add_argument(
|
self.parser_generate.add_argument(
|
||||||
"-radiover", dest="radioversion", required=False
|
"--radiover", dest="radioversion", required=False
|
||||||
)
|
)
|
||||||
|
|
||||||
self.parser_generate.set_defaults(func=self.generate)
|
self.parser_generate.set_defaults(func=self.generate)
|
||||||
@@ -43,7 +47,7 @@ class Main(App):
|
|||||||
stage_basename = basename(self.args.stage)
|
stage_basename = basename(self.args.stage)
|
||||||
dfu_basename = basename(self.args.dfu)
|
dfu_basename = basename(self.args.dfu)
|
||||||
radiobin_basename = basename(self.args.radiobin)
|
radiobin_basename = basename(self.args.radiobin)
|
||||||
assets_basename = ""
|
resources_basename = ""
|
||||||
|
|
||||||
if not exists(self.args.directory):
|
if not exists(self.args.directory):
|
||||||
os.makedirs(self.args.directory)
|
os.makedirs(self.args.directory)
|
||||||
@@ -54,10 +58,10 @@ class Main(App):
|
|||||||
shutil.copyfile(
|
shutil.copyfile(
|
||||||
self.args.radiobin, join(self.args.directory, radiobin_basename)
|
self.args.radiobin, join(self.args.directory, radiobin_basename)
|
||||||
)
|
)
|
||||||
if self.args.assets:
|
if self.args.resources:
|
||||||
assets_basename = "assets.tar"
|
resources_basename = self.RESOURCE_FILE_NAME
|
||||||
self.package_assets(
|
self.package_resources(
|
||||||
self.args.assets, join(self.args.directory, assets_basename)
|
self.args.resources, join(self.args.directory, resources_basename)
|
||||||
)
|
)
|
||||||
|
|
||||||
file = FlipperFormatFile()
|
file = FlipperFormatFile()
|
||||||
@@ -75,14 +79,14 @@ class Main(App):
|
|||||||
file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin)))
|
file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin)))
|
||||||
else:
|
else:
|
||||||
file.writeKey("Radio CRC", self.int2ffhex(0))
|
file.writeKey("Radio CRC", self.int2ffhex(0))
|
||||||
file.writeKey("Assets", assets_basename)
|
file.writeKey("Resources", resources_basename)
|
||||||
file.save(join(self.args.directory, "update.fuf"))
|
file.save(join(self.args.directory, self.UPDATE_MANIFEST_NAME))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def package_assets(self, srcdir: str, dst_name: str):
|
def package_resources(self, srcdir: str, dst_name: str):
|
||||||
with tarfile.open(
|
with tarfile.open(
|
||||||
dst_name, self.ASSET_TAR_MODE, format=tarfile.USTAR_FORMAT
|
dst_name, self.RESOURCE_TAR_MODE, format=self.RESOURCE_TAR_FORMAT
|
||||||
) as tarball:
|
) as tarball:
|
||||||
tarball.add(srcdir, arcname="")
|
tarball.add(srcdir, arcname="")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user