Merge branch 'release-candidate' into release
This commit is contained in:
		
						commit
						bb81e86495
					
				| @ -8,7 +8,7 @@ static const char* tab_default_paths[] = { | |||||||
|     [ArchiveTabFavorites] = "/any/favorites", |     [ArchiveTabFavorites] = "/any/favorites", | ||||||
|     [ArchiveTabIButton] = "/any/ibutton", |     [ArchiveTabIButton] = "/any/ibutton", | ||||||
|     [ArchiveTabNFC] = "/any/nfc", |     [ArchiveTabNFC] = "/any/nfc", | ||||||
|     [ArchiveTabSubGhz] = "/any/subghz/saved", |     [ArchiveTabSubGhz] = "/any/subghz", | ||||||
|     [ArchiveTabLFRFID] = "/any/lfrfid", |     [ArchiveTabLFRFID] = "/any/lfrfid", | ||||||
|     [ArchiveTabIrda] = "/any/irda", |     [ArchiveTabIrda] = "/any/irda", | ||||||
|     [ArchiveTabBrowser] = "/any", |     [ArchiveTabBrowser] = "/any", | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "bad_usb_app_i.h" | #include "bad_usb_app_i.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
|  | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
| static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { | static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     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); |     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* bad_usb_app_alloc() { | ||||||
|     BadUsbApp* app = furi_alloc(sizeof(BadUsbApp)); |     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); |     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(); |     app->bad_usb_view = bad_usb_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_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; |     return app; | ||||||
| } | } | ||||||
| @ -58,6 +86,10 @@ void bad_usb_app_free(BadUsbApp* app) { | |||||||
|     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); |     view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); | ||||||
|     bad_usb_free(app->bad_usb_view); |     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
 | ||||||
|     view_dispatcher_free(app->view_dispatcher); |     view_dispatcher_free(app->view_dispatcher); | ||||||
|     scene_manager_free(app->scene_manager); |     scene_manager_free(app->scene_manager); | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ | |||||||
| #include <dialogs/dialogs.h> | #include <dialogs/dialogs.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <gui/modules/variable_item_list.h> | #include <gui/modules/variable_item_list.h> | ||||||
|  | #include <gui/modules/widget.h> | ||||||
| #include "views/bad_usb_view.h" | #include "views/bad_usb_view.h" | ||||||
| 
 | 
 | ||||||
| #define BAD_USB_APP_PATH_FOLDER "/any/badusb" | #define BAD_USB_APP_PATH_FOLDER "/any/badusb" | ||||||
| @ -23,6 +24,7 @@ struct BadUsbApp { | |||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     NotificationApp* notifications; |     NotificationApp* notifications; | ||||||
|     DialogsApp* dialogs; |     DialogsApp* dialogs; | ||||||
|  |     Widget* widget; | ||||||
| 
 | 
 | ||||||
|     char file_name[BAD_USB_FILE_NAME_LEN + 1]; |     char file_name[BAD_USB_FILE_NAME_LEN + 1]; | ||||||
|     BadUsb* bad_usb_view; |     BadUsb* bad_usb_view; | ||||||
| @ -30,6 +32,7 @@ struct BadUsbApp { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  |     BadUsbAppViewError, | ||||||
|     BadUsbAppViewFileSelect, |     BadUsbAppViewFileSelect, | ||||||
|     BadUsbAppViewWork, |     BadUsbAppViewWork, | ||||||
| } BadUsbAppView; | } BadUsbAppView; | ||||||
|  | |||||||
| @ -159,8 +159,6 @@ static bool ducky_altchar(const char* charcode) { | |||||||
|     uint8_t i = 0; |     uint8_t i = 0; | ||||||
|     bool state = false; |     bool state = false; | ||||||
| 
 | 
 | ||||||
|     //TODO: numlock
 |  | ||||||
| 
 |  | ||||||
|     FURI_LOG_I(WORKER_TAG, "char %s", charcode); |     FURI_LOG_I(WORKER_TAG, "char %s", charcode); | ||||||
| 
 | 
 | ||||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); |     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); | ||||||
|  | |||||||
| @ -1,2 +1,3 @@ | |||||||
| ADD_SCENE(bad_usb, file_select, FileSelect) | ADD_SCENE(bad_usb, file_select, FileSelect) | ||||||
| ADD_SCENE(bad_usb, work, Work) | 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; |     BadUsbApp* bad_usb = context; | ||||||
| 
 | 
 | ||||||
|     if(bad_usb_file_select(bad_usb)) { |     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 { |     } else { | ||||||
|         //scene_manager_previous_scene(bad_usb->scene_manager);
 |         //scene_manager_previous_scene(bad_usb->scene_manager);
 | ||||||
|         view_dispatcher_stop(bad_usb->view_dispatcher); |         view_dispatcher_stop(bad_usb->view_dispatcher); | ||||||
|  | |||||||
| @ -594,7 +594,6 @@ void elements_text_box( | |||||||
|             line[line_num].height = line_height; |             line[line_num].height = line_height; | ||||||
|             line[line_num].descender = line_descender; |             line[line_num].descender = line_descender; | ||||||
|             if(total_height_min + line_leading_min > height) { |             if(total_height_min + line_leading_min > height) { | ||||||
|                 line_num--; |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             total_height_min += line_leading_min; |             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 free_pixel_num = height - total_height_min; | ||||||
|             uint8_t fill_pixel = 0; |             uint8_t fill_pixel = 0; | ||||||
|             uint8_t j = 1; |             uint8_t j = 1; | ||||||
|             line[0].y = line[0].height; |             line[0].y = y + line[0].height; | ||||||
|             while(fill_pixel < free_pixel_num) { |             while(fill_pixel < free_pixel_num) { | ||||||
|                 line[j].y = line[j - 1].y + line[j - 1].leading_min + 1; |                 line[j].y = line[j - 1].y + line[j - 1].leading_min + 1; | ||||||
|                 fill_pixel++; |                 fill_pixel++; | ||||||
|  | |||||||
| @ -7,17 +7,16 @@ | |||||||
| 
 | 
 | ||||||
| struct TextBox { | struct TextBox { | ||||||
|     View* view; |     View* view; | ||||||
|     void* context; |  | ||||||
|     TextBoxExitCallback callback; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     const char* text; |     const char* text; | ||||||
|     char* text_pos; |     char* text_pos; | ||||||
|     string_t text_formatted; |     string_t text_formatted; | ||||||
|     size_t scroll_pos; |     int32_t scroll_pos; | ||||||
|     size_t scroll_num; |     int32_t scroll_num; | ||||||
|     TextBoxFont font; |     TextBoxFont font; | ||||||
|  |     TextBoxFocus focus; | ||||||
|     bool formatted; |     bool formatted; | ||||||
| } TextBoxModel; | } 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) { | static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { | ||||||
|     size_t i = 0; |     size_t i = 0; | ||||||
|     size_t line_width = 0; |     size_t line_width = 0; | ||||||
| @ -84,8 +77,18 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { | |||||||
|     line_num++; |     line_num++; | ||||||
|     model->text = string_get_cstr(model->text_formatted); |     model->text = string_get_cstr(model->text_formatted); | ||||||
|     model->text_pos = (char*)model->text; |     model->text_pos = (char*)model->text; | ||||||
|     model->scroll_num = MAX(line_num - 4, 0); |     if(model->focus == TextBoxFocusEnd && line_num > 5) { | ||||||
|     model->scroll_pos = 0; |         // 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) { | 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) { |         } else if(event->key == InputKeyUp) { | ||||||
|             text_box_process_up(text_box); |             text_box_process_up(text_box); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event->key == InputKeyBack) { |  | ||||||
|             text_box_process_back(text_box); |  | ||||||
|             consumed = true; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
| @ -172,10 +172,9 @@ void text_box_reset(TextBox* text_box) { | |||||||
|             model->text = NULL; |             model->text = NULL; | ||||||
|             string_set_str(model->text_formatted, ""); |             string_set_str(model->text_formatted, ""); | ||||||
|             model->font = TextBoxFontText; |             model->font = TextBoxFontText; | ||||||
|  |             model->focus = TextBoxFocusStart; | ||||||
|             return true; |             return true; | ||||||
|         }); |         }); | ||||||
|     text_box->context = NULL; |  | ||||||
|     text_box->callback = NULL; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void text_box_set_text(TextBox* text_box, const char* text) { | 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( |     with_view_model( | ||||||
|         text_box->view, (TextBoxModel * model) { |         text_box->view, (TextBoxModel * model) { | ||||||
|             model->text = text; |             model->text = text; | ||||||
|  |             string_reset(model->text_formatted); | ||||||
|             string_reserve(model->text_formatted, strlen(text)); |             string_reserve(model->text_formatted, strlen(text)); | ||||||
|             model->formatted = false; |             model->formatted = false; | ||||||
|             return true; |             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); |     furi_assert(text_box); | ||||||
|     text_box->context = context; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback) { |     with_view_model( | ||||||
|     furi_assert(text_box); |         text_box->view, (TextBoxModel * model) { | ||||||
|     text_box->callback = callback; |             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 */ | /** TextBox anonymous structure */ | ||||||
| typedef struct TextBox TextBox; | typedef struct TextBox TextBox; | ||||||
| typedef void (*TextBoxExitCallback)(void* context); |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     TextBoxFontText, |     TextBoxFontText, | ||||||
|     TextBoxFontHex, |     TextBoxFontHex, | ||||||
| } TextBoxFont; | } TextBoxFont; | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     TextBoxFocusStart, | ||||||
|  |     TextBoxFocusEnd, | ||||||
|  | } TextBoxFocus; | ||||||
|  | 
 | ||||||
| /** Allocate and initialize text_box
 | /** Allocate and initialize text_box
 | ||||||
|  * |  * | ||||||
|  * @return     TextBox instance |  * @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); | 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      text_box  TextBox instance | ||||||
|  * @param      context   context pointer |  * @param      focus     TextBoxFocus instance | ||||||
|  */ |  */ | ||||||
| void text_box_set_context(TextBox* text_box, void* context); | void text_box_set_focus(TextBox* text_box, TextBoxFocus focus); | ||||||
| 
 |  | ||||||
| /** Set exit callback
 |  | ||||||
|  * |  | ||||||
|  * @param      text_box  TextBox instance |  | ||||||
|  * @param      callback  TextBoxExitCallback callback pointer |  | ||||||
|  */ |  | ||||||
| void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback); |  | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -68,7 +68,7 @@ Widget* widget_alloc() { | |||||||
|     return widget; |     return widget; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void widget_clear(Widget* widget) { | void widget_reset(Widget* widget) { | ||||||
|     furi_assert(widget); |     furi_assert(widget); | ||||||
| 
 | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
| @ -89,7 +89,7 @@ void widget_clear(Widget* widget) { | |||||||
| void widget_free(Widget* widget) { | void widget_free(Widget* widget) { | ||||||
|     furi_assert(widget); |     furi_assert(widget); | ||||||
|     // Free all elements
 |     // Free all elements
 | ||||||
|     widget_clear(widget); |     widget_reset(widget); | ||||||
|     // Free elements container
 |     // Free elements container
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         widget->view, (GuiWidgetModel * model) { |         widget->view, (GuiWidgetModel * model) { | ||||||
|  | |||||||
| @ -27,11 +27,11 @@ Widget* widget_alloc(); | |||||||
|  */ |  */ | ||||||
| void widget_free(Widget* widget); | void widget_free(Widget* widget); | ||||||
| 
 | 
 | ||||||
| /** Clear Widget
 | /** Reset Widget
 | ||||||
|  * |  * | ||||||
|  * @param      widget  Widget instance |  * @param      widget  Widget instance | ||||||
|  */ |  */ | ||||||
| void widget_clear(Widget* widget); | void widget_reset(Widget* widget); | ||||||
| 
 | 
 | ||||||
| /** Get Widget view
 | /** Get Widget view
 | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ void iButtonSceneDeleteConfirm::on_exit(iButtonApp* app) { | |||||||
| 
 | 
 | ||||||
|     app->set_text_store(""); |     app->set_text_store(""); | ||||||
| 
 | 
 | ||||||
|     widget_clear(widget); |     widget_reset(widget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iButtonSceneDeleteConfirm::widget_callback( | void iButtonSceneDeleteConfirm::widget_callback( | ||||||
|  | |||||||
| @ -69,7 +69,7 @@ void iButtonSceneInfo::on_exit(iButtonApp* app) { | |||||||
| 
 | 
 | ||||||
|     app->set_text_store(""); |     app->set_text_store(""); | ||||||
| 
 | 
 | ||||||
|     widget_clear(widget); |     widget_reset(widget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void iButtonSceneInfo::widget_callback(GuiButtonType result, InputType type, void* context) { | void iButtonSceneInfo::widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|  | |||||||
| @ -159,7 +159,7 @@ class IrdaAppSceneUniversalTV : public IrdaAppSceneUniversalCommon { | |||||||
| public: | public: | ||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     IrdaAppSceneUniversalTV() |     IrdaAppSceneUniversalTV() | ||||||
|         : IrdaAppSceneUniversalCommon("/ext/irda/universal/tv.ir") { |         : IrdaAppSceneUniversalCommon("/ext/irda/assets/tv.ir") { | ||||||
|     } |     } | ||||||
|     ~IrdaAppSceneUniversalTV() { |     ~IrdaAppSceneUniversalTV() { | ||||||
|     } |     } | ||||||
| @ -169,7 +169,7 @@ class IrdaAppSceneUniversalAudio : public IrdaAppSceneUniversalCommon { | |||||||
| public: | public: | ||||||
|     void on_enter(IrdaApp* app) final; |     void on_enter(IrdaApp* app) final; | ||||||
|     IrdaAppSceneUniversalAudio() |     IrdaAppSceneUniversalAudio() | ||||||
|         : IrdaAppSceneUniversalCommon("/ext/irda/universal/audio.ir") { |         : IrdaAppSceneUniversalCommon("/ext/irda/assets/audio.ir") { | ||||||
|     } |     } | ||||||
|     ~IrdaAppSceneUniversalAudio() { |     ~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++) { |     for(uint8_t i = 0; i < aid_len; i++) { | ||||||
|         string_cat_printf(key, "%02X", aid[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; |         parsed = true; | ||||||
|     } |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
| @ -58,7 +58,7 @@ bool nfc_emv_parser_get_country_name( | |||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     string_t key; |     string_t key; | ||||||
|     string_init_printf(key, "%04X", country_code); |     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; |         parsed = true; | ||||||
|     } |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
| @ -72,7 +72,8 @@ bool nfc_emv_parser_get_currency_name( | |||||||
|     bool parsed = false; |     bool parsed = false; | ||||||
|     string_t key; |     string_t key; | ||||||
|     string_init_printf(key, "%04X", currency_code); |     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; |         parsed = true; | ||||||
|     } |     } | ||||||
|     string_clear(key); |     string_clear(key); | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| 
 | 
 | ||||||
| #define NFC_DEV_NAME_MAX_LEN 22 | #define NFC_DEV_NAME_MAX_LEN 22 | ||||||
| #define NFC_FILE_NAME_MAX_LEN 120 | #define NFC_FILE_NAME_MAX_LEN 120 | ||||||
|  | #define NFC_READER_DATA_MAX_SIZE 64 | ||||||
| 
 | 
 | ||||||
| #define NFC_APP_FOLDER "/any/nfc" | #define NFC_APP_FOLDER "/any/nfc" | ||||||
| #define NFC_APP_EXTENSION ".nfc" | #define NFC_APP_EXTENSION ".nfc" | ||||||
| @ -54,11 +55,17 @@ typedef struct { | |||||||
|     uint16_t currency_code; |     uint16_t currency_code; | ||||||
| } NfcEmvData; | } NfcEmvData; | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t data[NFC_READER_DATA_MAX_SIZE]; | ||||||
|  |     uint16_t size; | ||||||
|  | } NfcReaderRequestData; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     NfcDeviceCommonData nfc_data; |     NfcDeviceCommonData nfc_data; | ||||||
|     union { |     union { | ||||||
|         NfcEmvData emv_data; |         NfcEmvData emv_data; | ||||||
|         MifareUlData mf_ul_data; |         MifareUlData mf_ul_data; | ||||||
|  |         NfcReaderRequestData reader_data; | ||||||
|     }; |     }; | ||||||
| } NfcDeviceData; | } NfcDeviceData; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ | |||||||
| #include "views/bank_card.h" | #include "views/bank_card.h" | ||||||
| 
 | 
 | ||||||
| #include <nfc/scenes/nfc_scene.h> | #include <nfc/scenes/nfc_scene.h> | ||||||
|  | #include <nfc/helpers/nfc_custom_event.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_SEND_NOTIFICATION_FALSE (0UL) | #define NFC_SEND_NOTIFICATION_FALSE (0UL) | ||||||
| #define NFC_SEND_NOTIFICATION_TRUE (1UL) | #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) { |     if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 |     furi_hal_nfc_stop(); | ||||||
|     nfc_worker_change_state(nfc_worker, NfcWorkerStateStop); |     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) { | void nfc_worker_emulate(NfcWorker* nfc_worker) { | ||||||
|     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; |     NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulate) { |     while(nfc_worker->state == NfcWorkerStateEmulate) { | ||||||
|         if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { |         furi_hal_nfc_emulate_nfca( | ||||||
|             FURI_LOG_D(TAG, "Reader detected"); |             data->uid, | ||||||
|         } |             data->uid_len, | ||||||
|         osDelay(10); |             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) { | void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||||
|     ReturnCode err; |     NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data; | ||||||
|     uint8_t tx_buff[255] = {}; |  | ||||||
|     uint16_t tx_len = 0; |  | ||||||
|     uint8_t* rx_buff; |  | ||||||
|     uint16_t* rx_len; |  | ||||||
|     NfcDeviceData* data = nfc_worker->dev_data; |  | ||||||
|     MifareUlDevice mf_ul_emulate; |     MifareUlDevice mf_ul_emulate; | ||||||
|     // Setup emulation parameters from mifare ultralight data structure
 |     mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data); | ||||||
|     mf_ul_prepare_emulation(&mf_ul_emulate, &data->mf_ul_data); |  | ||||||
|     while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { |     while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { | ||||||
|         // WARNING
 |         furi_hal_nfc_emulate_nfca( | ||||||
|         // DO NOT call any blocking functions (e.g. FURI_LOG_*) in this loop,
 |             nfc_common->uid, | ||||||
|         // as any delay will negatively affect the stability of the emulation.
 |             nfc_common->uid_len, | ||||||
|         if(furi_hal_nfc_listen( |             nfc_common->atqa, | ||||||
|                data->nfc_data.uid, |             nfc_common->sak, | ||||||
|                data->nfc_data.uid_len, |             mf_ul_prepare_emulation_response, | ||||||
|                data->nfc_data.atqa, |             &mf_ul_emulate, | ||||||
|                data->nfc_data.sak, |             5000); | ||||||
|                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(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         // Check if data was modified
 |         // Check if data was modified
 | ||||||
|         if(mf_ul_emulate.data_changed) { |         if(mf_ul_emulate.data_changed) { | ||||||
|             nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; |             nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; | ||||||
|             if(nfc_worker->callback) { |             if(nfc_worker->callback) { | ||||||
|                 nfc_worker->callback(nfc_worker->context); |                 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) { | void nfc_scene_delete_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     widget_clear(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,10 +1,8 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_delete_success_popup_callback(void* context) { | void nfc_scene_delete_success_popup_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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( |             return scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 nfc->scene_manager, NfcSceneStart); |                 nfc->scene_manager, NfcSceneStart); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include "../helpers/nfc_emv_parser.h" | #include "../helpers/nfc_emv_parser.h" | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| enum { | enum { | ||||||
|     NfcSceneDeviceInfoUid, |     NfcSceneDeviceInfoUid, | ||||||
|     NfcSceneDeviceInfoData, |     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) { | void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |     if(result == DialogExResultLeft) { | ||||||
| } |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
| 
 |     } | ||||||
| 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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) { | void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     if(type == InputTypeShort) { |     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) { |     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|         MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; |         MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|         TextBox* text_box = nfc->text_box; |         TextBox* text_box = nfc->text_box; | ||||||
|         text_box_set_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); |         text_box_set_font(text_box, TextBoxFontHex); | ||||||
|         for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { |         for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { | ||||||
|             if(!(i % 8) && i) { |             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); |                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); | ||||||
|                 consumed = true; |                 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( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |                 nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |             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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     // Clear Custom Widget
 |     // Clear Custom Widget
 | ||||||
|     widget_clear(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| 
 | 
 | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { |     if(nfc->dev->format == NfcDeviceSaveFormatUid) { | ||||||
|         // Clear Dialog
 |         // Clear Dialog
 | ||||||
|  | |||||||
| @ -1,61 +1,139 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.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) { | void nfc_scene_emulate_uid_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcEmulate); |     DOLPHIN_DEED(DolphinDeedNfcEmulate); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup Widget
 | ||||||
|     Popup* popup = nfc->popup; |     nfc_scene_emulate_uid_widget_config(nfc, false); | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     // 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, "")) { |     // Set Widget state and view
 | ||||||
|         nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); |     scene_manager_set_scene_state( | ||||||
|     } else if(data->uid_len == 4) { |         nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); | ||||||
|         nfc_text_store_set( |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|             nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]); |     // Start worker
 | ||||||
|     } else if(data->uid_len == 7) { |     memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); | ||||||
|         nfc_text_store_set( |     nfc_worker_start( | ||||||
|             nfc, |         nfc->worker, | ||||||
|             "%02X %02X %02X %02X\n%02X %02X %02X", |         NfcWorkerStateEmulate, | ||||||
|             data->uid[0], |         &nfc->dev->dev_data, | ||||||
|             data->uid[1], |         nfc_emulate_uid_worker_callback, | ||||||
|             data->uid[2], |         nfc); | ||||||
|             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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { | 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) { |     if(event.type == SceneManagerEventTypeTick) { | ||||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); |         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); | ||||||
|  |             } | ||||||
|  |             // 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 false; | 
 | ||||||
|  |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_emulate_uid_on_exit(void* context) { | void nfc_scene_emulate_uid_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Stop worker
 |     // Stop worker
 | ||||||
|     nfc_worker_stop(nfc->worker); |     nfc_worker_stop(nfc->worker); | ||||||
| 
 | 
 | ||||||
|     // Clear view
 |     // Clear view
 | ||||||
|     Popup* popup = nfc->popup; |     widget_reset(nfc->widget); | ||||||
|     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); |     text_box_reset(nfc->text_box); | ||||||
|     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); |     string_reset(nfc->text_box_store); | ||||||
|     popup_set_icon(popup, 0, 0, NULL); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_READ_CARD_CUSTOM_EVENT (10UL) |  | ||||||
| 
 |  | ||||||
| void nfc_read_card_worker_callback(void* context) { | void nfc_read_card_worker_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NFC_READ_CARD_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||||
|             return true; |             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) { | void nfc_scene_read_card_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
|     widget_clear(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_READ_EMV_APP_CUSTOM_EVENT (10UL) |  | ||||||
| 
 |  | ||||||
| void nfc_read_emv_app_worker_callback(void* context) { | void nfc_read_emv_app_worker_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NFC_READ_EMV_APP_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); |                 nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_READ_EMV_DATA_CUSTOM_EVENT (10UL) |  | ||||||
| 
 |  | ||||||
| void nfc_read_emv_data_worker_callback(void* context) { | void nfc_read_emv_data_worker_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NFC_READ_EMV_DATA_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventWorkerExit) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); |                 nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); | ||||||
|  | |||||||
| @ -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) { | void nfc_scene_read_emv_data_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     widget_clear(nfc->widget); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_READ_MIFARE_UL_CUSTOM_EVENT (10UL) |  | ||||||
| 
 |  | ||||||
| void nfc_read_mifare_ul_worker_callback(void* context) { | void nfc_read_mifare_ul_worker_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | ||||||
| #define NFC_SCENE_READ_MF_UL_CUSTOM_EVENT (0UL) |  | ||||||
| 
 | 
 | ||||||
| enum { | enum { | ||||||
|     ReadMifareUlStateShowUID, |     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); |     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) { | void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (Nfc*)context; | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| @ -59,8 +52,6 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup TextBox view
 |     // Setup TextBox view
 | ||||||
|     TextBox* text_box = nfc->text_box; |     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); |     text_box_set_font(text_box, TextBoxFontHex); | ||||||
|     for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { |     for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { | ||||||
|         if(!(i % 8) && i) { |         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) { | 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(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if((scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == |         if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { | ||||||
|             ReadMifareUlStateShowUID) && |  | ||||||
|            (event.event == DialogExResultLeft)) { |  | ||||||
|             scene_manager_previous_scene(nfc->scene_manager); |             scene_manager_previous_scene(nfc->scene_manager); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else if( |         } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) { | ||||||
|             (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == |  | ||||||
|              ReadMifareUlStateShowUID) && |  | ||||||
|             (event.event == DialogExResultRight)) { |  | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else if( |         } else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) { | ||||||
|             (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == |  | ||||||
|              ReadMifareUlStateShowUID) && |  | ||||||
|             (event.event == DialogExResultCenter)) { |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData); |                 nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData); | ||||||
|             return true; |             consumed = true; | ||||||
|         } else if( |         } | ||||||
|             (scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess) == |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|              ReadMifareUlStateShowData) && |         if(state == ReadMifareUlStateShowData) { | ||||||
|             (event.event == NFC_SCENE_READ_MF_UL_CUSTOM_EVENT)) { |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); |                 nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID); | ||||||
|             return true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return false; | 
 | ||||||
|  |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_read_mifare_ul_success_on_exit(void* context) { | void nfc_scene_read_mifare_ul_success_on_exit(void* context) { | ||||||
|  | |||||||
| @ -1,10 +1,8 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_restore_original_popup_callback(void* context) { | void nfc_scene_restore_original_popup_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_RESTORE_ORIGINAL_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventViewExit) { | ||||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); |             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,12 +2,10 @@ | |||||||
| #include <lib/toolbox/random_name.h> | #include <lib/toolbox/random_name.h> | ||||||
| #include <gui/modules/validators.h> | #include <gui/modules/validators.h> | ||||||
| 
 | 
 | ||||||
| #define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_save_name_text_input_callback(void* context) { | void nfc_scene_save_name_text_input_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventTextInputDone) { | ||||||
|             if(strcmp(nfc->dev->dev_name, "")) { |             if(strcmp(nfc->dev->dev_name, "")) { | ||||||
|                 nfc_device_delete(nfc->dev); |                 nfc_device_delete(nfc->dev); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define SCENE_SAVE_SUCCESS_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_save_success_popup_callback(void* context) { | void nfc_scene_save_success_popup_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)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) { | 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; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     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)) { |             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) { | ||||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|                     nfc->scene_manager, NfcSceneCardMenu); |                     nfc->scene_manager, NfcSceneCardMenu); | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define SCENE_SET_ATQA_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_set_atqa_byte_input_callback(void* context) { | void nfc_scene_set_atqa_byte_input_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SET_ATQA_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| 
 | 
 | ||||||
| #define SCENE_SET_SAK_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_set_sak_byte_input_callback(void* context) { | void nfc_scene_set_sak_byte_input_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SET_SAK_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,12 +1,10 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define SCENE_SET_UID_CUSTOM_EVENT (0UL) |  | ||||||
| 
 |  | ||||||
| void nfc_scene_set_uid_byte_input_callback(void* context) { | void nfc_scene_set_uid_byte_input_callback(void* context) { | ||||||
|     Nfc* nfc = (Nfc*)context; |     Nfc* nfc = (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) { | 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; |     Nfc* nfc = (Nfc*)context; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == SCENE_SET_UID_CUSTOM_EVENT) { |         if(event.event == NfcCustomEventByteInputDone) { | ||||||
|             DOLPHIN_DEED(DolphinDeedNfcAdd); |             DOLPHIN_DEED(DolphinDeedNfcAdd); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             return true; |             return true; | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ View* bank_card_get_view(BankCard* bank_card) { | |||||||
| 
 | 
 | ||||||
| void bank_card_clear(BankCard* bank_card) { | void bank_card_clear(BankCard* bank_card) { | ||||||
|     furi_assert(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) { | 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) { | void subghz_scene_delete_on_exit(void* context) { | ||||||
|     SubGhz* subghz = 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) { | void subghz_scene_delete_raw_on_exit(void* context) { | ||||||
|     SubGhz* subghz = 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) { | void subghz_scene_need_saving_on_exit(void* context) { | ||||||
|     SubGhz* subghz = 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); |         path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); | ||||||
|         strcpy(subghz->file_name, string_get_cstr(temp_str)); |         strcpy(subghz->file_name, string_get_cstr(temp_str)); | ||||||
|         string_printf( |         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( |         subghz_protocol_raw_set_last_file_name( | ||||||
|             (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str)); |             (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) { | void subghz_scene_receiver_info_on_exit(void* context) { | ||||||
|     SubGhz* subghz = 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); |         dev_name_empty); | ||||||
| 
 | 
 | ||||||
|     ValidatorIsFile* validator_is_file = |     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); |     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput); |     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; |     SubGhz* subghz = context; | ||||||
|     scene_manager_set_scene_state( |     scene_manager_set_scene_state( | ||||||
|         subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet); |         subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet); | ||||||
|     widget_clear(subghz->widget); |     widget_reset(subghz->widget); | ||||||
|     string_reset(subghz->error_str); |     string_reset(subghz->error_str); | ||||||
| } | } | ||||||
|  | |||||||
| @ -284,10 +284,10 @@ int32_t subghz_app(void* p) { | |||||||
| 
 | 
 | ||||||
|     //Load database
 |     //Load database
 | ||||||
|     bool 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/assets/keeloq_mfcodes"); | ||||||
|     subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/keeloq_mfcodes_user"); |     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/nice_flor_s_rx"); |     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/came_atomo"); |     subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/assets/came_atomo"); | ||||||
| 
 | 
 | ||||||
|     // Check argument and run corresponding scene
 |     // Check argument and run corresponding scene
 | ||||||
|     if(p && subghz_key_load(subghz, p)) { |     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); |     furi_check(instance->stream); | ||||||
| 
 | 
 | ||||||
|     SubGhzParser* parser = subghz_parser_alloc(); |     SubGhzParser* parser = subghz_parser_alloc(); | ||||||
|     subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes"); |     subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes"); | ||||||
|     subghz_parser_load_keeloq_file(parser, "/ext/subghz/keeloq_mfcodes_user"); |     subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes_user"); | ||||||
|     subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/nice_flor_s_rx"); |     subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/assets/nice_flor_s_rx"); | ||||||
|     subghz_parser_load_came_atomo_file(parser, "/ext/subghz/came_atomo"); |     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); |     subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance); | ||||||
| 
 | 
 | ||||||
|     // Configure radio
 |     // 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, "")) { |     if(strcmp(subghz->file_name, "")) { | ||||||
|         //get the name of the next free file
 |         //get the name of the next free file
 | ||||||
|         storage_get_next_filename( |         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)); |         strcpy(subghz->file_name, string_get_cstr(temp_str)); | ||||||
|         res = true; |         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"); |             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); | ||||||
|             break; |             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
 |         // First remove subghz device file if it was saved
 | ||||||
|         string_printf( |         string_printf(dev_file_name, "%s/%s%s", SUBGHZ_APP_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); | ||||||
|             dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); |  | ||||||
| 
 | 
 | ||||||
|         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { |         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { | ||||||
|             break; |             break; | ||||||
| @ -386,7 +380,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
|     // Input events and views are managed by file_select
 |     // Input events and views are managed by file_select
 | ||||||
|     bool res = dialog_file_select_show( |     bool res = dialog_file_select_show( | ||||||
|         subghz->dialogs, |         subghz->dialogs, | ||||||
|         SUBGHZ_APP_PATH_FOLDER, |         SUBGHZ_APP_FOLDER, | ||||||
|         SUBGHZ_APP_EXTENSION, |         SUBGHZ_APP_EXTENSION, | ||||||
|         subghz->file_name, |         subghz->file_name, | ||||||
|         sizeof(subghz->file_name), |         sizeof(subghz->file_name), | ||||||
| @ -394,7 +388,7 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { | |||||||
| 
 | 
 | ||||||
|     if(res) { |     if(res) { | ||||||
|         string_printf( |         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)); |         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"); |     Storage* storage = furi_record_open("storage"); | ||||||
| 
 | 
 | ||||||
|     string_init_printf( |     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( |     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 = |     FS_Error fs_result = | ||||||
|         storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); |         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"); |     Storage* storage = furi_record_open("storage"); | ||||||
|     string_t file_path; |     string_t file_path; | ||||||
|     string_init_printf( |     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)); |     bool result = storage_simply_remove(storage, string_get_cstr(file_path)); | ||||||
|     furi_record_close("storage"); |     furi_record_close("storage"); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1 +1,2 @@ | |||||||
| ADD_SCENE(u2f, main, Main) | 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_app_i.h" | ||||||
|  | #include "u2f_data.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| @ -39,11 +40,19 @@ U2fApp* u2f_app_alloc() { | |||||||
| 
 | 
 | ||||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); |     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(); |     app->u2f_view = u2f_view_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         app->view_dispatcher, U2fAppViewMain, u2f_view_get_view(app->u2f_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; |     return app; | ||||||
| } | } | ||||||
| @ -55,6 +64,10 @@ void u2f_app_free(U2fApp* app) { | |||||||
|     view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewMain); |     view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewMain); | ||||||
|     u2f_view_free(app->u2f_view); |     u2f_view_free(app->u2f_view); | ||||||
| 
 | 
 | ||||||
|  |     // Custom Widget
 | ||||||
|  |     view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewError); | ||||||
|  |     widget_free(app->widget); | ||||||
|  | 
 | ||||||
|     // View dispatcher
 |     // View dispatcher
 | ||||||
|     view_dispatcher_free(app->view_dispatcher); |     view_dispatcher_free(app->view_dispatcher); | ||||||
|     scene_manager_free(app->scene_manager); |     scene_manager_free(app->scene_manager); | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
| #include <dialogs/dialogs.h> | #include <dialogs/dialogs.h> | ||||||
| #include <notification/notification_messages.h> | #include <notification/notification_messages.h> | ||||||
| #include <gui/modules/variable_item_list.h> | #include <gui/modules/variable_item_list.h> | ||||||
|  | #include <gui/modules/widget.h> | ||||||
| #include "views/u2f_view.h" | #include "views/u2f_view.h" | ||||||
| #include "u2f_hid.h" | #include "u2f_hid.h" | ||||||
| #include "u2f.h" | #include "u2f.h" | ||||||
| @ -29,9 +30,12 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
|     U2fCustomEventConfirm, |     U2fCustomEventConfirm, | ||||||
| 
 | 
 | ||||||
|  |     U2fCustomEventErrorBack, | ||||||
|  | 
 | ||||||
| } GpioCustomEvent; | } GpioCustomEvent; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|  |     U2fAppViewError, | ||||||
|     U2fAppViewMain, |     U2fAppViewMain, | ||||||
| } U2fAppView; | } U2fAppView; | ||||||
| 
 | 
 | ||||||
| @ -40,6 +44,7 @@ struct U2fApp { | |||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     NotificationApp* notifications; |     NotificationApp* notifications; | ||||||
|  |     Widget* widget; | ||||||
|     osTimerId_t timer; |     osTimerId_t timer; | ||||||
|     U2fHid* u2f_hid; |     U2fHid* u2f_hid; | ||||||
|     U2fView* u2f_view; |     U2fView* u2f_view; | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ | |||||||
| #define TAG "U2F" | #define TAG "U2F" | ||||||
| 
 | 
 | ||||||
| #define U2F_DATA_FOLDER "/any/u2f/" | #define U2F_DATA_FOLDER "/any/u2f/" | ||||||
| #define U2F_CERT_FILE U2F_DATA_FOLDER "cert.der" | #define U2F_CERT_FILE U2F_DATA_FOLDER "assets/cert.der" | ||||||
| #define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "cert_key.u2f" | #define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "assets/cert_key.u2f" | ||||||
| #define U2F_KEY_FILE U2F_DATA_FOLDER "key.u2f" | #define U2F_KEY_FILE U2F_DATA_FOLDER "key.u2f" | ||||||
| #define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f" | #define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f" | ||||||
| 
 | 
 | ||||||
| @ -38,6 +38,26 @@ typedef struct { | |||||||
|     uint32_t control; |     uint32_t control; | ||||||
| } __attribute__((packed)) U2fCounterData; | } __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 u2f_data_cert_check() { | ||||||
|     bool state = false; |     bool state = false; | ||||||
|     Storage* fs_api = furi_record_open("storage"); |     Storage* fs_api = furi_record_open("storage"); | ||||||
|  | |||||||
| @ -6,6 +6,8 @@ extern "C" { | |||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
|  | bool u2f_data_check(); | ||||||
|  | 
 | ||||||
| bool u2f_data_cert_check(); | bool u2f_data_cert_check(); | ||||||
| 
 | 
 | ||||||
| uint32_t u2f_data_cert_load(uint8_t* cert); | 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!"); |             canvas, 128 / 2, 3, AlignCenter, AlignTop, "Authentication successfull!"); | ||||||
|     } else if(model->display_msg == U2fMsgError) { |     } else if(model->display_msg == U2fMsgError) { | ||||||
|         canvas_draw_icon(canvas, 22, 15, &I_Error_62x31); |         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/>. | along with PyCortexMDebug.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| import sys |  | ||||||
| from collections import OrderedDict | from collections import OrderedDict | ||||||
| import os | from . import x2d | ||||||
| import pickle | 
 | ||||||
| import traceback | import traceback | ||||||
| import re |  | ||||||
| import warnings | import warnings | ||||||
| import x2d | import pickle | ||||||
|  | import sys | ||||||
|  | import os | ||||||
|  | import re | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class SmartDict: | 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 "furi_hal_nfc.h" | ||||||
| #include <st25r3916.h> | #include <st25r3916.h> | ||||||
|  | #include <rfal_rf.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <lib/nfc_protocols/nfca.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalNfc" | #define TAG "FuriHalNfc" | ||||||
| 
 | 
 | ||||||
| static const uint32_t clocks_in_ms = 64 * 1000; | 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() { | void furi_hal_nfc_init() { | ||||||
|     ReturnCode ret = rfalNfcInitialize(); |     ReturnCode ret = rfalNfcInitialize(); | ||||||
|     if(ret == ERR_NONE) { |     if(ret == ERR_NONE) { | ||||||
|         furi_hal_nfc_start_sleep(); |         furi_hal_nfc_start_sleep(); | ||||||
|  |         event = osEventFlagsNew(NULL); | ||||||
|         FURI_LOG_I(TAG, "Init OK"); |         FURI_LOG_I(TAG, "Init OK"); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); |         FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); | ||||||
| @ -140,6 +151,126 @@ bool furi_hal_nfc_listen( | |||||||
|     return true; |     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) { | bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | ||||||
|     ReturnCode ret = |     ReturnCode ret = | ||||||
|         rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); |         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 "furi_hal_nfc.h" | ||||||
| #include <st25r3916.h> | #include <st25r3916.h> | ||||||
|  | #include <rfal_rf.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <lib/nfc_protocols/nfca.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalNfc" | #define TAG "FuriHalNfc" | ||||||
| 
 | 
 | ||||||
| static const uint32_t clocks_in_ms = 64 * 1000; | 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() { | void furi_hal_nfc_init() { | ||||||
|     ReturnCode ret = rfalNfcInitialize(); |     ReturnCode ret = rfalNfcInitialize(); | ||||||
|     if(ret == ERR_NONE) { |     if(ret == ERR_NONE) { | ||||||
|         furi_hal_nfc_start_sleep(); |         furi_hal_nfc_start_sleep(); | ||||||
|  |         event = osEventFlagsNew(NULL); | ||||||
|         FURI_LOG_I(TAG, "Init OK"); |         FURI_LOG_I(TAG, "Init OK"); | ||||||
|     } else { |     } else { | ||||||
|         FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); |         FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); | ||||||
| @ -140,6 +151,126 @@ bool furi_hal_nfc_listen( | |||||||
|     return true; |     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) { | bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | ||||||
|     ReturnCode ret = |     ReturnCode ret = | ||||||
|         rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); |         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_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
 | /** Init nfc
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_nfc_init(); | void furi_hal_nfc_init(); | ||||||
| @ -76,6 +96,15 @@ bool furi_hal_nfc_listen( | |||||||
|     bool activate_after_sak, |     bool activate_after_sak, | ||||||
|     uint32_t timeout); |     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
 | /** Get first command from reader after activation in emulation mode
 | ||||||
|  * |  * | ||||||
|  * @param      rx_buff  pointer to receive buffer |  * @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_deactivate(); | ||||||
| 
 | 
 | ||||||
|  | void furi_hal_nfc_stop(); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -545,10 +545,13 @@ typedef struct { | |||||||
| typedef void (*rfalUpperLayerCallback)(void); | typedef void (*rfalUpperLayerCallback)(void); | ||||||
| 
 | 
 | ||||||
| /*! Callback to be executed before a Transceive                              */ | /*! Callback to be executed before a Transceive                              */ | ||||||
| typedef void (*rfalPreTxRxCallback)(void); | typedef void (*rfalPreTxRxCallback)(void* context); | ||||||
| 
 | 
 | ||||||
| /*! Callback to be executed after a Transceive                               */ | /*! 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                                                                  */ | /*  ISO14443A                                                                  */ | ||||||
| @ -819,6 +822,19 @@ void rfalSetPreTxRxCallback(rfalPreTxRxCallback pFunc); | |||||||
|  */ |  */ | ||||||
| void rfalSetPostTxRxCallback(rfalPostTxRxCallback 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 |  * \brief  RFAL Deinitialize | ||||||
| @ -1480,6 +1496,15 @@ ReturnCode rfalTransceiveBlockingTxRx( | |||||||
|     uint32_t flags, |     uint32_t flags, | ||||||
|     uint32_t fwt); |     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                                                              *   |  *  Listen Mode                                                              *   | ||||||
|  *****************************************************************************/ |  *****************************************************************************/ | ||||||
|  | |||||||
| @ -130,6 +130,8 @@ typedef struct { | |||||||
| typedef struct { | typedef struct { | ||||||
|     rfalPreTxRxCallback preTxRx; /*!< RFAL's Pre TxRx callback  */ |     rfalPreTxRxCallback preTxRx; /*!< RFAL's Pre TxRx callback  */ | ||||||
|     rfalPostTxRxCallback postTxRx; /*!< RFAL's Post TxRx callback */ |     rfalPostTxRxCallback postTxRx; /*!< RFAL's Post TxRx callback */ | ||||||
|  |     RfalStateChangedCallback state_changed_cb; | ||||||
|  |     void* ctx; | ||||||
| } rfalCallbacks; | } rfalCallbacks; | ||||||
| 
 | 
 | ||||||
| /*! Struct that holds counters to control the FIFO on Tx and Rx                                                                          */ | /*! 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.preTxRx = NULL; | ||||||
|     gRFAL.callbacks.postTxRx = NULL; |     gRFAL.callbacks.postTxRx = NULL; | ||||||
|  |     gRFAL.callbacks.state_changed_cb = NULL; | ||||||
|  |     gRFAL.callbacks.ctx = NULL; | ||||||
| 
 | 
 | ||||||
| #if RFAL_FEATURE_NFCV | #if RFAL_FEATURE_NFCV | ||||||
|     /* Initialize NFC-V Data */ |     /* Initialize NFC-V Data */ | ||||||
| @ -669,6 +673,14 @@ void rfalSetPostTxRxCallback(rfalPostTxRxCallback pFunc) { | |||||||
|     gRFAL.callbacks.postTxRx = 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) { | ReturnCode rfalDeinitialize(void) { | ||||||
|     /* Deinitialize chip */ |     /* Deinitialize chip */ | ||||||
| @ -1520,6 +1532,30 @@ ReturnCode rfalTransceiveBlockingTx( | |||||||
|     return rfalTransceiveRunBlockingTx(); |     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) { | static ReturnCode rfalTransceiveRunBlockingTx(void) { | ||||||
|     ReturnCode ret; |     ReturnCode ret; | ||||||
| @ -1797,7 +1833,7 @@ static void rfalCleanupTransceive(void) { | |||||||
|     /* Execute Post Transceive Callback                                            */ |     /* Execute Post Transceive Callback                                            */ | ||||||
|     /*******************************************************************************/ |     /*******************************************************************************/ | ||||||
|     if(gRFAL.callbacks.postTxRx != NULL) { |     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                                             */ |     /* Execute Pre Transceive Callback                                             */ | ||||||
|     /*******************************************************************************/ |     /*******************************************************************************/ | ||||||
|     if(gRFAL.callbacks.preTxRx != NULL) { |     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; |     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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,6 @@ | |||||||
| #include "mifare_ultralight.h" | #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) { | bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { | ||||||
|     if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { |     if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { | ||||||
| @ -154,6 +156,7 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) | |||||||
|     mf_ul_emulate->data = *data; |     mf_ul_emulate->data = *data; | ||||||
|     mf_ul_emulate->auth_data = NULL; |     mf_ul_emulate->auth_data = NULL; | ||||||
|     mf_ul_emulate->data_changed = false; |     mf_ul_emulate->data_changed = false; | ||||||
|  |     mf_ul_emulate->comp_write_cmd_started = false; | ||||||
|     if(data->version.storage_size == 0) { |     if(data->version.storage_size == 0) { | ||||||
|         mf_ul_emulate->data.type = MfUltralightTypeUnknown; |         mf_ul_emulate->data.type = MfUltralightTypeUnknown; | ||||||
|         mf_ul_emulate->support_fast_read = false; |         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, |     uint8_t* buff_rx, | ||||||
|     uint16_t len_rx, |     uint16_t buff_rx_len, | ||||||
|     uint8_t* buff_tx, |     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]; |     uint8_t cmd = buff_rx[0]; | ||||||
|     uint16_t page_num = mf_ul_emulate->data.data_size / 4; |     uint16_t page_num = mf_ul_emulate->data.data_size / 4; | ||||||
|     uint16_t tx_bytes = 0; |     uint16_t tx_bytes = 0; | ||||||
| @ -211,12 +218,13 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|     // Check composite commands
 |     // Check composite commands
 | ||||||
|     if(mf_ul_emulate->comp_write_cmd_started) { |     if(mf_ul_emulate->comp_write_cmd_started) { | ||||||
|         // Compatibility write is the only one composit command
 |         // 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); |             memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4); | ||||||
|             mf_ul_emulate->data_changed = true; |             mf_ul_emulate->data_changed = true; | ||||||
|             // Send ACK message
 |             // Send ACK message
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_bits = 4; |             tx_bits = 4; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_RAW; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|         mf_ul_emulate->comp_write_cmd_started = false; |         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) { |         if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) { | ||||||
|             tx_bytes = sizeof(mf_ul_emulate->data.version); |             tx_bytes = sizeof(mf_ul_emulate->data.version); | ||||||
|             memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); |             memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_READ_CMD) { |     } 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( |             mf_ul_protect_auth_data_on_read_command( | ||||||
|                 buff_tx, start_page, (start_page + 4), mf_ul_emulate); |                 buff_tx, start_page, (start_page + 4), mf_ul_emulate); | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_FAST_READ_CMD) { |     } else if(cmd == MF_UL_FAST_READ_CMD) { | ||||||
| @ -254,6 +264,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); |                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); | ||||||
|                 mf_ul_protect_auth_data_on_read_command( |                 mf_ul_protect_auth_data_on_read_command( | ||||||
|                     buff_tx, start_page, end_page, mf_ul_emulate); |                     buff_tx, start_page, end_page, mf_ul_emulate); | ||||||
|  |                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|                 command_parsed = true; |                 command_parsed = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -265,6 +276,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|             // ACK
 |             // ACK
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_bits = 4; |             tx_bits = 4; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_RAW; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_COMP_WRITE) { |     } else if(cmd == MF_UL_COMP_WRITE) { | ||||||
| @ -275,6 +287,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|             // ACK
 |             // ACK
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_bits = 4; |             tx_bits = 4; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_RAW; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_READ_CNT) { |     } 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[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; | ||||||
|             buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; |             buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; | ||||||
|             tx_bytes = 3; |             tx_bytes = 3; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_INC_CNT) { |     } else if(cmd == MF_UL_INC_CNT) { | ||||||
| @ -295,6 +309,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|             // ACK
 |             // ACK
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_bits = 4; |             tx_bits = 4; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_RAW; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_AUTH) { |     } 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[0] = mf_ul_emulate->auth_data->pack.raw[0]; | ||||||
|                 buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; |                 buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; | ||||||
|                 tx_bytes = 2; |                 tx_bytes = 2; | ||||||
|  |                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|                 command_parsed = true; |                 command_parsed = true; | ||||||
|             } else if(!mf_ul_emulate->auth_data->pack.value) { |             } else if(!mf_ul_emulate->auth_data->pack.value) { | ||||||
|                 buff_tx[0] = 0x80; |                 buff_tx[0] = 0x80; | ||||||
|                 buff_tx[1] = 0x80; |                 buff_tx[1] = 0x80; | ||||||
|                 tx_bytes = 2; |                 tx_bytes = 2; | ||||||
|  |                 *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|                 command_parsed = true; |                 command_parsed = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -316,6 +333,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|         if(buff_rx[1] == 0x00) { |         if(buff_rx[1] == 0x00) { | ||||||
|             tx_bytes = sizeof(mf_ul_emulate->data.signature); |             tx_bytes = sizeof(mf_ul_emulate->data.signature); | ||||||
|             memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); |             memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_CHECK_TEARING) { |     } else if(cmd == MF_UL_CHECK_TEARING) { | ||||||
| @ -323,6 +341,7 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|         if(cnt_num < 3) { |         if(cnt_num < 3) { | ||||||
|             buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; |             buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; | ||||||
|             tx_bytes = 1; |             tx_bytes = 1; | ||||||
|  |             *data_type = FURI_HAL_NFC_TXRX_DEFAULT; | ||||||
|             command_parsed = true; |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_HALT_START) { |     } else if(cmd == MF_UL_HALT_START) { | ||||||
| @ -334,10 +353,12 @@ uint16_t mf_ul_prepare_emulation_response( | |||||||
|         // Send NACK
 |         // Send NACK
 | ||||||
|         buff_tx[0] = 0x00; |         buff_tx[0] = 0x00; | ||||||
|         tx_bits = 4; |         tx_bits = 4; | ||||||
|  |         *data_type = FURI_HAL_NFC_TXRX_RAW; | ||||||
|     } |     } | ||||||
|     // Return tx buffer size in bits
 |     // Return tx buffer size in bits
 | ||||||
|     if(tx_bytes) { |     if(tx_bytes) { | ||||||
|         tx_bits = tx_bytes * 8; |         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); | 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); | 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, |     uint8_t* buff_rx, | ||||||
|     uint16_t len_rx, |     uint16_t buff_rx_len, | ||||||
|     uint8_t* buff_tx, |     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 DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y)) | ||||||
| 
 | 
 | ||||||
| #define SUBGHZ_APP_FOLDER "/any/subghz" | #define SUBGHZ_APP_FOLDER "/any/subghz" | ||||||
| #define SUBGHZ_APP_PATH_FOLDER "/any/subghz/saved" |  | ||||||
| #define SUBGHZ_RAW_FOLDER "/ext/subghz" | #define SUBGHZ_RAW_FOLDER "/ext/subghz" | ||||||
| #define SUBGHZ_RAW_PATH_FOLDER "/ext/subghz/saved" |  | ||||||
| #define SUBGHZ_APP_EXTENSION ".sub" | #define SUBGHZ_APP_EXTENSION ".sub" | ||||||
| #define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 2048 | #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)) { |         if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_FOLDER)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         // Create saved directory if necessary
 |  | ||||||
|         if(!storage_simply_mkdir(instance->storage, SUBGHZ_RAW_PATH_FOLDER)) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         string_set(instance->file_name, dev_name); |         string_set(instance->file_name, dev_name); | ||||||
|         // First remove subghz device file if it was saved
 |         // First remove subghz device file if it was saved
 | ||||||
|         string_printf( |         string_printf(dev_file_name, "%s/%s%s", SUBGHZ_RAW_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); | ||||||
|             dev_file_name, "%s/%s%s", SUBGHZ_APP_PATH_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); |  | ||||||
| 
 | 
 | ||||||
|         if(!storage_simply_remove(instance->storage, string_get_cstr(dev_file_name))) { |         if(!storage_simply_remove(instance->storage, string_get_cstr(dev_file_name))) { | ||||||
|             break; |             break; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov