Merge branch 'dev' into release-candidate
This commit is contained in:
		
						commit
						3cdcd644fe
					
				@ -8,7 +8,7 @@ static const char* tab_default_paths[] = {
 | 
			
		||||
    [ArchiveTabFavorites] = "/any/favorites",
 | 
			
		||||
    [ArchiveTabIButton] = "/any/ibutton",
 | 
			
		||||
    [ArchiveTabNFC] = "/any/nfc",
 | 
			
		||||
    [ArchiveTabSubGhz] = "/any/subghz/saved",
 | 
			
		||||
    [ArchiveTabSubGhz] = "/any/subghz",
 | 
			
		||||
    [ArchiveTabLFRFID] = "/any/lfrfid",
 | 
			
		||||
    [ArchiveTabIrda] = "/any/irda",
 | 
			
		||||
    [ArchiveTabBrowser] = "/any",
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#include "bad_usb_app_i.h"
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <furi_hal.h>
 | 
			
		||||
#include <storage/storage.h>
 | 
			
		||||
 | 
			
		||||
static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
@ -20,6 +21,24 @@ static void bad_usb_app_tick_event_callback(void* context) {
 | 
			
		||||
    scene_manager_handle_tick_event(app->scene_manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool bad_usb_check_assets() {
 | 
			
		||||
    Storage* fs_api = furi_record_open("storage");
 | 
			
		||||
 | 
			
		||||
    File* dir = storage_file_alloc(fs_api);
 | 
			
		||||
    bool ret = false;
 | 
			
		||||
 | 
			
		||||
    if(storage_dir_open(dir, BAD_USB_APP_PATH_FOLDER)) {
 | 
			
		||||
        ret = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    storage_dir_close(dir);
 | 
			
		||||
    storage_file_free(dir);
 | 
			
		||||
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BadUsbApp* bad_usb_app_alloc() {
 | 
			
		||||
    BadUsbApp* app = furi_alloc(sizeof(BadUsbApp));
 | 
			
		||||
 | 
			
		||||
@ -41,11 +60,20 @@ BadUsbApp* bad_usb_app_alloc() {
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
 | 
			
		||||
 | 
			
		||||
    // Custom Widget
 | 
			
		||||
    app->widget = widget_alloc();
 | 
			
		||||
    view_dispatcher_add_view(
 | 
			
		||||
        app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));
 | 
			
		||||
 | 
			
		||||
    app->bad_usb_view = bad_usb_alloc();
 | 
			
		||||
    view_dispatcher_add_view(
 | 
			
		||||
        app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view));
 | 
			
		||||
 | 
			
		||||
    scene_manager_next_scene(app->scene_manager, BadUsbAppViewFileSelect);
 | 
			
		||||
    if(bad_usb_check_assets()) {
 | 
			
		||||
        scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect);
 | 
			
		||||
    } else {
 | 
			
		||||
        scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return app;
 | 
			
		||||
}
 | 
			
		||||
@ -58,6 +86,10 @@ void bad_usb_app_free(BadUsbApp* app) {
 | 
			
		||||
    view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
 | 
			
		||||
    bad_usb_free(app->bad_usb_view);
 | 
			
		||||
 | 
			
		||||
    // Custom Widget
 | 
			
		||||
    view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
 | 
			
		||||
    widget_free(app->widget);
 | 
			
		||||
 | 
			
		||||
    // View dispatcher
 | 
			
		||||
    view_dispatcher_free(app->view_dispatcher);
 | 
			
		||||
    scene_manager_free(app->scene_manager);
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@
 | 
			
		||||
#include <dialogs/dialogs.h>
 | 
			
		||||
#include <notification/notification_messages.h>
 | 
			
		||||
#include <gui/modules/variable_item_list.h>
 | 
			
		||||
#include <gui/modules/widget.h>
 | 
			
		||||
#include "views/bad_usb_view.h"
 | 
			
		||||
 | 
			
		||||
#define BAD_USB_APP_PATH_FOLDER "/any/badusb"
 | 
			
		||||
@ -23,6 +24,7 @@ struct BadUsbApp {
 | 
			
		||||
    SceneManager* scene_manager;
 | 
			
		||||
    NotificationApp* notifications;
 | 
			
		||||
    DialogsApp* dialogs;
 | 
			
		||||
    Widget* widget;
 | 
			
		||||
 | 
			
		||||
    char file_name[BAD_USB_FILE_NAME_LEN + 1];
 | 
			
		||||
    BadUsb* bad_usb_view;
 | 
			
		||||
@ -30,6 +32,7 @@ struct BadUsbApp {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    BadUsbAppViewError,
 | 
			
		||||
    BadUsbAppViewFileSelect,
 | 
			
		||||
    BadUsbAppViewWork,
 | 
			
		||||
} BadUsbAppView;
 | 
			
		||||
 | 
			
		||||
@ -159,8 +159,6 @@ static bool ducky_altchar(const char* charcode) {
 | 
			
		||||
    uint8_t i = 0;
 | 
			
		||||
    bool state = false;
 | 
			
		||||
 | 
			
		||||
    //TODO: numlock
 | 
			
		||||
 | 
			
		||||
    FURI_LOG_I(WORKER_TAG, "char %s", charcode);
 | 
			
		||||
 | 
			
		||||
    furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1,3 @@
 | 
			
		||||
ADD_SCENE(bad_usb, file_select, FileSelect)
 | 
			
		||||
ADD_SCENE(bad_usb, work, Work)
 | 
			
		||||
ADD_SCENE(bad_usb, error, Error)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										53
									
								
								applications/bad_usb/scenes/bad_usb_scene_error.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								applications/bad_usb/scenes/bad_usb_scene_error.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#include "../bad_usb_app_i.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SubghzCustomEventErrorBack,
 | 
			
		||||
} BadUsbCustomEvent;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
    bad_usb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    BadUsbApp* app = context;
 | 
			
		||||
 | 
			
		||||
    if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, SubghzCustomEventErrorBack);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bad_usb_scene_error_on_enter(void* context) {
 | 
			
		||||
    BadUsbApp* app = context;
 | 
			
		||||
 | 
			
		||||
    widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
 | 
			
		||||
 | 
			
		||||
    widget_add_string_multiline_element(
 | 
			
		||||
        app->widget,
 | 
			
		||||
        81,
 | 
			
		||||
        4,
 | 
			
		||||
        AlignCenter,
 | 
			
		||||
        AlignTop,
 | 
			
		||||
        FontSecondary,
 | 
			
		||||
        "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
 | 
			
		||||
 | 
			
		||||
    widget_add_button_element(
 | 
			
		||||
        app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app);
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewError);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    BadUsbApp* app = context;
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SubghzCustomEventErrorBack) {
 | 
			
		||||
            view_dispatcher_stop(app->view_dispatcher);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return consumed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bad_usb_scene_error_on_exit(void* context) {
 | 
			
		||||
    BadUsbApp* app = context;
 | 
			
		||||
    widget_reset(app->widget);
 | 
			
		||||
}
 | 
			
		||||
@ -19,7 +19,7 @@ void bad_usb_scene_file_select_on_enter(void* context) {
 | 
			
		||||
    BadUsbApp* bad_usb = context;
 | 
			
		||||
 | 
			
		||||
    if(bad_usb_file_select(bad_usb)) {
 | 
			
		||||
        scene_manager_next_scene(bad_usb->scene_manager, BadUsbAppViewWork);
 | 
			
		||||
        scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
 | 
			
		||||
    } else {
 | 
			
		||||
        //scene_manager_previous_scene(bad_usb->scene_manager);
 | 
			
		||||
        view_dispatcher_stop(bad_usb->view_dispatcher);
 | 
			
		||||
 | 
			
		||||
@ -594,7 +594,6 @@ void elements_text_box(
 | 
			
		||||
            line[line_num].height = line_height;
 | 
			
		||||
            line[line_num].descender = line_descender;
 | 
			
		||||
            if(total_height_min + line_leading_min > height) {
 | 
			
		||||
                line_num--;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            total_height_min += line_leading_min;
 | 
			
		||||
@ -640,7 +639,7 @@ void elements_text_box(
 | 
			
		||||
            uint8_t free_pixel_num = height - total_height_min;
 | 
			
		||||
            uint8_t fill_pixel = 0;
 | 
			
		||||
            uint8_t j = 1;
 | 
			
		||||
            line[0].y = line[0].height;
 | 
			
		||||
            line[0].y = y + line[0].height;
 | 
			
		||||
            while(fill_pixel < free_pixel_num) {
 | 
			
		||||
                line[j].y = line[j - 1].y + line[j - 1].leading_min + 1;
 | 
			
		||||
                fill_pixel++;
 | 
			
		||||
 | 
			
		||||
@ -7,17 +7,16 @@
 | 
			
		||||
 | 
			
		||||
struct TextBox {
 | 
			
		||||
    View* view;
 | 
			
		||||
    void* context;
 | 
			
		||||
    TextBoxExitCallback callback;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char* text;
 | 
			
		||||
    char* text_pos;
 | 
			
		||||
    string_t text_formatted;
 | 
			
		||||
    size_t scroll_pos;
 | 
			
		||||
    size_t scroll_num;
 | 
			
		||||
    int32_t scroll_pos;
 | 
			
		||||
    int32_t scroll_num;
 | 
			
		||||
    TextBoxFont font;
 | 
			
		||||
    TextBoxFocus focus;
 | 
			
		||||
    bool formatted;
 | 
			
		||||
} TextBoxModel;
 | 
			
		||||
 | 
			
		||||
@ -52,12 +51,6 @@ static void text_box_process_up(TextBox* text_box) {
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void text_box_process_back(TextBox* text_box) {
 | 
			
		||||
    if(text_box->callback) {
 | 
			
		||||
        text_box->callback(text_box->context);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    size_t line_width = 0;
 | 
			
		||||
@ -84,8 +77,18 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
 | 
			
		||||
    line_num++;
 | 
			
		||||
    model->text = string_get_cstr(model->text_formatted);
 | 
			
		||||
    model->text_pos = (char*)model->text;
 | 
			
		||||
    if(model->focus == TextBoxFocusEnd && line_num > 5) {
 | 
			
		||||
        // Set text position to 5th line from the end
 | 
			
		||||
        for(uint8_t i = 0; i < line_num - 5; i++) {
 | 
			
		||||
            while(*model->text_pos++ != '\n') {
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        model->scroll_num = line_num - 4;
 | 
			
		||||
        model->scroll_pos = line_num - 5;
 | 
			
		||||
    } else {
 | 
			
		||||
        model->scroll_num = MAX(line_num - 4, 0);
 | 
			
		||||
        model->scroll_pos = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void text_box_view_draw_callback(Canvas* canvas, void* _model) {
 | 
			
		||||
@ -119,9 +122,6 @@ static bool text_box_view_input_callback(InputEvent* event, void* context) {
 | 
			
		||||
        } else if(event->key == InputKeyUp) {
 | 
			
		||||
            text_box_process_up(text_box);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        } else if(event->key == InputKeyBack) {
 | 
			
		||||
            text_box_process_back(text_box);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return consumed;
 | 
			
		||||
@ -172,10 +172,9 @@ void text_box_reset(TextBox* text_box) {
 | 
			
		||||
            model->text = NULL;
 | 
			
		||||
            string_set_str(model->text_formatted, "");
 | 
			
		||||
            model->font = TextBoxFontText;
 | 
			
		||||
            model->focus = TextBoxFocusStart;
 | 
			
		||||
            return true;
 | 
			
		||||
        });
 | 
			
		||||
    text_box->context = NULL;
 | 
			
		||||
    text_box->callback = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void text_box_set_text(TextBox* text_box, const char* text) {
 | 
			
		||||
@ -185,6 +184,7 @@ void text_box_set_text(TextBox* text_box, const char* text) {
 | 
			
		||||
    with_view_model(
 | 
			
		||||
        text_box->view, (TextBoxModel * model) {
 | 
			
		||||
            model->text = text;
 | 
			
		||||
            string_reset(model->text_formatted);
 | 
			
		||||
            string_reserve(model->text_formatted, strlen(text));
 | 
			
		||||
            model->formatted = false;
 | 
			
		||||
            return true;
 | 
			
		||||
@ -201,12 +201,12 @@ void text_box_set_font(TextBox* text_box, TextBoxFont font) {
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void text_box_set_context(TextBox* text_box, void* context) {
 | 
			
		||||
void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) {
 | 
			
		||||
    furi_assert(text_box);
 | 
			
		||||
    text_box->context = context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback) {
 | 
			
		||||
    furi_assert(text_box);
 | 
			
		||||
    text_box->callback = callback;
 | 
			
		||||
    with_view_model(
 | 
			
		||||
        text_box->view, (TextBoxModel * model) {
 | 
			
		||||
            model->focus = focus;
 | 
			
		||||
            return true;
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								applications/gui/modules/text_box.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										20
									
								
								applications/gui/modules/text_box.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -13,13 +13,17 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
/** TextBox anonymous structure */
 | 
			
		||||
typedef struct TextBox TextBox;
 | 
			
		||||
typedef void (*TextBoxExitCallback)(void* context);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    TextBoxFontText,
 | 
			
		||||
    TextBoxFontHex,
 | 
			
		||||
} TextBoxFont;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    TextBoxFocusStart,
 | 
			
		||||
    TextBoxFocusEnd,
 | 
			
		||||
} TextBoxFocus;
 | 
			
		||||
 | 
			
		||||
/** Allocate and initialize text_box
 | 
			
		||||
 *
 | 
			
		||||
 * @return     TextBox instance
 | 
			
		||||
@ -60,19 +64,13 @@ void text_box_set_text(TextBox* text_box, const char* text);
 | 
			
		||||
 */
 | 
			
		||||
void text_box_set_font(TextBox* text_box, TextBoxFont font);
 | 
			
		||||
 | 
			
		||||
/** Set text_box context
 | 
			
		||||
/** Set TextBox focus
 | 
			
		||||
 * @note Use to display from start or from end
 | 
			
		||||
 *
 | 
			
		||||
 * @param      text_box  TextBox instance
 | 
			
		||||
 * @param      context   context pointer
 | 
			
		||||
 * @param      focus     TextBoxFocus instance
 | 
			
		||||
 */
 | 
			
		||||
void text_box_set_context(TextBox* text_box, void* context);
 | 
			
		||||
 | 
			
		||||
/** Set exit callback
 | 
			
		||||
 *
 | 
			
		||||
 * @param      text_box  TextBox instance
 | 
			
		||||
 * @param      callback  TextBoxExitCallback callback pointer
 | 
			
		||||
 */
 | 
			
		||||
void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback);
 | 
			
		||||
void text_box_set_focus(TextBox* text_box, TextBoxFocus focus);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ Widget* widget_alloc() {
 | 
			
		||||
    return widget;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void widget_clear(Widget* widget) {
 | 
			
		||||
void widget_reset(Widget* widget) {
 | 
			
		||||
    furi_assert(widget);
 | 
			
		||||
 | 
			
		||||
    with_view_model(
 | 
			
		||||
@ -89,7 +89,7 @@ void widget_clear(Widget* widget) {
 | 
			
		||||
void widget_free(Widget* widget) {
 | 
			
		||||
    furi_assert(widget);
 | 
			
		||||
    // Free all elements
 | 
			
		||||
    widget_clear(widget);
 | 
			
		||||
    widget_reset(widget);
 | 
			
		||||
    // Free elements container
 | 
			
		||||
    with_view_model(
 | 
			
		||||
        widget->view, (GuiWidgetModel * model) {
 | 
			
		||||
 | 
			
		||||
@ -27,11 +27,11 @@ Widget* widget_alloc();
 | 
			
		||||
 */
 | 
			
		||||
void widget_free(Widget* widget);
 | 
			
		||||
 | 
			
		||||
/** Clear Widget
 | 
			
		||||
/** Reset Widget
 | 
			
		||||
 *
 | 
			
		||||
 * @param      widget  Widget instance
 | 
			
		||||
 */
 | 
			
		||||
void widget_clear(Widget* widget);
 | 
			
		||||
void widget_reset(Widget* widget);
 | 
			
		||||
 | 
			
		||||
/** Get Widget view
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,7 @@ void iButtonSceneDeleteConfirm::on_exit(iButtonApp* app) {
 | 
			
		||||
 | 
			
		||||
    app->set_text_store("");
 | 
			
		||||
 | 
			
		||||
    widget_clear(widget);
 | 
			
		||||
    widget_reset(widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iButtonSceneDeleteConfirm::widget_callback(
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,7 @@ void iButtonSceneInfo::on_exit(iButtonApp* app) {
 | 
			
		||||
 | 
			
		||||
    app->set_text_store("");
 | 
			
		||||
 | 
			
		||||
    widget_clear(widget);
 | 
			
		||||
    widget_reset(widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iButtonSceneInfo::widget_callback(GuiButtonType result, InputType type, void* context) {
 | 
			
		||||
 | 
			
		||||
@ -159,7 +159,7 @@ class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon {
 | 
			
		||||
public:
 | 
			
		||||
    void on_enter(IrdaApp* app) final;
 | 
			
		||||
    IrdaAppSceneUniversalTV()
 | 
			
		||||
        : IrdaAppSceneUniversalCommon("/ext/irda/universal/tv.ir") {
 | 
			
		||||
        : IrdaAppSceneUniversalCommon("/ext/irda/assets/tv.ir") {
 | 
			
		||||
    }
 | 
			
		||||
    ~IrdaAppSceneUniversalTV() {
 | 
			
		||||
    }
 | 
			
		||||
@ -169,7 +169,7 @@ class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon {
 | 
			
		||||
public:
 | 
			
		||||
    void on_enter(IrdaApp* app) final;
 | 
			
		||||
    IrdaAppSceneUniversalAudio()
 | 
			
		||||
        : IrdaAppSceneUniversalCommon("/ext/irda/universal/audio.ir") {
 | 
			
		||||
        : IrdaAppSceneUniversalCommon("/ext/irda/assets/audio.ir") {
 | 
			
		||||
    }
 | 
			
		||||
    ~IrdaAppSceneUniversalAudio() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								applications/nfc/helpers/nfc_custom_event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/nfc/helpers/nfc_custom_event.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
enum NfcCustomEvent {
 | 
			
		||||
    // Reserve first 100 events for button types and indexes, starting from 0
 | 
			
		||||
    NfcCustomEventReserved = 100,
 | 
			
		||||
 | 
			
		||||
    NfcCustomEventViewExit,
 | 
			
		||||
    NfcCustomEventWorkerExit,
 | 
			
		||||
    NfcCustomEventByteInputDone,
 | 
			
		||||
    NfcCustomEventTextInputDone,
 | 
			
		||||
};
 | 
			
		||||
@ -44,7 +44,7 @@ bool nfc_emv_parser_get_aid_name(
 | 
			
		||||
    for(uint8_t i = 0; i < aid_len; i++) {
 | 
			
		||||
        string_cat_printf(key, "%02X", aid[i]);
 | 
			
		||||
    }
 | 
			
		||||
    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/aid.nfc", key, aid_name)) {
 | 
			
		||||
    if(nfc_emv_parser_search_data(storage, "/ext/nfc/assets/aid.nfc", key, aid_name)) {
 | 
			
		||||
        parsed = true;
 | 
			
		||||
    }
 | 
			
		||||
    string_clear(key);
 | 
			
		||||
@ -58,7 +58,7 @@ bool nfc_emv_parser_get_country_name(
 | 
			
		||||
    bool parsed = false;
 | 
			
		||||
    string_t key;
 | 
			
		||||
    string_init_printf(key, "%04X", country_code);
 | 
			
		||||
    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/country_code.nfc", key, country_name)) {
 | 
			
		||||
    if(nfc_emv_parser_search_data(storage, "/ext/nfc/assets/country_code.nfc", key, country_name)) {
 | 
			
		||||
        parsed = true;
 | 
			
		||||
    }
 | 
			
		||||
    string_clear(key);
 | 
			
		||||
@ -72,7 +72,8 @@ bool nfc_emv_parser_get_currency_name(
 | 
			
		||||
    bool parsed = false;
 | 
			
		||||
    string_t key;
 | 
			
		||||
    string_init_printf(key, "%04X", currency_code);
 | 
			
		||||
    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/currency_code.nfc", key, currency_name)) {
 | 
			
		||||
    if(nfc_emv_parser_search_data(
 | 
			
		||||
           storage, "/ext/nfc/assets/currency_code.nfc", key, currency_name)) {
 | 
			
		||||
        parsed = true;
 | 
			
		||||
    }
 | 
			
		||||
    string_clear(key);
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
 | 
			
		||||
#define NFC_DEV_NAME_MAX_LEN 22
 | 
			
		||||
#define NFC_FILE_NAME_MAX_LEN 120
 | 
			
		||||
#define NFC_READER_DATA_MAX_SIZE 64
 | 
			
		||||
 | 
			
		||||
#define NFC_APP_FOLDER "/any/nfc"
 | 
			
		||||
#define NFC_APP_EXTENSION ".nfc"
 | 
			
		||||
@ -54,11 +55,17 @@ typedef struct {
 | 
			
		||||
    uint16_t currency_code;
 | 
			
		||||
} NfcEmvData;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t data[NFC_READER_DATA_MAX_SIZE];
 | 
			
		||||
    uint16_t size;
 | 
			
		||||
} NfcReaderRequestData;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    NfcDeviceCommonData nfc_data;
 | 
			
		||||
    union {
 | 
			
		||||
        NfcEmvData emv_data;
 | 
			
		||||
        MifareUlData mf_ul_data;
 | 
			
		||||
        NfcReaderRequestData reader_data;
 | 
			
		||||
    };
 | 
			
		||||
} NfcDeviceData;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@
 | 
			
		||||
#include "views/bank_card.h"
 | 
			
		||||
 | 
			
		||||
#include <nfc/scenes/nfc_scene.h>
 | 
			
		||||
#include <nfc/helpers/nfc_custom_event.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_SEND_NOTIFICATION_FALSE (0UL)
 | 
			
		||||
#define NFC_SEND_NOTIFICATION_TRUE (1UL)
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ void nfc_worker_stop(NfcWorker* nfc_worker) {
 | 
			
		||||
    if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    furi_hal_nfc_stop();
 | 
			
		||||
    nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -140,13 +140,37 @@ void nfc_worker_detect(NfcWorker* nfc_worker) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nfc_worker_emulate_uid_callback(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    uint16_t* buff_tx_len,
 | 
			
		||||
    uint32_t* data_type,
 | 
			
		||||
    void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    NfcWorker* nfc_worker = context;
 | 
			
		||||
    NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
 | 
			
		||||
    reader_data->size = buff_rx_len / 8;
 | 
			
		||||
    if(reader_data->size > 0) {
 | 
			
		||||
        memcpy(reader_data->data, buff_rx, reader_data->size);
 | 
			
		||||
        if(nfc_worker->callback) {
 | 
			
		||||
            nfc_worker->callback(nfc_worker->context);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_worker_emulate(NfcWorker* nfc_worker) {
 | 
			
		||||
    NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data;
 | 
			
		||||
    while(nfc_worker->state == NfcWorkerStateEmulate) {
 | 
			
		||||
        if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) {
 | 
			
		||||
            FURI_LOG_D(TAG, "Reader detected");
 | 
			
		||||
        }
 | 
			
		||||
        osDelay(10);
 | 
			
		||||
        furi_hal_nfc_emulate_nfca(
 | 
			
		||||
            data->uid,
 | 
			
		||||
            data->uid_len,
 | 
			
		||||
            data->atqa,
 | 
			
		||||
            data->sak,
 | 
			
		||||
            nfc_worker_emulate_uid_callback,
 | 
			
		||||
            nfc_worker,
 | 
			
		||||
            1000);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -603,65 +627,26 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
 | 
			
		||||
    ReturnCode err;
 | 
			
		||||
    uint8_t tx_buff[255] = {};
 | 
			
		||||
    uint16_t tx_len = 0;
 | 
			
		||||
    uint8_t* rx_buff;
 | 
			
		||||
    uint16_t* rx_len;
 | 
			
		||||
    NfcDeviceData* data = nfc_worker->dev_data;
 | 
			
		||||
    NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data;
 | 
			
		||||
    MifareUlDevice mf_ul_emulate;
 | 
			
		||||
    // Setup emulation parameters from mifare ultralight data structure
 | 
			
		||||
    mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data);
 | 
			
		||||
    mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data);
 | 
			
		||||
    while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
 | 
			
		||||
        // WARNING
 | 
			
		||||
        // DO NOT call any blocking functions (e.g. FURI_LOG_*) in this loop,
 | 
			
		||||
        // as any delay will negatively affect the stability of the emulation.
 | 
			
		||||
        if(furi_hal_nfc_listen(
 | 
			
		||||
               data->nfc_data.uid,
 | 
			
		||||
               data->nfc_data.uid_len,
 | 
			
		||||
               data->nfc_data.atqa,
 | 
			
		||||
               data->nfc_data.sak,
 | 
			
		||||
               true,
 | 
			
		||||
               200)) {
 | 
			
		||||
            if(furi_hal_nfc_get_first_frame(&rx_buff, &rx_len)) {
 | 
			
		||||
                // Data exchange loop
 | 
			
		||||
                while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
 | 
			
		||||
                    tx_len = mf_ul_prepare_emulation_response(
 | 
			
		||||
                        rx_buff, *rx_len, tx_buff, &mf_ul_emulate);
 | 
			
		||||
                    if(tx_len > 0) {
 | 
			
		||||
                        if(tx_len < 8) {
 | 
			
		||||
                            err = furi_hal_nfc_raw_bitstream_exchange(
 | 
			
		||||
                                tx_buff, tx_len, &rx_buff, &rx_len, false);
 | 
			
		||||
                            *rx_len /= 8;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            err = furi_hal_nfc_data_exchange(
 | 
			
		||||
                                tx_buff, tx_len / 8, &rx_buff, &rx_len, false);
 | 
			
		||||
                        }
 | 
			
		||||
                        if(err == ERR_NONE) {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            FURI_LOG_D(TAG, "Communication error: %d", err);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        furi_hal_nfc_deactivate();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                FURI_LOG_D(TAG, "Error in 1st data exchange");
 | 
			
		||||
                furi_hal_nfc_deactivate();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        furi_hal_nfc_emulate_nfca(
 | 
			
		||||
            nfc_common->uid,
 | 
			
		||||
            nfc_common->uid_len,
 | 
			
		||||
            nfc_common->atqa,
 | 
			
		||||
            nfc_common->sak,
 | 
			
		||||
            mf_ul_prepare_emulation_response,
 | 
			
		||||
            &mf_ul_emulate,
 | 
			
		||||
            5000);
 | 
			
		||||
        // Check if data was modified
 | 
			
		||||
        if(mf_ul_emulate.data_changed) {
 | 
			
		||||
            nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data;
 | 
			
		||||
            if(nfc_worker->callback) {
 | 
			
		||||
                nfc_worker->callback(nfc_worker->context);
 | 
			
		||||
            }
 | 
			
		||||
            mf_ul_emulate.data_changed = false;
 | 
			
		||||
        }
 | 
			
		||||
        FURI_LOG_D(TAG, "Can't find reader");
 | 
			
		||||
        osThreadYield();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -88,5 +88,5 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
void nfc_scene_delete_on_exit(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    widget_clear(nfc->widget);
 | 
			
		||||
    widget_reset(nfc->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
 | 
			
		||||
#define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_delete_success_popup_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_delete_success_on_enter(void* context) {
 | 
			
		||||
@ -25,7 +23,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventViewExit) {
 | 
			
		||||
            return scene_manager_search_and_switch_to_previous_scene(
 | 
			
		||||
                nfc->scene_manager, NfcSceneStart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,6 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include "../helpers/nfc_emv_parser.h"
 | 
			
		||||
 | 
			
		||||
#define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    NfcSceneDeviceInfoUid,
 | 
			
		||||
    NfcSceneDeviceInfoData,
 | 
			
		||||
@ -17,18 +15,15 @@ void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type,
 | 
			
		||||
 | 
			
		||||
void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) {
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_device_info_text_box_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
 | 
			
		||||
    if(result == DialogExResultLeft) {
 | 
			
		||||
        view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) {
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    if(type == InputTypeShort) {
 | 
			
		||||
        view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
 | 
			
		||||
        view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -97,8 +92,6 @@ void nfc_scene_device_info_on_enter(void* context) {
 | 
			
		||||
    } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
 | 
			
		||||
        MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
 | 
			
		||||
        TextBox* text_box = nfc->text_box;
 | 
			
		||||
        text_box_set_context(text_box, nfc);
 | 
			
		||||
        text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback);
 | 
			
		||||
        text_box_set_font(text_box, TextBoxFontHex);
 | 
			
		||||
        for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
 | 
			
		||||
            if(!(i % 8) && i) {
 | 
			
		||||
@ -170,7 +163,14 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
                view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
 | 
			
		||||
                consumed = true;
 | 
			
		||||
            }
 | 
			
		||||
        } else if(state == NfcSceneDeviceInfoData) {
 | 
			
		||||
        } else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) {
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(event.type == SceneManagerEventTypeBack) {
 | 
			
		||||
        if(state == NfcSceneDeviceInfoData) {
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 | 
			
		||||
@ -184,7 +184,7 @@ void nfc_scene_device_info_on_exit(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    // Clear Custom Widget
 | 
			
		||||
    widget_clear(nfc->widget);
 | 
			
		||||
    widget_reset(nfc->widget);
 | 
			
		||||
 | 
			
		||||
    if(nfc->dev->format == NfcDeviceSaveFormatUid) {
 | 
			
		||||
        // Clear Dialog
 | 
			
		||||
 | 
			
		||||
@ -1,61 +1,139 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    NfcSceneEmulateUidStateWidget,
 | 
			
		||||
    NfcSceneEmulateUidStateTextBox,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void nfc_emulate_uid_worker_callback(void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    if(type == InputTypeShort) {
 | 
			
		||||
        view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_emulate_uid_textbox_callback(void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add widget with device name or inform that data received
 | 
			
		||||
static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
 | 
			
		||||
    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
 | 
			
		||||
    Widget* widget = nfc->widget;
 | 
			
		||||
    widget_reset(widget);
 | 
			
		||||
    string_t info_str;
 | 
			
		||||
    string_init(info_str);
 | 
			
		||||
 | 
			
		||||
    widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
 | 
			
		||||
    widget_add_string_element(widget, 56, 32, AlignLeft, AlignTop, FontPrimary, "Emulating UID");
 | 
			
		||||
    if(strcmp(nfc->dev->dev_name, "")) {
 | 
			
		||||
        string_printf(info_str, "%s", nfc->dev->dev_name);
 | 
			
		||||
    } else {
 | 
			
		||||
        for(uint8_t i = 0; i < data->uid_len; i++) {
 | 
			
		||||
            string_cat_printf(info_str, "%02X ", data->uid[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    string_strim(info_str);
 | 
			
		||||
    widget_add_text_box_element(
 | 
			
		||||
        widget, 56, 43, 70, 21, AlignLeft, AlignTop, string_get_cstr(info_str));
 | 
			
		||||
    string_clear(info_str);
 | 
			
		||||
    if(data_received) {
 | 
			
		||||
        widget_add_button_element(
 | 
			
		||||
            widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_uid_widget_callback, nfc);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_emulate_uid_on_enter(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    DOLPHIN_DEED(DolphinDeedNfcEmulate);
 | 
			
		||||
 | 
			
		||||
    // Setup view
 | 
			
		||||
    Popup* popup = nfc->popup;
 | 
			
		||||
    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
 | 
			
		||||
    // Setup Widget
 | 
			
		||||
    nfc_scene_emulate_uid_widget_config(nfc, false);
 | 
			
		||||
    // Setup TextBox
 | 
			
		||||
    TextBox* text_box = nfc->text_box;
 | 
			
		||||
    text_box_set_font(text_box, TextBoxFontHex);
 | 
			
		||||
    text_box_set_focus(text_box, TextBoxFocusEnd);
 | 
			
		||||
    string_reset(nfc->text_box_store);
 | 
			
		||||
 | 
			
		||||
    if(strcmp(nfc->dev->dev_name, "")) {
 | 
			
		||||
        nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
 | 
			
		||||
    } else if(data->uid_len == 4) {
 | 
			
		||||
        nfc_text_store_set(
 | 
			
		||||
            nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
 | 
			
		||||
    } else if(data->uid_len == 7) {
 | 
			
		||||
        nfc_text_store_set(
 | 
			
		||||
            nfc,
 | 
			
		||||
            "%02X %02X %02X %02X\n%02X %02X %02X",
 | 
			
		||||
            data->uid[0],
 | 
			
		||||
            data->uid[1],
 | 
			
		||||
            data->uid[2],
 | 
			
		||||
            data->uid[3],
 | 
			
		||||
            data->uid[4],
 | 
			
		||||
            data->uid[5],
 | 
			
		||||
            data->uid[6]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
 | 
			
		||||
    popup_set_header(popup, "Emulating UID", 56, 31, AlignLeft, AlignTop);
 | 
			
		||||
    popup_set_text(popup, nfc->text_store, 56, 43, AlignLeft, AlignTop);
 | 
			
		||||
 | 
			
		||||
    // Setup and start worker
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
 | 
			
		||||
    nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
 | 
			
		||||
    // Set Widget state and view
 | 
			
		||||
    scene_manager_set_scene_state(
 | 
			
		||||
        nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget);
 | 
			
		||||
    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 | 
			
		||||
    // Start worker
 | 
			
		||||
    memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
 | 
			
		||||
    nfc_worker_start(
 | 
			
		||||
        nfc->worker,
 | 
			
		||||
        NfcWorkerStateEmulate,
 | 
			
		||||
        &nfc->dev->dev_data,
 | 
			
		||||
        nfc_emulate_uid_worker_callback,
 | 
			
		||||
        nfc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data;
 | 
			
		||||
    uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid);
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeTick) {
 | 
			
		||||
        notification_message(nfc->notifications, &sequence_blink_blue_10);
 | 
			
		||||
        return true;
 | 
			
		||||
        consumed = true;
 | 
			
		||||
    } else if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == NfcCustomEventWorkerExit) {
 | 
			
		||||
            // Add data button to widget if data is received for the first time
 | 
			
		||||
            if(!string_size(nfc->text_box_store)) {
 | 
			
		||||
                nfc_scene_emulate_uid_widget_config(nfc, true);
 | 
			
		||||
            }
 | 
			
		||||
    return false;
 | 
			
		||||
            // Update TextBox data
 | 
			
		||||
            string_cat_printf(nfc->text_box_store, "R:");
 | 
			
		||||
            for(uint16_t i = 0; i < reader_data->size; i++) {
 | 
			
		||||
                string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
 | 
			
		||||
            }
 | 
			
		||||
            string_push_back(nfc->text_box_store, '\n');
 | 
			
		||||
            memset(reader_data, 0, sizeof(NfcReaderRequestData));
 | 
			
		||||
            text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) {
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateTextBox);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateUidStateTextBox) {
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(event.type == SceneManagerEventTypeBack) {
 | 
			
		||||
        if(state == NfcSceneEmulateUidStateTextBox) {
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return consumed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_emulate_uid_on_exit(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
 | 
			
		||||
    // Stop worker
 | 
			
		||||
    nfc_worker_stop(nfc->worker);
 | 
			
		||||
 | 
			
		||||
    // Clear view
 | 
			
		||||
    Popup* popup = nfc->popup;
 | 
			
		||||
    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
 | 
			
		||||
    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
 | 
			
		||||
    popup_set_icon(popup, 0, 0, NULL);
 | 
			
		||||
    widget_reset(nfc->widget);
 | 
			
		||||
    text_box_reset(nfc->text_box);
 | 
			
		||||
    string_reset(nfc->text_box_store);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_READ_CARD_CUSTOM_EVENT (10UL)
 | 
			
		||||
 | 
			
		||||
void nfc_read_card_worker_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_CARD_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_card_on_enter(void* context) {
 | 
			
		||||
@ -27,7 +25,7 @@ bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == NFC_READ_CARD_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventWorkerExit) {
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -85,5 +85,5 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_card_success_on_exit(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    widget_clear(nfc->widget);
 | 
			
		||||
    widget_reset(nfc->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_READ_EMV_APP_CUSTOM_EVENT (10UL)
 | 
			
		||||
 | 
			
		||||
void nfc_read_emv_app_worker_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_EMV_APP_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_emv_app_on_enter(void* context) {
 | 
			
		||||
@ -31,7 +29,7 @@ bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == NFC_READ_EMV_APP_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventWorkerExit) {
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_READ_EMV_DATA_CUSTOM_EVENT (10UL)
 | 
			
		||||
 | 
			
		||||
void nfc_read_emv_data_worker_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_EMV_DATA_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_emv_data_on_enter(void* context) {
 | 
			
		||||
@ -33,7 +31,7 @@ bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == NFC_READ_EMV_DATA_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventWorkerExit) {
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
 | 
			
		||||
 | 
			
		||||
@ -140,5 +140,5 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e
 | 
			
		||||
void nfc_scene_read_emv_data_success_on_exit(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    widget_clear(nfc->widget);
 | 
			
		||||
    widget_reset(nfc->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_READ_MIFARE_UL_CUSTOM_EVENT (10UL)
 | 
			
		||||
 | 
			
		||||
void nfc_read_mifare_ul_worker_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_READ_MIFARE_UL_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_mifare_ul_on_enter(void* context) {
 | 
			
		||||
@ -31,7 +29,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == NFC_READ_MIFARE_UL_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventWorkerExit) {
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define NFC_SCENE_READ_SUCCESS_SHIFT "              "
 | 
			
		||||
#define NFC_SCENE_READ_MF_UL_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    ReadMifareUlStateShowUID,
 | 
			
		||||
@ -15,12 +14,6 @@ void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, voi
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_mifare_ul_success_text_box_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_READ_MF_UL_CUSTOM_EVENT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
 | 
			
		||||
@ -59,8 +52,6 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
 | 
			
		||||
 | 
			
		||||
    // Setup TextBox view
 | 
			
		||||
    TextBox* text_box = nfc->text_box;
 | 
			
		||||
    text_box_set_context(text_box, nfc);
 | 
			
		||||
    text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback);
 | 
			
		||||
    text_box_set_font(text_box, TextBoxFontHex);
 | 
			
		||||
    for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) {
 | 
			
		||||
        if(!(i % 8) && i) {
 | 
			
		||||
@ -77,39 +68,34 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    Nfc* nfc = context;
 | 
			
		||||
    uint32_t state =
 | 
			
		||||
        scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if((scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) ==
 | 
			
		||||
            ReadMifareUlStateShowUID) &&
 | 
			
		||||
           (event.event == DialogExResultLeft)) {
 | 
			
		||||
        if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
 | 
			
		||||
            scene_manager_previous_scene(nfc->scene_manager);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if(
 | 
			
		||||
            (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) ==
 | 
			
		||||
             ReadMifareUlStateShowUID) &&
 | 
			
		||||
            (event.event == DialogExResultRight)) {
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) {
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if(
 | 
			
		||||
            (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) ==
 | 
			
		||||
             ReadMifareUlStateShowUID) &&
 | 
			
		||||
            (event.event == DialogExResultCenter)) {
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) {
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if(
 | 
			
		||||
            (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) ==
 | 
			
		||||
             ReadMifareUlStateShowData) &&
 | 
			
		||||
            (event.event == NFC_SCENE_READ_MF_UL_CUSTOM_EVENT)) {
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(event.type == SceneManagerEventTypeBack) {
 | 
			
		||||
        if(state == ReadMifareUlStateShowData) {
 | 
			
		||||
            view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
 | 
			
		||||
            scene_manager_set_scene_state(
 | 
			
		||||
                nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID);
 | 
			
		||||
            return true;
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
    return consumed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,8 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
 | 
			
		||||
#define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_restore_original_popup_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_restore_original_on_enter(void* context) {
 | 
			
		||||
@ -26,7 +24,7 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event)
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventViewExit) {
 | 
			
		||||
            consumed = scene_manager_previous_scene(nfc->scene_manager);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,10 @@
 | 
			
		||||
#include <lib/toolbox/random_name.h>
 | 
			
		||||
#include <gui/modules/validators.h>
 | 
			
		||||
 | 
			
		||||
#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_save_name_text_input_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_NAME_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_save_name_on_enter(void* context) {
 | 
			
		||||
@ -42,7 +40,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventTextInputDone) {
 | 
			
		||||
            if(strcmp(nfc->dev->dev_name, "")) {
 | 
			
		||||
                nfc_device_delete(nfc->dev);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_save_success_popup_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SAVE_SUCCESS_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_save_success_on_enter(void* context) {
 | 
			
		||||
@ -28,7 +26,7 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventViewExit) {
 | 
			
		||||
            if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
 | 
			
		||||
                consumed = scene_manager_search_and_switch_to_previous_scene(
 | 
			
		||||
                    nfc->scene_manager, NfcSceneCardMenu);
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
 | 
			
		||||
#define SCENE_SET_ATQA_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_atqa_byte_input_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_ATQA_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_atqa_on_enter(void* context) {
 | 
			
		||||
@ -28,7 +26,7 @@ bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SET_ATQA_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventByteInputDone) {
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,9 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
 | 
			
		||||
#define SCENE_SET_SAK_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_sak_byte_input_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_SAK_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_sak_on_enter(void* context) {
 | 
			
		||||
@ -28,7 +26,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SET_SAK_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventByteInputDone) {
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,10 @@
 | 
			
		||||
#include "../nfc_i.h"
 | 
			
		||||
#include <dolphin/dolphin.h>
 | 
			
		||||
 | 
			
		||||
#define SCENE_SET_UID_CUSTOM_EVENT (0UL)
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_uid_byte_input_callback(void* context) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, SCENE_SET_UID_CUSTOM_EVENT);
 | 
			
		||||
    view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nfc_scene_set_uid_on_enter(void* context) {
 | 
			
		||||
@ -30,7 +28,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    Nfc* nfc = (Nfc*)context;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == SCENE_SET_UID_CUSTOM_EVENT) {
 | 
			
		||||
        if(event.event == NfcCustomEventByteInputDone) {
 | 
			
		||||
            DOLPHIN_DEED(DolphinDeedNfcAdd);
 | 
			
		||||
            scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ View* bank_card_get_view(BankCard* bank_card) {
 | 
			
		||||
 | 
			
		||||
void bank_card_clear(BankCard* bank_card) {
 | 
			
		||||
    furi_assert(bank_card);
 | 
			
		||||
    widget_clear(bank_card->widget);
 | 
			
		||||
    widget_reset(bank_card->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bank_card_set_name(BankCard* bank_card, char* name) {
 | 
			
		||||
 | 
			
		||||
@ -65,5 +65,5 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
 | 
			
		||||
void subghz_scene_delete_on_exit(void* context) {
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    widget_clear(subghz->widget);
 | 
			
		||||
    widget_reset(subghz->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -73,5 +73,5 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
 | 
			
		||||
void subghz_scene_delete_raw_on_exit(void* context) {
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    widget_clear(subghz->widget);
 | 
			
		||||
    widget_reset(subghz->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -63,5 +63,5 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
 | 
			
		||||
void subghz_scene_need_saving_on_exit(void* context) {
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    widget_clear(subghz->widget);
 | 
			
		||||
    widget_reset(subghz->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
 | 
			
		||||
        path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str);
 | 
			
		||||
        strcpy(subghz->file_name, string_get_cstr(temp_str));
 | 
			
		||||
        string_printf(
 | 
			
		||||
            temp_str, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
            temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
        subghz_protocol_raw_set_last_file_name(
 | 
			
		||||
            (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str));
 | 
			
		||||
 | 
			
		||||
@ -180,5 +180,5 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
 | 
			
		||||
 | 
			
		||||
void subghz_scene_receiver_info_on_exit(void* context) {
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    widget_clear(subghz->widget);
 | 
			
		||||
    widget_reset(subghz->widget);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ void subghz_scene_save_name_on_enter(void* context) {
 | 
			
		||||
        dev_name_empty);
 | 
			
		||||
 | 
			
		||||
    ValidatorIsFile* validator_is_file =
 | 
			
		||||
        validator_is_file_alloc_init(SUBGHZ_APP_PATH_FOLDER, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
    text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput);
 | 
			
		||||
 | 
			
		||||
@ -79,6 +79,6 @@ void subghz_scene_show_error_on_exit(void* context) {
 | 
			
		||||
    SubGhz* subghz = context;
 | 
			
		||||
    scene_manager_set_scene_state(
 | 
			
		||||
        subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet);
 | 
			
		||||
    widget_clear(subghz->widget);
 | 
			
		||||
    widget_reset(subghz->widget);
 | 
			
		||||
    string_reset(subghz->error_str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -284,10 +284,10 @@ int32_t subghz_app(void* p) {
 | 
			
		||||
 | 
			
		||||
    //Load database
 | 
			
		||||
    bool load_database =
 | 
			
		||||
        subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes");
 | 
			
		||||
    subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes_user");
 | 
			
		||||
    subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/nice_flor_s_rx");
 | 
			
		||||
    subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/came_atomo");
 | 
			
		||||
        subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes");
 | 
			
		||||
    subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes_user");
 | 
			
		||||
    subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/assets/nice_flor_s_rx");
 | 
			
		||||
    subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/assets/came_atomo");
 | 
			
		||||
 | 
			
		||||
    // Check argument and run corresponding scene
 | 
			
		||||
    if(p && subghz_key_load(subghz, p)) {
 | 
			
		||||
 | 
			
		||||
@ -215,10 +215,10 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
 | 
			
		||||
    furi_check(instance->stream);
 | 
			
		||||
 | 
			
		||||
    SubGhzParser* parser = subghz_parser_alloc();
 | 
			
		||||
    subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes");
 | 
			
		||||
    subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes_user");
 | 
			
		||||
    subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/nice_flor_s_rx");
 | 
			
		||||
    subghz_parser_load_came_atomo_file(parser, "/ext/subghz/came_atomo");
 | 
			
		||||
    subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes");
 | 
			
		||||
    subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes_user");
 | 
			
		||||
    subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/assets/nice_flor_s_rx");
 | 
			
		||||
    subghz_parser_load_came_atomo_file(parser, "/ext/subghz/assets/came_atomo");
 | 
			
		||||
    subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance);
 | 
			
		||||
 | 
			
		||||
    // Configure radio
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								applications/subghz/subghz_i.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										20
									
								
								applications/subghz/subghz_i.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -284,7 +284,7 @@ bool subghz_get_next_name_file(SubGhz* subghz) {
 | 
			
		||||
    if(strcmp(subghz->file_name, "")) {
 | 
			
		||||
        //get the name of the next free file
 | 
			
		||||
        storage_get_next_filename(
 | 
			
		||||
            storage, SUBGHZ_RAW_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str);
 | 
			
		||||
            storage, SUBGHZ_RAW_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str);
 | 
			
		||||
 | 
			
		||||
        strcpy(subghz->file_name, string_get_cstr(temp_str));
 | 
			
		||||
        res = true;
 | 
			
		||||
@ -319,15 +319,9 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) {
 | 
			
		||||
            dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        // Create saved directory if necessary
 | 
			
		||||
        if(!storage_simply_mkdir(storage, SUBGHZ_APP_PATH_FOLDER)) {
 | 
			
		||||
            dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // First remove subghz device file if it was saved
 | 
			
		||||
        string_printf(
 | 
			
		||||
            dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        string_printf(dev_file_name, "%s/%s%s", SUBGHZ_APP_FOLDER, dev_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
        if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) {
 | 
			
		||||
            break;
 | 
			
		||||
@ -386,7 +380,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
 | 
			
		||||
    // Input events and views are managed by file_select
 | 
			
		||||
    bool res = dialog_file_select_show(
 | 
			
		||||
        subghz->dialogs,
 | 
			
		||||
        SUBGHZ_APP_PATH_FOLDER,
 | 
			
		||||
        SUBGHZ_APP_FOLDER,
 | 
			
		||||
        SUBGHZ_APP_EXTENSION,
 | 
			
		||||
        subghz->file_name,
 | 
			
		||||
        sizeof(subghz->file_name),
 | 
			
		||||
@ -394,7 +388,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) {
 | 
			
		||||
 | 
			
		||||
    if(res) {
 | 
			
		||||
        string_printf(
 | 
			
		||||
            file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
            file_name, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
        res = subghz_key_load(subghz, string_get_cstr(file_name));
 | 
			
		||||
    }
 | 
			
		||||
@ -413,10 +407,10 @@ bool subghz_rename_file(SubGhz* subghz) {
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
 | 
			
		||||
    string_init_printf(
 | 
			
		||||
        old_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        old_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
    string_init_printf(
 | 
			
		||||
        new_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        new_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
    FS_Error fs_result =
 | 
			
		||||
        storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path));
 | 
			
		||||
@ -439,7 +433,7 @@ bool subghz_delete_file(SubGhz* subghz) {
 | 
			
		||||
    Storage* storage = furi_record_open("storage");
 | 
			
		||||
    string_t file_path;
 | 
			
		||||
    string_init_printf(
 | 
			
		||||
        file_path, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        file_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
    bool result = storage_simply_remove(storage, string_get_cstr(file_path));
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1 +1,2 @@
 | 
			
		||||
ADD_SCENE(u2f, main, Main)
 | 
			
		||||
ADD_SCENE(u2f, error, Error)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								applications/u2f/scenes/u2f_scene_error.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								applications/u2f/scenes/u2f_scene_error.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#include "../u2f_app_i.h"
 | 
			
		||||
 | 
			
		||||
static void u2f_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    U2fApp* app = context;
 | 
			
		||||
 | 
			
		||||
    if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
 | 
			
		||||
        view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventErrorBack);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void u2f_scene_error_on_enter(void* context) {
 | 
			
		||||
    U2fApp* app = context;
 | 
			
		||||
 | 
			
		||||
    widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
 | 
			
		||||
 | 
			
		||||
    widget_add_string_multiline_element(
 | 
			
		||||
        app->widget,
 | 
			
		||||
        81,
 | 
			
		||||
        4,
 | 
			
		||||
        AlignCenter,
 | 
			
		||||
        AlignTop,
 | 
			
		||||
        FontSecondary,
 | 
			
		||||
        "No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
 | 
			
		||||
 | 
			
		||||
    widget_add_button_element(
 | 
			
		||||
        app->widget, GuiButtonTypeLeft, "Back", u2f_scene_error_event_callback, app);
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_switch_to_view(app->view_dispatcher, U2fAppViewError);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool u2f_scene_error_on_event(void* context, SceneManagerEvent event) {
 | 
			
		||||
    U2fApp* app = context;
 | 
			
		||||
    bool consumed = false;
 | 
			
		||||
 | 
			
		||||
    if(event.type == SceneManagerEventTypeCustom) {
 | 
			
		||||
        if(event.event == U2fCustomEventErrorBack) {
 | 
			
		||||
            view_dispatcher_stop(app->view_dispatcher);
 | 
			
		||||
            consumed = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return consumed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void u2f_scene_error_on_exit(void* context) {
 | 
			
		||||
    U2fApp* app = context;
 | 
			
		||||
    widget_reset(app->widget);
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
#include "u2f_app_i.h"
 | 
			
		||||
#include "u2f_data.h"
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <furi_hal.h>
 | 
			
		||||
 | 
			
		||||
@ -39,11 +40,19 @@ U2fApp* u2f_app_alloc() {
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
 | 
			
		||||
 | 
			
		||||
    // Custom Widget
 | 
			
		||||
    app->widget = widget_alloc();
 | 
			
		||||
    view_dispatcher_add_view(app->view_dispatcher, U2fAppViewError, widget_get_view(app->widget));
 | 
			
		||||
 | 
			
		||||
    app->u2f_view = u2f_view_alloc();
 | 
			
		||||
    view_dispatcher_add_view(
 | 
			
		||||
        app->view_dispatcher, U2fAppViewMain, u2f_view_get_view(app->u2f_view));
 | 
			
		||||
 | 
			
		||||
    scene_manager_next_scene(app->scene_manager, U2fAppViewMain);
 | 
			
		||||
    if(u2f_data_check()) {
 | 
			
		||||
        scene_manager_next_scene(app->scene_manager, U2fSceneMain);
 | 
			
		||||
    } else {
 | 
			
		||||
        scene_manager_next_scene(app->scene_manager, U2fSceneError);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return app;
 | 
			
		||||
}
 | 
			
		||||
@ -55,6 +64,10 @@ void u2f_app_free(U2fApp* app) {
 | 
			
		||||
    view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewMain);
 | 
			
		||||
    u2f_view_free(app->u2f_view);
 | 
			
		||||
 | 
			
		||||
    // Custom Widget
 | 
			
		||||
    view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewError);
 | 
			
		||||
    widget_free(app->widget);
 | 
			
		||||
 | 
			
		||||
    // View dispatcher
 | 
			
		||||
    view_dispatcher_free(app->view_dispatcher);
 | 
			
		||||
    scene_manager_free(app->scene_manager);
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@
 | 
			
		||||
#include <dialogs/dialogs.h>
 | 
			
		||||
#include <notification/notification_messages.h>
 | 
			
		||||
#include <gui/modules/variable_item_list.h>
 | 
			
		||||
#include <gui/modules/widget.h>
 | 
			
		||||
#include "views/u2f_view.h"
 | 
			
		||||
#include "u2f_hid.h"
 | 
			
		||||
#include "u2f.h"
 | 
			
		||||
@ -29,9 +30,12 @@ typedef enum {
 | 
			
		||||
 | 
			
		||||
    U2fCustomEventConfirm,
 | 
			
		||||
 | 
			
		||||
    U2fCustomEventErrorBack,
 | 
			
		||||
 | 
			
		||||
} GpioCustomEvent;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    U2fAppViewError,
 | 
			
		||||
    U2fAppViewMain,
 | 
			
		||||
} U2fAppView;
 | 
			
		||||
 | 
			
		||||
@ -40,6 +44,7 @@ struct U2fApp {
 | 
			
		||||
    ViewDispatcher* view_dispatcher;
 | 
			
		||||
    SceneManager* scene_manager;
 | 
			
		||||
    NotificationApp* notifications;
 | 
			
		||||
    Widget* widget;
 | 
			
		||||
    osTimerId_t timer;
 | 
			
		||||
    U2fHid* u2f_hid;
 | 
			
		||||
    U2fView* u2f_view;
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,8 @@
 | 
			
		||||
#define TAG "U2F"
 | 
			
		||||
 | 
			
		||||
#define U2F_DATA_FOLDER "/any/u2f/"
 | 
			
		||||
#define U2F_CERT_FILE U2F_DATA_FOLDER "cert.der"
 | 
			
		||||
#define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "cert_key.u2f"
 | 
			
		||||
#define U2F_CERT_FILE U2F_DATA_FOLDER "assets/cert.der"
 | 
			
		||||
#define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "assets/cert_key.u2f"
 | 
			
		||||
#define U2F_KEY_FILE U2F_DATA_FOLDER "key.u2f"
 | 
			
		||||
#define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f"
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,26 @@ typedef struct {
 | 
			
		||||
    uint32_t control;
 | 
			
		||||
} __attribute__((packed)) U2fCounterData;
 | 
			
		||||
 | 
			
		||||
bool u2f_data_check() {
 | 
			
		||||
    bool state = false;
 | 
			
		||||
    Storage* fs_api = furi_record_open("storage");
 | 
			
		||||
    File* file = storage_file_alloc(fs_api);
 | 
			
		||||
 | 
			
		||||
    if(storage_file_open(file, U2F_CERT_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
 | 
			
		||||
        storage_file_close(file);
 | 
			
		||||
        if(storage_file_open(file, U2F_CERT_KEY_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
 | 
			
		||||
            state = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    storage_file_close(file);
 | 
			
		||||
    storage_file_free(file);
 | 
			
		||||
 | 
			
		||||
    furi_record_close("storage");
 | 
			
		||||
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool u2f_data_cert_check() {
 | 
			
		||||
    bool state = false;
 | 
			
		||||
    Storage* fs_api = furi_record_open("storage");
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
 | 
			
		||||
bool u2f_data_check();
 | 
			
		||||
 | 
			
		||||
bool u2f_data_cert_check();
 | 
			
		||||
 | 
			
		||||
uint32_t u2f_data_cert_load(uint8_t* cert);
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ static void u2f_view_draw_callback(Canvas* canvas, void* _model) {
 | 
			
		||||
            canvas, 128 / 2, 3, AlignCenter, AlignTop, "Authentication successfull!");
 | 
			
		||||
    } else if(model->display_msg == U2fMsgError) {
 | 
			
		||||
        canvas_draw_icon(canvas, 22, 15, &I_Error_62x31);
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Ceritficate missing");
 | 
			
		||||
        canvas_draw_str_aligned(canvas, 128 / 2, 3, AlignCenter, AlignTop, "Ceritficate error");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,14 +16,15 @@ You should have received a copy of the GNU General Public License
 | 
			
		||||
along with PyCortexMDebug.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
import os
 | 
			
		||||
import pickle
 | 
			
		||||
from . import x2d
 | 
			
		||||
 | 
			
		||||
import traceback
 | 
			
		||||
import re
 | 
			
		||||
import warnings
 | 
			
		||||
import x2d
 | 
			
		||||
import pickle
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SmartDict:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										131
									
								
								firmware/targets/f6/furi_hal/furi_hal_nfc.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										131
									
								
								firmware/targets/f6/furi_hal/furi_hal_nfc.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -1,14 +1,25 @@
 | 
			
		||||
#include "furi_hal_nfc.h"
 | 
			
		||||
#include <st25r3916.h>
 | 
			
		||||
#include <rfal_rf.h>
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <m-string.h>
 | 
			
		||||
#include <lib/nfc_protocols/nfca.h>
 | 
			
		||||
 | 
			
		||||
#define TAG "FuriHalNfc"
 | 
			
		||||
 | 
			
		||||
static const uint32_t clocks_in_ms = 64 * 1000;
 | 
			
		||||
 | 
			
		||||
osEventFlagsId_t event = NULL;
 | 
			
		||||
#define EVENT_FLAG_INTERRUPT (1UL << 0)
 | 
			
		||||
#define EVENT_FLAG_STATE_CHANGED (1UL << 1)
 | 
			
		||||
#define EVENT_FLAG_STOP (1UL << 2)
 | 
			
		||||
#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP)
 | 
			
		||||
 | 
			
		||||
void furi_hal_nfc_init() {
 | 
			
		||||
    ReturnCode ret = rfalNfcInitialize();
 | 
			
		||||
    if(ret == ERR_NONE) {
 | 
			
		||||
        furi_hal_nfc_start_sleep();
 | 
			
		||||
        event = osEventFlagsNew(NULL);
 | 
			
		||||
        FURI_LOG_I(TAG, "Init OK");
 | 
			
		||||
    } else {
 | 
			
		||||
        FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret);
 | 
			
		||||
@ -140,6 +151,126 @@ bool furi_hal_nfc_listen(
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_interrupt_callback_handler() {
 | 
			
		||||
    osEventFlagsSet(event, EVENT_FLAG_INTERRUPT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_state_changed_callback(void* context) {
 | 
			
		||||
    osEventFlagsSet(event, EVENT_FLAG_STATE_CHANGED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void furi_hal_nfc_stop() {
 | 
			
		||||
    if(event) {
 | 
			
		||||
        osEventFlagsSet(event, EVENT_FLAG_STOP);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool furi_hal_nfc_emulate_nfca(
 | 
			
		||||
    uint8_t* uid,
 | 
			
		||||
    uint8_t uid_len,
 | 
			
		||||
    uint8_t* atqa,
 | 
			
		||||
    uint8_t sak,
 | 
			
		||||
    FuriHalNfcEmulateCallback callback,
 | 
			
		||||
    void* context,
 | 
			
		||||
    uint32_t timeout) {
 | 
			
		||||
    rfalSetUpperLayerCallback(rfal_interrupt_callback_handler);
 | 
			
		||||
    rfal_set_state_changed_callback(rfal_state_changed_callback);
 | 
			
		||||
 | 
			
		||||
    rfalLmConfPA config;
 | 
			
		||||
    config.nfcidLen = uid_len;
 | 
			
		||||
    memcpy(config.nfcid, uid, uid_len);
 | 
			
		||||
    memcpy(config.SENS_RES, atqa, RFAL_LM_SENS_RES_LEN);
 | 
			
		||||
    config.SEL_RES = sak;
 | 
			
		||||
    uint8_t buff_rx[256];
 | 
			
		||||
    uint16_t buff_rx_size = 256;
 | 
			
		||||
    uint16_t buff_rx_len = 0;
 | 
			
		||||
    uint8_t buff_tx[256];
 | 
			
		||||
    uint16_t buff_tx_len = 0;
 | 
			
		||||
    uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
 | 
			
		||||
    rfalLowPowerModeStop();
 | 
			
		||||
    if(rfalListenStart(
 | 
			
		||||
           RFAL_LM_MASK_NFCA,
 | 
			
		||||
           &config,
 | 
			
		||||
           NULL,
 | 
			
		||||
           NULL,
 | 
			
		||||
           buff_rx,
 | 
			
		||||
           rfalConvBytesToBits(buff_rx_size),
 | 
			
		||||
           &buff_rx_len)) {
 | 
			
		||||
        rfalListenStop();
 | 
			
		||||
        FURI_LOG_E(TAG, "Failed to start listen mode");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    while(true) {
 | 
			
		||||
        buff_rx_len = 0;
 | 
			
		||||
        buff_tx_len = 0;
 | 
			
		||||
        uint32_t flag = osEventFlagsWait(event, EVENT_FLAG_ALL, osFlagsWaitAny, timeout);
 | 
			
		||||
        if(flag == osErrorTimeout || flag == EVENT_FLAG_STOP) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        bool data_received = false;
 | 
			
		||||
        buff_rx_len = 0;
 | 
			
		||||
        rfalWorker();
 | 
			
		||||
        rfalLmState state = rfalListenGetState(&data_received, NULL);
 | 
			
		||||
        if(data_received) {
 | 
			
		||||
            rfalTransceiveBlockingRx();
 | 
			
		||||
            if(nfca_emulation_handler(buff_rx, buff_rx_len, buff_tx, &buff_tx_len)) {
 | 
			
		||||
                if(rfalListenSleepStart(
 | 
			
		||||
                       RFAL_LM_STATE_SLEEP_A,
 | 
			
		||||
                       buff_rx,
 | 
			
		||||
                       rfalConvBytesToBits(buff_rx_size),
 | 
			
		||||
                       &buff_rx_len)) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Failed to enter sleep mode");
 | 
			
		||||
                    break;
 | 
			
		||||
                } else {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if(buff_tx_len) {
 | 
			
		||||
                ReturnCode ret = rfalTransceiveBitsBlockingTx(
 | 
			
		||||
                    buff_tx,
 | 
			
		||||
                    buff_tx_len,
 | 
			
		||||
                    buff_rx,
 | 
			
		||||
                    sizeof(buff_rx),
 | 
			
		||||
                    &buff_rx_len,
 | 
			
		||||
                    data_type,
 | 
			
		||||
                    RFAL_FWT_NONE);
 | 
			
		||||
                if(ret) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if((state == RFAL_LM_STATE_ACTIVE_A || state == RFAL_LM_STATE_ACTIVE_Ax)) {
 | 
			
		||||
                if(callback) {
 | 
			
		||||
                    callback(buff_rx, buff_rx_len, buff_tx, &buff_tx_len, &data_type, context);
 | 
			
		||||
                }
 | 
			
		||||
                if(!rfalIsExtFieldOn()) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if(buff_tx_len) {
 | 
			
		||||
                    ReturnCode ret = rfalTransceiveBitsBlockingTx(
 | 
			
		||||
                        buff_tx,
 | 
			
		||||
                        buff_tx_len,
 | 
			
		||||
                        buff_rx,
 | 
			
		||||
                        sizeof(buff_rx),
 | 
			
		||||
                        &buff_rx_len,
 | 
			
		||||
                        data_type,
 | 
			
		||||
                        RFAL_FWT_NONE);
 | 
			
		||||
                    if(ret) {
 | 
			
		||||
                        FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    rfalListenStop();
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										131
									
								
								firmware/targets/f7/furi_hal/furi_hal_nfc.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										131
									
								
								firmware/targets/f7/furi_hal/furi_hal_nfc.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -1,14 +1,25 @@
 | 
			
		||||
#include "furi_hal_nfc.h"
 | 
			
		||||
#include <st25r3916.h>
 | 
			
		||||
#include <rfal_rf.h>
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <m-string.h>
 | 
			
		||||
#include <lib/nfc_protocols/nfca.h>
 | 
			
		||||
 | 
			
		||||
#define TAG "FuriHalNfc"
 | 
			
		||||
 | 
			
		||||
static const uint32_t clocks_in_ms = 64 * 1000;
 | 
			
		||||
 | 
			
		||||
osEventFlagsId_t event = NULL;
 | 
			
		||||
#define EVENT_FLAG_INTERRUPT (1UL << 0)
 | 
			
		||||
#define EVENT_FLAG_STATE_CHANGED (1UL << 1)
 | 
			
		||||
#define EVENT_FLAG_STOP (1UL << 2)
 | 
			
		||||
#define EVENT_FLAG_ALL (EVENT_FLAG_INTERRUPT | EVENT_FLAG_STATE_CHANGED | EVENT_FLAG_STOP)
 | 
			
		||||
 | 
			
		||||
void furi_hal_nfc_init() {
 | 
			
		||||
    ReturnCode ret = rfalNfcInitialize();
 | 
			
		||||
    if(ret == ERR_NONE) {
 | 
			
		||||
        furi_hal_nfc_start_sleep();
 | 
			
		||||
        event = osEventFlagsNew(NULL);
 | 
			
		||||
        FURI_LOG_I(TAG, "Init OK");
 | 
			
		||||
    } else {
 | 
			
		||||
        FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret);
 | 
			
		||||
@ -140,6 +151,126 @@ bool furi_hal_nfc_listen(
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_interrupt_callback_handler() {
 | 
			
		||||
    osEventFlagsSet(event, EVENT_FLAG_INTERRUPT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_state_changed_callback(void* context) {
 | 
			
		||||
    osEventFlagsSet(event, EVENT_FLAG_STATE_CHANGED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void furi_hal_nfc_stop() {
 | 
			
		||||
    if(event) {
 | 
			
		||||
        osEventFlagsSet(event, EVENT_FLAG_STOP);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool furi_hal_nfc_emulate_nfca(
 | 
			
		||||
    uint8_t* uid,
 | 
			
		||||
    uint8_t uid_len,
 | 
			
		||||
    uint8_t* atqa,
 | 
			
		||||
    uint8_t sak,
 | 
			
		||||
    FuriHalNfcEmulateCallback callback,
 | 
			
		||||
    void* context,
 | 
			
		||||
    uint32_t timeout) {
 | 
			
		||||
    rfalSetUpperLayerCallback(rfal_interrupt_callback_handler);
 | 
			
		||||
    rfal_set_state_changed_callback(rfal_state_changed_callback);
 | 
			
		||||
 | 
			
		||||
    rfalLmConfPA config;
 | 
			
		||||
    config.nfcidLen = uid_len;
 | 
			
		||||
    memcpy(config.nfcid, uid, uid_len);
 | 
			
		||||
    memcpy(config.SENS_RES, atqa, RFAL_LM_SENS_RES_LEN);
 | 
			
		||||
    config.SEL_RES = sak;
 | 
			
		||||
    uint8_t buff_rx[256];
 | 
			
		||||
    uint16_t buff_rx_size = 256;
 | 
			
		||||
    uint16_t buff_rx_len = 0;
 | 
			
		||||
    uint8_t buff_tx[256];
 | 
			
		||||
    uint16_t buff_tx_len = 0;
 | 
			
		||||
    uint32_t data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
 | 
			
		||||
    rfalLowPowerModeStop();
 | 
			
		||||
    if(rfalListenStart(
 | 
			
		||||
           RFAL_LM_MASK_NFCA,
 | 
			
		||||
           &config,
 | 
			
		||||
           NULL,
 | 
			
		||||
           NULL,
 | 
			
		||||
           buff_rx,
 | 
			
		||||
           rfalConvBytesToBits(buff_rx_size),
 | 
			
		||||
           &buff_rx_len)) {
 | 
			
		||||
        rfalListenStop();
 | 
			
		||||
        FURI_LOG_E(TAG, "Failed to start listen mode");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    while(true) {
 | 
			
		||||
        buff_rx_len = 0;
 | 
			
		||||
        buff_tx_len = 0;
 | 
			
		||||
        uint32_t flag = osEventFlagsWait(event, EVENT_FLAG_ALL, osFlagsWaitAny, timeout);
 | 
			
		||||
        if(flag == osErrorTimeout || flag == EVENT_FLAG_STOP) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        bool data_received = false;
 | 
			
		||||
        buff_rx_len = 0;
 | 
			
		||||
        rfalWorker();
 | 
			
		||||
        rfalLmState state = rfalListenGetState(&data_received, NULL);
 | 
			
		||||
        if(data_received) {
 | 
			
		||||
            rfalTransceiveBlockingRx();
 | 
			
		||||
            if(nfca_emulation_handler(buff_rx, buff_rx_len, buff_tx, &buff_tx_len)) {
 | 
			
		||||
                if(rfalListenSleepStart(
 | 
			
		||||
                       RFAL_LM_STATE_SLEEP_A,
 | 
			
		||||
                       buff_rx,
 | 
			
		||||
                       rfalConvBytesToBits(buff_rx_size),
 | 
			
		||||
                       &buff_rx_len)) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Failed to enter sleep mode");
 | 
			
		||||
                    break;
 | 
			
		||||
                } else {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if(buff_tx_len) {
 | 
			
		||||
                ReturnCode ret = rfalTransceiveBitsBlockingTx(
 | 
			
		||||
                    buff_tx,
 | 
			
		||||
                    buff_tx_len,
 | 
			
		||||
                    buff_rx,
 | 
			
		||||
                    sizeof(buff_rx),
 | 
			
		||||
                    &buff_rx_len,
 | 
			
		||||
                    data_type,
 | 
			
		||||
                    RFAL_FWT_NONE);
 | 
			
		||||
                if(ret) {
 | 
			
		||||
                    FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if((state == RFAL_LM_STATE_ACTIVE_A || state == RFAL_LM_STATE_ACTIVE_Ax)) {
 | 
			
		||||
                if(callback) {
 | 
			
		||||
                    callback(buff_rx, buff_rx_len, buff_tx, &buff_tx_len, &data_type, context);
 | 
			
		||||
                }
 | 
			
		||||
                if(!rfalIsExtFieldOn()) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if(buff_tx_len) {
 | 
			
		||||
                    ReturnCode ret = rfalTransceiveBitsBlockingTx(
 | 
			
		||||
                        buff_tx,
 | 
			
		||||
                        buff_tx_len,
 | 
			
		||||
                        buff_rx,
 | 
			
		||||
                        sizeof(buff_rx),
 | 
			
		||||
                        &buff_rx_len,
 | 
			
		||||
                        data_type,
 | 
			
		||||
                        RFAL_FWT_NONE);
 | 
			
		||||
                    if(ret) {
 | 
			
		||||
                        FURI_LOG_E(TAG, "Tranceive failed with status %d", ret);
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    rfalListenStop();
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,26 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
#define FURI_HAL_NFC_UID_MAX_LEN 10
 | 
			
		||||
 | 
			
		||||
#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_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_NFCV_FLAG_AUTO)
 | 
			
		||||
 | 
			
		||||
#define FURI_HAL_NFC_TXRX_RAW                                                          \
 | 
			
		||||
    ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (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_NONE |   \
 | 
			
		||||
     (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO)
 | 
			
		||||
 | 
			
		||||
typedef bool (*FuriHalNfcEmulateCallback)(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    uint16_t* buff_tx_len,
 | 
			
		||||
    uint32_t* flags,
 | 
			
		||||
    void* context);
 | 
			
		||||
 | 
			
		||||
/** Init nfc
 | 
			
		||||
 */
 | 
			
		||||
void furi_hal_nfc_init();
 | 
			
		||||
@ -76,6 +96,15 @@ bool furi_hal_nfc_listen(
 | 
			
		||||
    bool activate_after_sak,
 | 
			
		||||
    uint32_t timeout);
 | 
			
		||||
 | 
			
		||||
bool furi_hal_nfc_emulate_nfca(
 | 
			
		||||
    uint8_t* uid,
 | 
			
		||||
    uint8_t uid_len,
 | 
			
		||||
    uint8_t* atqa,
 | 
			
		||||
    uint8_t sak,
 | 
			
		||||
    FuriHalNfcEmulateCallback callback,
 | 
			
		||||
    void* context,
 | 
			
		||||
    uint32_t timeout);
 | 
			
		||||
 | 
			
		||||
/** Get first command from reader after activation in emulation mode
 | 
			
		||||
 *
 | 
			
		||||
 * @param      rx_buff  pointer to receive buffer
 | 
			
		||||
@ -113,6 +142,8 @@ ReturnCode furi_hal_nfc_raw_bitstream_exchange(
 | 
			
		||||
 */
 | 
			
		||||
void furi_hal_nfc_deactivate();
 | 
			
		||||
 | 
			
		||||
void furi_hal_nfc_stop();
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -545,10 +545,13 @@ typedef struct {
 | 
			
		||||
typedef void (*rfalUpperLayerCallback)(void);
 | 
			
		||||
 | 
			
		||||
/*! Callback to be executed before a Transceive                              */
 | 
			
		||||
typedef void (*rfalPreTxRxCallback)(void);
 | 
			
		||||
typedef void (*rfalPreTxRxCallback)(void* context);
 | 
			
		||||
 | 
			
		||||
/*! Callback to be executed after a Transceive                               */
 | 
			
		||||
typedef void (*rfalPostTxRxCallback)(void);
 | 
			
		||||
typedef void (*rfalPostTxRxCallback)(void* context);
 | 
			
		||||
 | 
			
		||||
/** Callback to be executed on each RFAL state change */
 | 
			
		||||
typedef void (*RfalStateChangedCallback)(void* context);
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************/
 | 
			
		||||
/*  ISO14443A                                                                  */
 | 
			
		||||
@ -819,6 +822,19 @@ void rfalSetPreTxRxCallback(rfalPreTxRxCallback pFunc);
 | 
			
		||||
 */
 | 
			
		||||
void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc);
 | 
			
		||||
 | 
			
		||||
/** Set RFAL state changed callback
 | 
			
		||||
 *
 | 
			
		||||
 * @param cb    RfalStateChangedCallback instance
 | 
			
		||||
 * @param ctx   pointer to context
 | 
			
		||||
 */
 | 
			
		||||
void rfal_set_state_changed_callback(RfalStateChangedCallback callback);
 | 
			
		||||
 | 
			
		||||
/** Set callback context
 | 
			
		||||
 *
 | 
			
		||||
 * @param ctx pointer to context
 | 
			
		||||
 */
 | 
			
		||||
void rfal_set_callback_context(void* context);
 | 
			
		||||
 | 
			
		||||
/*! 
 | 
			
		||||
 *****************************************************************************
 | 
			
		||||
 * \brief  RFAL Deinitialize
 | 
			
		||||
@ -1480,6 +1496,15 @@ ReturnCode rfalTransceiveBlockingTxRx(
 | 
			
		||||
    uint32_t flags,
 | 
			
		||||
    uint32_t fwt);
 | 
			
		||||
 | 
			
		||||
ReturnCode rfalTransceiveBitsBlockingTx(
 | 
			
		||||
    uint8_t* txBuf,
 | 
			
		||||
    uint16_t txBufLen,
 | 
			
		||||
    uint8_t* rxBuf,
 | 
			
		||||
    uint16_t rxBufLen,
 | 
			
		||||
    uint16_t* actLen,
 | 
			
		||||
    uint32_t flags,
 | 
			
		||||
    uint32_t fwt);
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 *  Listen Mode                                                              *  
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@ -130,6 +130,8 @@ typedef struct {
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rfalPreTxRxCallback preTxRx; /*!< RFAL's Pre TxRx callback  */
 | 
			
		||||
    rfalPostTxRxCallback postTxRx; /*!< RFAL's Post TxRx callback */
 | 
			
		||||
    RfalStateChangedCallback state_changed_cb;
 | 
			
		||||
    void* ctx;
 | 
			
		||||
} rfalCallbacks;
 | 
			
		||||
 | 
			
		||||
/*! Struct that holds counters to control the FIFO on Tx and Rx                                                                          */
 | 
			
		||||
@ -595,6 +597,8 @@ ReturnCode rfalInitialize(void) {
 | 
			
		||||
 | 
			
		||||
    gRFAL.callbacks.preTxRx = NULL;
 | 
			
		||||
    gRFAL.callbacks.postTxRx = NULL;
 | 
			
		||||
    gRFAL.callbacks.state_changed_cb = NULL;
 | 
			
		||||
    gRFAL.callbacks.ctx = NULL;
 | 
			
		||||
 | 
			
		||||
#if RFAL_FEATURE_NFCV
 | 
			
		||||
    /* Initialize NFC-V Data */
 | 
			
		||||
@ -669,6 +673,14 @@ void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc) {
 | 
			
		||||
    gRFAL.callbacks.postTxRx = pFunc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_set_state_changed_callback(RfalStateChangedCallback callback) {
 | 
			
		||||
    gRFAL.callbacks.state_changed_cb = callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rfal_set_callback_context(void* context) {
 | 
			
		||||
    gRFAL.callbacks.ctx = context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************/
 | 
			
		||||
ReturnCode rfalDeinitialize(void) {
 | 
			
		||||
    /* Deinitialize chip */
 | 
			
		||||
@ -1520,6 +1532,30 @@ ReturnCode rfalTransceiveBlockingTx(
 | 
			
		||||
    return rfalTransceiveRunBlockingTx();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ReturnCode rfalTransceiveBitsBlockingTx(
 | 
			
		||||
    uint8_t* txBuf,
 | 
			
		||||
    uint16_t txBufLen,
 | 
			
		||||
    uint8_t* rxBuf,
 | 
			
		||||
    uint16_t rxBufLen,
 | 
			
		||||
    uint16_t* actLen,
 | 
			
		||||
    uint32_t flags,
 | 
			
		||||
    uint32_t fwt) {
 | 
			
		||||
    ReturnCode ret;
 | 
			
		||||
    rfalTransceiveContext ctx = {
 | 
			
		||||
        .rxBuf = rxBuf,
 | 
			
		||||
        .rxBufLen = rxBufLen,
 | 
			
		||||
        .rxRcvdLen = actLen,
 | 
			
		||||
        .txBuf = txBuf,
 | 
			
		||||
        .txBufLen = txBufLen,
 | 
			
		||||
        .flags = flags,
 | 
			
		||||
        .fwt = fwt,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    EXIT_ON_ERR(ret, rfalStartTransceive(&ctx));
 | 
			
		||||
 | 
			
		||||
    return rfalTransceiveRunBlockingTx();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************/
 | 
			
		||||
static ReturnCode rfalTransceiveRunBlockingTx(void) {
 | 
			
		||||
    ReturnCode ret;
 | 
			
		||||
@ -1797,7 +1833,7 @@ static void rfalCleanupTransceive(void) {
 | 
			
		||||
    /* Execute Post Transceive Callback                                            */
 | 
			
		||||
    /*******************************************************************************/
 | 
			
		||||
    if(gRFAL.callbacks.postTxRx != NULL) {
 | 
			
		||||
        gRFAL.callbacks.postTxRx();
 | 
			
		||||
        gRFAL.callbacks.postTxRx(gRFAL.callbacks.ctx);
 | 
			
		||||
    }
 | 
			
		||||
    /*******************************************************************************/
 | 
			
		||||
}
 | 
			
		||||
@ -1838,7 +1874,7 @@ static void rfalPrepareTransceive(void) {
 | 
			
		||||
    /* Execute Pre Transceive Callback                                             */
 | 
			
		||||
    /*******************************************************************************/
 | 
			
		||||
    if(gRFAL.callbacks.preTxRx != NULL) {
 | 
			
		||||
        gRFAL.callbacks.preTxRx();
 | 
			
		||||
        gRFAL.callbacks.preTxRx(gRFAL.callbacks.ctx);
 | 
			
		||||
    }
 | 
			
		||||
    /*******************************************************************************/
 | 
			
		||||
 | 
			
		||||
@ -4164,6 +4200,11 @@ ReturnCode rfalListenSetState(rfalLmState newSt) {
 | 
			
		||||
 | 
			
		||||
    gRFAL.Lm.state = newState;
 | 
			
		||||
 | 
			
		||||
    // Call callback on state change
 | 
			
		||||
    if(gRFAL.callbacks.state_changed_cb) {
 | 
			
		||||
        gRFAL.callbacks.state_changed_cb(gRFAL.callbacks.ctx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,6 @@
 | 
			
		||||
#include "mifare_ultralight.h"
 | 
			
		||||
#include <furi.h>
 | 
			
		||||
#include <furi_hal_nfc.h>
 | 
			
		||||
 | 
			
		||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
 | 
			
		||||
    if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
 | 
			
		||||
@ -154,6 +156,7 @@ 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;
 | 
			
		||||
@ -197,11 +200,15 @@ void mf_ul_protect_auth_data_on_read_command(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
bool mf_ul_prepare_emulation_response(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t len_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    MifareUlDevice* mf_ul_emulate) {
 | 
			
		||||
    uint16_t* buff_tx_len,
 | 
			
		||||
    uint32_t* data_type,
 | 
			
		||||
    void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    MifareUlDevice* mf_ul_emulate = context;
 | 
			
		||||
    uint8_t cmd = buff_rx[0];
 | 
			
		||||
    uint16_t page_num = mf_ul_emulate->data.data_size / 4;
 | 
			
		||||
    uint16_t tx_bytes = 0;
 | 
			
		||||
@ -211,12 +218,13 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
    // Check composite commands
 | 
			
		||||
    if(mf_ul_emulate->comp_write_cmd_started) {
 | 
			
		||||
        // Compatibility write is the only one composit command
 | 
			
		||||
        if(len_rx == 16) {
 | 
			
		||||
        if(buff_rx_len == 16) {
 | 
			
		||||
            memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4);
 | 
			
		||||
            mf_ul_emulate->data_changed = true;
 | 
			
		||||
            // Send ACK message
 | 
			
		||||
            buff_tx[0] = 0x0A;
 | 
			
		||||
            tx_bits = 4;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_RAW;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
        mf_ul_emulate->comp_write_cmd_started = false;
 | 
			
		||||
@ -224,6 +232,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
        if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) {
 | 
			
		||||
            tx_bytes = sizeof(mf_ul_emulate->data.version);
 | 
			
		||||
            memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes);
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_READ_CMD) {
 | 
			
		||||
@ -243,6 +252,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
            }
 | 
			
		||||
            mf_ul_protect_auth_data_on_read_command(
 | 
			
		||||
                buff_tx, start_page, (start_page + 4), mf_ul_emulate);
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_FAST_READ_CMD) {
 | 
			
		||||
@ -254,6 +264,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
                memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes);
 | 
			
		||||
                mf_ul_protect_auth_data_on_read_command(
 | 
			
		||||
                    buff_tx, start_page, end_page, mf_ul_emulate);
 | 
			
		||||
                *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
                command_parsed = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -265,6 +276,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
            // ACK
 | 
			
		||||
            buff_tx[0] = 0x0A;
 | 
			
		||||
            tx_bits = 4;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_RAW;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_COMP_WRITE) {
 | 
			
		||||
@ -275,6 +287,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
            // ACK
 | 
			
		||||
            buff_tx[0] = 0x0A;
 | 
			
		||||
            tx_bits = 4;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_RAW;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_READ_CNT) {
 | 
			
		||||
@ -284,6 +297,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
            buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8;
 | 
			
		||||
            buff_tx[2] = mf_ul_emulate->data.counter[cnt_num];
 | 
			
		||||
            tx_bytes = 3;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_INC_CNT) {
 | 
			
		||||
@ -295,6 +309,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
            // ACK
 | 
			
		||||
            buff_tx[0] = 0x0A;
 | 
			
		||||
            tx_bits = 4;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_RAW;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_AUTH) {
 | 
			
		||||
@ -303,11 +318,13 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
                buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0];
 | 
			
		||||
                buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1];
 | 
			
		||||
                tx_bytes = 2;
 | 
			
		||||
                *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
                command_parsed = true;
 | 
			
		||||
            } else if(!mf_ul_emulate->auth_data->pack.value) {
 | 
			
		||||
                buff_tx[0] = 0x80;
 | 
			
		||||
                buff_tx[1] = 0x80;
 | 
			
		||||
                tx_bytes = 2;
 | 
			
		||||
                *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
                command_parsed = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -316,6 +333,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
        if(buff_rx[1] == 0x00) {
 | 
			
		||||
            tx_bytes = sizeof(mf_ul_emulate->data.signature);
 | 
			
		||||
            memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes);
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_CHECK_TEARING) {
 | 
			
		||||
@ -323,6 +341,7 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
        if(cnt_num < 3) {
 | 
			
		||||
            buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num];
 | 
			
		||||
            tx_bytes = 1;
 | 
			
		||||
            *data_type = FURI_HAL_NFC_TXRX_DEFAULT;
 | 
			
		||||
            command_parsed = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if(cmd == MF_UL_HALT_START) {
 | 
			
		||||
@ -334,10 +353,12 @@ uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
        // Send NACK
 | 
			
		||||
        buff_tx[0] = 0x00;
 | 
			
		||||
        tx_bits = 4;
 | 
			
		||||
        *data_type = FURI_HAL_NFC_TXRX_RAW;
 | 
			
		||||
    }
 | 
			
		||||
    // Return tx buffer size in bits
 | 
			
		||||
    if(tx_bytes) {
 | 
			
		||||
        tx_bits = tx_bytes * 8;
 | 
			
		||||
    }
 | 
			
		||||
    return tx_bits;
 | 
			
		||||
    *buff_tx_len = tx_bits;
 | 
			
		||||
    return tx_bits > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -116,8 +116,10 @@ void mf_ul_parse_fast_read_response(
 | 
			
		||||
uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data);
 | 
			
		||||
 | 
			
		||||
void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data);
 | 
			
		||||
uint16_t mf_ul_prepare_emulation_response(
 | 
			
		||||
bool mf_ul_prepare_emulation_response(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t len_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    MifareUlDevice* mf_ul_emulate);
 | 
			
		||||
    uint16_t* buff_tx_len,
 | 
			
		||||
    uint32_t* data_type,
 | 
			
		||||
    void* context);
 | 
			
		||||
							
								
								
									
										32
									
								
								lib/nfc_protocols/nfca.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								lib/nfc_protocols/nfca.c
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#include "nfca.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#define NFCA_CMD_RATS (0xE0U)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t cmd;
 | 
			
		||||
    uint8_t param;
 | 
			
		||||
} nfca_cmd_rats;
 | 
			
		||||
 | 
			
		||||
static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00};
 | 
			
		||||
 | 
			
		||||
static uint8_t nfca_sleep_req[] = {0x50, 0x00};
 | 
			
		||||
 | 
			
		||||
bool nfca_emulation_handler(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    uint16_t* buff_tx_len) {
 | 
			
		||||
    bool sleep = false;
 | 
			
		||||
    uint8_t rx_bytes = buff_rx_len / 8;
 | 
			
		||||
 | 
			
		||||
    if(rx_bytes == sizeof(nfca_sleep_req) && !memcmp(buff_rx, nfca_sleep_req, rx_bytes)) {
 | 
			
		||||
        sleep = true;
 | 
			
		||||
    } else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) {
 | 
			
		||||
        memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats));
 | 
			
		||||
        *buff_tx_len = sizeof(nfca_default_ats) * 8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return sleep;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								lib/nfc_protocols/nfca.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/nfc_protocols/nfca.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
bool nfca_emulation_handler(
 | 
			
		||||
    uint8_t* buff_rx,
 | 
			
		||||
    uint16_t buff_rx_len,
 | 
			
		||||
    uint8_t* buff_tx,
 | 
			
		||||
    uint16_t* buff_tx_len);
 | 
			
		||||
@ -15,9 +15,7 @@
 | 
			
		||||
#define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y))
 | 
			
		||||
 | 
			
		||||
#define SUBGHZ_APP_FOLDER "/any/subghz"
 | 
			
		||||
#define SUBGHZ_APP_PATH_FOLDER "/any/subghz/saved"
 | 
			
		||||
#define SUBGHZ_RAW_FOLDER "/ext/subghz"
 | 
			
		||||
#define SUBGHZ_RAW_PATH_FOLDER "/ext/subghz/saved"
 | 
			
		||||
#define SUBGHZ_APP_EXTENSION ".sub"
 | 
			
		||||
#define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 2048
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								lib/subghz/protocols/subghz_protocol_raw.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										7
									
								
								lib/subghz/protocols/subghz_protocol_raw.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -176,15 +176,10 @@ bool subghz_protocol_raw_save_to_file_init(
 | 
			
		||||
        if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_FOLDER)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        // Create saved directory if necessary
 | 
			
		||||
        if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_PATH_FOLDER)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        string_set(instance->file_name, dev_name);
 | 
			
		||||
        // First remove subghz device file if it was saved
 | 
			
		||||
        string_printf(
 | 
			
		||||
            dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
        string_printf(dev_file_name, "%s/%s%s", SUBGHZ_RAW_FOLDER, dev_name, SUBGHZ_APP_EXTENSION);
 | 
			
		||||
 | 
			
		||||
        if(!storage_simply_remove(instance->storage, string_get_cstr(dev_file_name))) {
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user