[FL-1501] NFC: read Mifare Ultralight (#571)
* nfc: add scripts menu scene * canvas: add glyph width api * app_scene: add state to Scene template * gui: introduce TextBox view * nfc: add mifare ultralight read scenes * nfc: add mifare ultralight menu scene * nfc: fix scene functions declaration * Gui: use size_t for sizes. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									9f6e14d005
								
							
						
					
					
						commit
						20fe544b4f
					
				| @ -176,6 +176,11 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str) { | |||||||
|     return u8g2_GetStrWidth(&canvas->fb, str); |     return u8g2_GetStrWidth(&canvas->fb, str); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     return u8g2_GetGlyphWidth(&canvas->fb, symbol); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void canvas_draw_icon_animation( | void canvas_draw_icon_animation( | ||||||
|     Canvas* canvas, |     Canvas* canvas, | ||||||
|     uint8_t x, |     uint8_t x, | ||||||
|  | |||||||
| @ -91,6 +91,11 @@ void canvas_draw_str_aligned( | |||||||
|  */ |  */ | ||||||
| uint16_t canvas_string_width(Canvas* canvas, const char* str); | uint16_t canvas_string_width(Canvas* canvas, const char* str); | ||||||
| 
 | 
 | ||||||
|  | /** Get glyph width
 | ||||||
|  |  * @return width in pixels | ||||||
|  |  */ | ||||||
|  | uint8_t canvas_glyph_width(Canvas* canvas, char symbol); | ||||||
|  | 
 | ||||||
| /** Draw animation at position defined by x,y.
 | /** Draw animation at position defined by x,y.
 | ||||||
|  * @param canvas - canvas instance |  * @param canvas - canvas instance | ||||||
|  * @param x - x coordinate |  * @param x - x coordinate | ||||||
|  | |||||||
							
								
								
									
										212
									
								
								applications/gui/modules/text_box.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										212
									
								
								applications/gui/modules/text_box.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,212 @@ | |||||||
|  | #include "text_box.h" | ||||||
|  | #include "gui/canvas.h" | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | struct TextBox { | ||||||
|  |     View* view; | ||||||
|  |     void* context; | ||||||
|  |     TextBoxExitCallback callback; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const char* text; | ||||||
|  |     char* text_pos; | ||||||
|  |     string_t text_formatted; | ||||||
|  |     size_t scroll_pos; | ||||||
|  |     size_t scroll_num; | ||||||
|  |     TextBoxFont font; | ||||||
|  |     bool formatted; | ||||||
|  | } TextBoxModel; | ||||||
|  | 
 | ||||||
|  | static void text_box_process_down(TextBox* text_box) { | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             if(model->scroll_pos < model->scroll_num - 1) { | ||||||
|  |                 model->scroll_pos++; | ||||||
|  |                 // Search next line start
 | ||||||
|  |                 while(*model->text_pos++ != '\n') | ||||||
|  |                     ; | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void text_box_process_up(TextBox* text_box) { | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             if(model->scroll_pos > 0) { | ||||||
|  |                 model->scroll_pos--; | ||||||
|  |                 // Reach last symbol of previous line
 | ||||||
|  |                 model->text_pos--; | ||||||
|  |                 // Search prevous line start
 | ||||||
|  |                 while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) | ||||||
|  |                     ; | ||||||
|  |                 if(*model->text_pos == '\n') { | ||||||
|  |                     model->text_pos++; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void text_box_process_back(TextBox* text_box) { | ||||||
|  |     if(text_box->callback) { | ||||||
|  |         text_box->callback(text_box->context); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { | ||||||
|  |     size_t i = 0; | ||||||
|  |     size_t line_width = 0; | ||||||
|  |     const char* str = model->text; | ||||||
|  |     size_t line_num = 0; | ||||||
|  | 
 | ||||||
|  |     const size_t text_width = 140; | ||||||
|  | 
 | ||||||
|  |     while(str[i] != '\0') { | ||||||
|  |         char symb = str[i++]; | ||||||
|  |         if(symb != '\n') { | ||||||
|  |             line_width += canvas_glyph_width(canvas, symb) + 1; | ||||||
|  |             if(line_width > text_width) { | ||||||
|  |                 line_num++; | ||||||
|  |                 line_width = 0; | ||||||
|  |                 string_push_back(model->text_formatted, '\n'); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             line_num++; | ||||||
|  |             line_width = 0; | ||||||
|  |         } | ||||||
|  |         string_push_back(model->text_formatted, symb); | ||||||
|  |     } | ||||||
|  |     line_num++; | ||||||
|  |     model->text = string_get_cstr(model->text_formatted); | ||||||
|  |     model->text_pos = (char*)model->text; | ||||||
|  |     model->scroll_num = MAX(line_num - 4, 0); | ||||||
|  |     model->scroll_pos = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void text_box_view_draw_callback(Canvas* canvas, void* _model) { | ||||||
|  |     TextBoxModel* model = _model; | ||||||
|  | 
 | ||||||
|  |     if(!model->formatted) { | ||||||
|  |         text_box_insert_endline(canvas, model); | ||||||
|  |         model->formatted = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     elements_slightly_rounded_frame(canvas, 0, 0, 124, 64); | ||||||
|  |     if(model->font == TextBoxFontText) { | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |     } else if(model->font == TextBoxFontHex) { | ||||||
|  |         canvas_set_font(canvas, FontKeyboard); | ||||||
|  |     } | ||||||
|  |     elements_multiline_text(canvas, 3, 11, model->text_pos); | ||||||
|  |     elements_scrollbar(canvas, model->scroll_pos, model->scroll_num); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool text_box_view_input_callback(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     TextBox* text_box = context; | ||||||
|  |     bool consumed = false; | ||||||
|  |     if(event->type == InputTypeShort) { | ||||||
|  |         if(event->key == InputKeyDown) { | ||||||
|  |             text_box_process_down(text_box); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event->key == InputKeyUp) { | ||||||
|  |             text_box_process_up(text_box); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event->key == InputKeyBack) { | ||||||
|  |             text_box_process_back(text_box); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TextBox* text_box_alloc() { | ||||||
|  |     TextBox* text_box = furi_alloc(sizeof(TextBox)); | ||||||
|  |     text_box->view = view_alloc(); | ||||||
|  |     view_set_context(text_box->view, text_box); | ||||||
|  |     view_allocate_model(text_box->view, ViewModelTypeLocking, sizeof(TextBoxModel)); | ||||||
|  |     view_set_draw_callback(text_box->view, text_box_view_draw_callback); | ||||||
|  |     view_set_input_callback(text_box->view, text_box_view_input_callback); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             model->text = NULL; | ||||||
|  |             string_init_set_str(model->text_formatted, ""); | ||||||
|  |             model->formatted = false; | ||||||
|  |             model->font = TextBoxFontText; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     return text_box; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_free(TextBox* text_box) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             string_clear(model->text_formatted); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     view_free(text_box->view); | ||||||
|  |     free(text_box); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* text_box_get_view(TextBox* text_box) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  |     return text_box->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_clean(TextBox* text_box) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             model->text = NULL; | ||||||
|  |             string_set_str(model->text_formatted, ""); | ||||||
|  |             model->font = TextBoxFontText; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  |     text_box->context = NULL; | ||||||
|  |     text_box->callback = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_set_text(TextBox* text_box, const char* text) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  |     furi_assert(text); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             model->text = text; | ||||||
|  |             string_reserve(model->text_formatted, strlen(text)); | ||||||
|  |             model->formatted = false; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_set_font(TextBox* text_box, TextBoxFont font) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         text_box->view, (TextBoxModel * model) { | ||||||
|  |             model->font = font; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_set_context(TextBox* text_box, void* context) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  |     text_box->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback) { | ||||||
|  |     furi_assert(text_box); | ||||||
|  |     text_box->callback = callback; | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								applications/gui/modules/text_box.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								applications/gui/modules/text_box.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* TextBox anonymous structure */ | ||||||
|  | typedef struct TextBox TextBox; | ||||||
|  | typedef void (*TextBoxExitCallback)(void* context); | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     TextBoxFontText, | ||||||
|  |     TextBoxFontHex, | ||||||
|  | } TextBoxFont; | ||||||
|  | 
 | ||||||
|  | /** Allocate and initialize text_box
 | ||||||
|  |  */ | ||||||
|  | TextBox* text_box_alloc(); | ||||||
|  | 
 | ||||||
|  | /** Deinitialize and free text_box
 | ||||||
|  |  * @param text_box text_box instance | ||||||
|  |  */ | ||||||
|  | void text_box_free(TextBox* text_box); | ||||||
|  | 
 | ||||||
|  | /** Get text_box view
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  * @return View instance that can be used for embedding | ||||||
|  |  */ | ||||||
|  | View* text_box_get_view(TextBox* text_box); | ||||||
|  | 
 | ||||||
|  | /** Clean text_box
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  */ | ||||||
|  | void text_box_clean(TextBox* text_box); | ||||||
|  | 
 | ||||||
|  | /** Set text for text_box
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  * @param text text to set | ||||||
|  |  */ | ||||||
|  | void text_box_set_text(TextBox* text_box, const char* text); | ||||||
|  | 
 | ||||||
|  | /** Set TextBox font
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  * @param font TextBoxFont instance | ||||||
|  |  */ | ||||||
|  | void text_box_set_font(TextBox* text_box, TextBoxFont font); | ||||||
|  | 
 | ||||||
|  | /** Set text_box context
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  * @param context context pointer | ||||||
|  |  */ | ||||||
|  | void text_box_set_context(TextBox* text_box, void* context); | ||||||
|  | 
 | ||||||
|  | /** Set exit callback
 | ||||||
|  |  * @param text_box TextBox instance | ||||||
|  |  * @param callback TextBoxExitCallback callback pointer | ||||||
|  |  */ | ||||||
|  | void text_box_set_exit_callback(TextBox* text_box, TextBoxExitCallback callback); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -43,6 +43,12 @@ Nfc* nfc_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         nfc->nfc_common.view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); |         nfc->nfc_common.view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); | ||||||
| 
 | 
 | ||||||
|  |     // TextBox
 | ||||||
|  |     nfc->text_box = text_box_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         nfc->nfc_common.view_dispatcher, NfcViewTextBox, text_box_get_view(nfc->text_box)); | ||||||
|  |     string_init(nfc->text_box_store); | ||||||
|  | 
 | ||||||
|     // Detect
 |     // Detect
 | ||||||
|     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); |     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -85,6 +91,10 @@ Nfc* nfc_alloc() { | |||||||
|     nfc->scene_set_sak = nfc_scene_set_sak_alloc(); |     nfc->scene_set_sak = nfc_scene_set_sak_alloc(); | ||||||
|     nfc->scene_set_atqa = nfc_scene_set_atqa_alloc(); |     nfc->scene_set_atqa = nfc_scene_set_atqa_alloc(); | ||||||
|     nfc->scene_set_uid = nfc_scene_set_uid_alloc(); |     nfc->scene_set_uid = nfc_scene_set_uid_alloc(); | ||||||
|  |     nfc->scene_scripts_menu = nfc_scene_scripts_menu_alloc(); | ||||||
|  |     nfc->scene_read_mifare_ul = nfc_scene_read_mifare_ul_alloc(); | ||||||
|  |     nfc->scene_read_mifare_ul_success = nfc_scene_read_mifare_ul_success_alloc(); | ||||||
|  |     nfc->scene_mifare_ul_menu = nfc_scene_mifare_ul_menu_alloc(); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_start); |     view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_start); | ||||||
| 
 | 
 | ||||||
| @ -114,6 +124,11 @@ void nfc_free(Nfc* nfc) { | |||||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); | ||||||
|     byte_input_free(nfc->byte_input); |     byte_input_free(nfc->byte_input); | ||||||
| 
 | 
 | ||||||
|  |     // TextBox
 | ||||||
|  |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); | ||||||
|  |     text_box_free(nfc->text_box); | ||||||
|  |     string_clear(nfc->text_box_store); | ||||||
|  | 
 | ||||||
|     // Detect
 |     // Detect
 | ||||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); |     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); | ||||||
|     nfc_detect_free(nfc->nfc_detect); |     nfc_detect_free(nfc->nfc_detect); | ||||||
| @ -154,6 +169,10 @@ void nfc_free(Nfc* nfc) { | |||||||
|     nfc_scene_set_sak_free(nfc->scene_set_sak); |     nfc_scene_set_sak_free(nfc->scene_set_sak); | ||||||
|     nfc_scene_set_atqa_free(nfc->scene_set_atqa); |     nfc_scene_set_atqa_free(nfc->scene_set_atqa); | ||||||
|     nfc_scene_set_uid_free(nfc->scene_set_uid); |     nfc_scene_set_uid_free(nfc->scene_set_uid); | ||||||
|  |     nfc_scene_scripts_menu_free(nfc->scene_scripts_menu); | ||||||
|  |     nfc_scene_read_mifare_ul_free(nfc->scene_read_mifare_ul); | ||||||
|  |     nfc_scene_read_mifare_ul_success_free(nfc->scene_read_mifare_ul_success); | ||||||
|  |     nfc_scene_mifare_ul_menu_free(nfc->scene_mifare_ul_menu); | ||||||
| 
 | 
 | ||||||
|     // View Dispatcher
 |     // View Dispatcher
 | ||||||
|     view_dispatcher_free(nfc->nfc_common.view_dispatcher); |     view_dispatcher_free(nfc->nfc_common.view_dispatcher); | ||||||
|  | |||||||
| @ -6,6 +6,8 @@ | |||||||
| #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_MIFARE_UL_MAX_SIZE 256 | ||||||
|  | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     NfcDeviceNfca, |     NfcDeviceNfca, | ||||||
|     NfcDeviceNfcb, |     NfcDeviceNfcb, | ||||||
| @ -36,6 +38,9 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     NfcDeviceData nfc_data; |     NfcDeviceData nfc_data; | ||||||
|  |     uint8_t full_dump[NFC_MIFARE_UL_MAX_SIZE]; | ||||||
|  |     uint16_t dump_size; | ||||||
|  |     // TODO delete with debug view
 | ||||||
|     uint8_t man_block[12]; |     uint8_t man_block[12]; | ||||||
|     uint8_t otp[4]; |     uint8_t otp[4]; | ||||||
| } NfcMifareUlData; | } NfcMifareUlData; | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								applications/nfc/nfc_i.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										16
									
								
								applications/nfc/nfc_i.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -18,6 +18,7 @@ | |||||||
| #include <gui/modules/popup.h> | #include <gui/modules/popup.h> | ||||||
| #include <gui/modules/text_input.h> | #include <gui/modules/text_input.h> | ||||||
| #include <gui/modules/byte_input.h> | #include <gui/modules/byte_input.h> | ||||||
|  | #include <gui/modules/text_box.h> | ||||||
| 
 | 
 | ||||||
| #include "views/nfc_detect.h" | #include "views/nfc_detect.h" | ||||||
| #include "views/nfc_emulate.h" | #include "views/nfc_emulate.h" | ||||||
| @ -38,6 +39,10 @@ | |||||||
| #include "scenes/nfc_scene_set_sak.h" | #include "scenes/nfc_scene_set_sak.h" | ||||||
| #include "scenes/nfc_scene_set_atqa.h" | #include "scenes/nfc_scene_set_atqa.h" | ||||||
| #include "scenes/nfc_scene_set_uid.h" | #include "scenes/nfc_scene_set_uid.h" | ||||||
|  | #include "scenes/nfc_scene_scripts_menu.h" | ||||||
|  | #include "scenes/nfc_scene_read_mifare_ul.h" | ||||||
|  | #include "scenes/nfc_scene_read_mifare_ul_success.h" | ||||||
|  | #include "scenes/nfc_scene_mifare_ul_menu.h" | ||||||
| 
 | 
 | ||||||
| // TODO delete debug scenes
 | // TODO delete debug scenes
 | ||||||
| #include "scenes/nfc_scene_debug_menu.h" | #include "scenes/nfc_scene_debug_menu.h" | ||||||
| @ -55,6 +60,7 @@ struct Nfc { | |||||||
|     NfcDevice device; |     NfcDevice device; | ||||||
| 
 | 
 | ||||||
|     char text_store[NFC_TEXT_STORE_SIZE + 1]; |     char text_store[NFC_TEXT_STORE_SIZE + 1]; | ||||||
|  |     string_t text_box_store; | ||||||
| 
 | 
 | ||||||
|     // Nfc Views
 |     // Nfc Views
 | ||||||
|     NfcDetect* nfc_detect; |     NfcDetect* nfc_detect; | ||||||
| @ -68,6 +74,7 @@ struct Nfc { | |||||||
|     Popup* popup; |     Popup* popup; | ||||||
|     TextInput* text_input; |     TextInput* text_input; | ||||||
|     ByteInput* byte_input; |     ByteInput* byte_input; | ||||||
|  |     TextBox* text_box; | ||||||
| 
 | 
 | ||||||
|     // Scenes
 |     // Scenes
 | ||||||
|     AppScene* scene_start; |     AppScene* scene_start; | ||||||
| @ -84,6 +91,10 @@ struct Nfc { | |||||||
|     AppScene* scene_set_sak; |     AppScene* scene_set_sak; | ||||||
|     AppScene* scene_set_atqa; |     AppScene* scene_set_atqa; | ||||||
|     AppScene* scene_set_uid; |     AppScene* scene_set_uid; | ||||||
|  |     AppScene* scene_scripts_menu; | ||||||
|  |     AppScene* scene_read_mifare_ul; | ||||||
|  |     AppScene* scene_read_mifare_ul_success; | ||||||
|  |     AppScene* scene_mifare_ul_menu; | ||||||
| 
 | 
 | ||||||
|     // TODO delete debug scenes
 |     // TODO delete debug scenes
 | ||||||
|     AppScene* scene_debug_menu; |     AppScene* scene_debug_menu; | ||||||
| @ -99,6 +110,7 @@ typedef enum { | |||||||
|     NfcViewPopup, |     NfcViewPopup, | ||||||
|     NfcViewTextInput, |     NfcViewTextInput, | ||||||
|     NfcViewByteInput, |     NfcViewByteInput, | ||||||
|  |     NfcViewTextBox, | ||||||
|     NfcViewDetect, |     NfcViewDetect, | ||||||
|     NfcViewEmulate, |     NfcViewEmulate, | ||||||
|     NfcViewEmv, |     NfcViewEmv, | ||||||
| @ -125,6 +137,10 @@ typedef enum { | |||||||
|     NfcSceneSetSak, |     NfcSceneSetSak, | ||||||
|     NfcSceneSetAtqa, |     NfcSceneSetAtqa, | ||||||
|     NfcSceneSetUid, |     NfcSceneSetUid, | ||||||
|  |     NfcSceneScriptsMenu, | ||||||
|  |     NfcSceneReadMifareUl, | ||||||
|  |     NfcSceneReadMifareUlSuccess, | ||||||
|  |     NfcSceneReadMifareUlMenu, | ||||||
| } NfcScene; | } NfcScene; | ||||||
| 
 | 
 | ||||||
| Nfc* nfc_alloc(); | Nfc* nfc_alloc(); | ||||||
|  | |||||||
| @ -383,7 +383,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                     mf_ul_set_default_version(&mf_ul_read); |                     mf_ul_set_default_version(&mf_ul_read); | ||||||
|                     // Reinit device
 |                     // Reinit device
 | ||||||
|                     api_hal_nfc_deactivate(); |                     api_hal_nfc_deactivate(); | ||||||
|                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { |                     if(!api_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { | ||||||
|                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); |                         FURI_LOG_E(NFC_WORKER_TAG, "Lost connection. Restarting search"); | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
| @ -439,6 +439,9 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | |||||||
|                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); |                     result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); | ||||||
|                 memcpy(result->man_block, mf_ul_read.dump, 4 * 3); |                 memcpy(result->man_block, mf_ul_read.dump, 4 * 3); | ||||||
|                 memcpy(result->otp, &mf_ul_read.dump[4 * 3], 4); |                 memcpy(result->otp, &mf_ul_read.dump[4 * 3], 4); | ||||||
|  |                 result->dump_size = mf_ul_read.pages_readed * 4; | ||||||
|  |                 memcpy(result->full_dump, mf_ul_read.dump, result->dump_size); | ||||||
|  | 
 | ||||||
|                 for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { |                 for(uint8_t i = 0; i < mf_ul_read.pages_readed * 4; i += 4) { | ||||||
|                     printf("Page %2d: ", i / 4); |                     printf("Page %2d: ", i / 4); | ||||||
|                     for(uint8_t j = 0; j < 4; j++) { |                     for(uint8_t j = 0; j < 4; j++) { | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								applications/nfc/scenes/nfc_scene_mifare_ul_menu.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								applications/nfc/scenes/nfc_scene_mifare_ul_menu.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | #include "nfc_scene_mifare_ul_menu.h" | ||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexSave, | ||||||
|  |     SubmenuIndexEmulate, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_mifare_ul_menu_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  |     Submenu* submenu = nfc->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Name and save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool nfc_scene_mifare_ul_menu_on_event(void* context, uint32_t event) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     if(event == SubmenuIndexSave) { | ||||||
|  |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } else if(event == SubmenuIndexEmulate) { | ||||||
|  |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } else if(event == ViewNavigatorEventBack) { | ||||||
|  |         view_dispatcher_send_back_search_scene_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, NfcSceneStart); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_mifare_ul_menu_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     submenu_clean(nfc->submenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_mifare_ul_menu_alloc() { | ||||||
|  |     AppScene* scene = furi_alloc(sizeof(AppScene)); | ||||||
|  |     scene->id = NfcSceneReadMifareUlMenu; | ||||||
|  |     scene->on_enter = nfc_scene_mifare_ul_menu_on_enter; | ||||||
|  |     scene->on_event = nfc_scene_mifare_ul_menu_on_event; | ||||||
|  |     scene->on_exit = nfc_scene_mifare_ul_menu_on_exit; | ||||||
|  | 
 | ||||||
|  |     return scene; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mifare_ul_menu_free(AppScene* scene) { | ||||||
|  |     free(scene); | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								applications/nfc/scenes/nfc_scene_mifare_ul_menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								applications/nfc/scenes/nfc_scene_mifare_ul_menu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "app_scene.h" | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_mifare_ul_menu_alloc(); | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mifare_ul_menu_free(AppScene* scene); | ||||||
							
								
								
									
										67
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										67
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | #include <nfc/scenes/nfc_scene_read_mifare_ul.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_read_mifare_ul_worker_callback(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  |     view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, NfcEventMifareUl); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_read_mifare_ul_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     Popup* popup = nfc->popup; | ||||||
|  |     popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop); | ||||||
|  |     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); | ||||||
|  | 
 | ||||||
|  |     // Start worker
 | ||||||
|  |     nfc_worker_start( | ||||||
|  |         nfc->nfc_common.worker, | ||||||
|  |         NfcWorkerStateReadMfUltralight, | ||||||
|  |         &nfc->nfc_common.worker_result, | ||||||
|  |         nfc_read_mifare_ul_worker_callback, | ||||||
|  |         nfc); | ||||||
|  |     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewPopup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool nfc_scene_read_mifare_ul_on_event(void* context, uint32_t event) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     if(event == NfcEventMifareUl) { | ||||||
|  |         nfc->device.data = nfc->nfc_common.worker_result.nfc_detect_data; | ||||||
|  |         view_dispatcher_add_scene( | ||||||
|  |             nfc->nfc_common.view_dispatcher, nfc->scene_read_mifare_ul_success); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_read_mifare_ul_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     // Stop worker
 | ||||||
|  |     nfc_worker_stop(nfc->nfc_common.worker); | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     Popup* popup = nfc->popup; | ||||||
|  |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||||
|  |     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||||
|  |     popup_set_icon(popup, 0, 0, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_read_mifare_ul_alloc() { | ||||||
|  |     AppScene* scene = furi_alloc(sizeof(AppScene)); | ||||||
|  |     scene->id = NfcSceneReadMifareUl; | ||||||
|  |     scene->on_enter = nfc_scene_read_mifare_ul_on_enter; | ||||||
|  |     scene->on_event = nfc_scene_read_mifare_ul_on_event; | ||||||
|  |     scene->on_exit = nfc_scene_read_mifare_ul_on_exit; | ||||||
|  | 
 | ||||||
|  |     return scene; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_read_mifare_ul_free(AppScene* scene) { | ||||||
|  |     free(scene); | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "app_scene.h" | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_read_mifare_ul_alloc(); | ||||||
|  | 
 | ||||||
|  | void nfc_scene_read_mifare_ul_free(AppScene* scene); | ||||||
							
								
								
									
										152
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										152
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,152 @@ | |||||||
|  | #include "nfc_scene_read_mifare_ul_success.h" | ||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/modules/dialog_ex.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | 
 | ||||||
|  | #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | ||||||
|  | #define NFC_SCENE_READ_MF_UL_CUSTOM_EVENT (0UL) | ||||||
|  | 
 | ||||||
|  | enum { | ||||||
|  |     ReadMifareUlStateShowUID, | ||||||
|  |     ReadMifareUlStateShowData, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->nfc_common.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->nfc_common.view_dispatcher, NFC_SCENE_READ_MF_UL_CUSTOM_EVENT); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     // Clear device name
 | ||||||
|  |     nfc_device_set_name(&nfc->device, ""); | ||||||
|  | 
 | ||||||
|  |     // Send notification
 | ||||||
|  |     notification_message(nfc->notifications, &sequence_success); | ||||||
|  | 
 | ||||||
|  |     // Setup dialog view
 | ||||||
|  |     NfcDeviceData* data = | ||||||
|  |         (NfcDeviceData*)&nfc->nfc_common.worker_result.nfc_mifare_ul_data.nfc_data; | ||||||
|  |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|  |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|  |     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||||
|  |     dialog_ex_set_center_button_text(dialog_ex, "Data"); | ||||||
|  |     dialog_ex_set_header(dialog_ex, "Mifare Ultralight", 22, 8, AlignLeft, AlignCenter); | ||||||
|  |     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); | ||||||
|  |     // Display UID
 | ||||||
|  |     nfc_set_text_store( | ||||||
|  |         nfc, | ||||||
|  |         NFC_SCENE_READ_SUCCESS_SHIFT "ATQA: %02X%02X\n" NFC_SCENE_READ_SUCCESS_SHIFT | ||||||
|  |                                      "SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", | ||||||
|  |         data->atqa[0], | ||||||
|  |         data->atqa[1], | ||||||
|  |         data->sak, | ||||||
|  |         data->uid[0], | ||||||
|  |         data->uid[1], | ||||||
|  |         data->uid[2], | ||||||
|  |         data->uid[3], | ||||||
|  |         data->uid[4], | ||||||
|  |         data->uid[5], | ||||||
|  |         data->uid[6]); | ||||||
|  |     dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); | ||||||
|  |     dialog_ex_set_context(dialog_ex, nfc); | ||||||
|  |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); | ||||||
|  | 
 | ||||||
|  |     // Setup TextBox view
 | ||||||
|  |     NfcMifareUlData* mf_ul_data = | ||||||
|  |         (NfcMifareUlData*)&nfc->nfc_common.worker_result.nfc_mifare_ul_data; | ||||||
|  |     TextBox* text_box = nfc->text_box; | ||||||
|  |     text_box_set_context(text_box, nfc); | ||||||
|  |     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); | ||||||
|  |     text_box_set_font(text_box, TextBoxFontHex); | ||||||
|  |     for(uint16_t i = 0; i < mf_ul_data->dump_size; i += 2) { | ||||||
|  |         if(!(i % 8) && i) { | ||||||
|  |             string_push_back(nfc->text_box_store, '\n'); | ||||||
|  |         } | ||||||
|  |         string_cat_printf( | ||||||
|  |             nfc->text_box_store, | ||||||
|  |             "%02X%02X ", | ||||||
|  |             mf_ul_data->full_dump[i], | ||||||
|  |             mf_ul_data->full_dump[i + 1]); | ||||||
|  |     } | ||||||
|  |     text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||||
|  | 
 | ||||||
|  |     nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowUID; | ||||||
|  |     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool nfc_scene_read_mifare_ul_success_on_event(void* context, uint32_t event) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     if((nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && | ||||||
|  |        (event == DialogExResultLeft)) { | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventBack); | ||||||
|  |         return true; | ||||||
|  |     } else if( | ||||||
|  |         (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && | ||||||
|  |         (event == DialogExResultRight)) { | ||||||
|  |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_mifare_ul_menu); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } else if( | ||||||
|  |         (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowUID) && | ||||||
|  |         (event == DialogExResultCenter)) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewTextBox); | ||||||
|  |         nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowData; | ||||||
|  |         return true; | ||||||
|  |     } else if( | ||||||
|  |         (nfc->scene_read_mifare_ul_success->state == ReadMifareUlStateShowData) && | ||||||
|  |         (event == NFC_SCENE_READ_MF_UL_CUSTOM_EVENT)) { | ||||||
|  |         view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewDialogEx); | ||||||
|  |         nfc->scene_read_mifare_ul_success->state = ReadMifareUlStateShowUID; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_read_mifare_ul_success_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     // Clean dialog
 | ||||||
|  |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|  |     dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); | ||||||
|  |     dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); | ||||||
|  |     dialog_ex_set_icon(dialog_ex, 0, 0, NULL); | ||||||
|  |     dialog_ex_set_left_button_text(dialog_ex, NULL); | ||||||
|  |     dialog_ex_set_right_button_text(dialog_ex, NULL); | ||||||
|  |     dialog_ex_set_center_button_text(dialog_ex, NULL); | ||||||
|  |     dialog_ex_set_result_callback(dialog_ex, NULL); | ||||||
|  |     dialog_ex_set_context(dialog_ex, NULL); | ||||||
|  | 
 | ||||||
|  |     // Clean TextBox
 | ||||||
|  |     TextBox* text_box = nfc->text_box; | ||||||
|  |     text_box_clean(text_box); | ||||||
|  |     string_clean(nfc->text_box_store); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_read_mifare_ul_success_alloc() { | ||||||
|  |     AppScene* scene = furi_alloc(sizeof(AppScene)); | ||||||
|  |     scene->id = NfcSceneReadMifareUlSuccess; | ||||||
|  |     scene->on_enter = nfc_scene_read_mifare_ul_success_on_enter; | ||||||
|  |     scene->on_event = nfc_scene_read_mifare_ul_success_on_event; | ||||||
|  |     scene->on_exit = nfc_scene_read_mifare_ul_success_on_exit; | ||||||
|  | 
 | ||||||
|  |     return scene; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_read_mifare_ul_success_free(AppScene* scene) { | ||||||
|  |     free(scene); | ||||||
|  | } | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "app_scene.h" | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_read_mifare_ul_success_alloc(); | ||||||
|  | 
 | ||||||
|  | void nfc_scene_read_mifare_ul_success_free(AppScene* scene); | ||||||
							
								
								
									
										75
									
								
								applications/nfc/scenes/nfc_scene_scripts_menu.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										75
									
								
								applications/nfc/scenes/nfc_scene_scripts_menu.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | #include "nfc_scene_scripts_menu.h" | ||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/modules/submenu.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexBankCard, | ||||||
|  |     SubmenuIndexMifareUltralight, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->nfc_common.view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_scripts_menu_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  |     Submenu* submenu = nfc->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Read bank card", | ||||||
|  |         SubmenuIndexBankCard, | ||||||
|  |         nfc_scene_scripts_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Read Mifare Ultralight", | ||||||
|  |         SubmenuIndexMifareUltralight, | ||||||
|  |         nfc_scene_scripts_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->nfc_common.view_dispatcher, NfcViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool nfc_scene_scripts_menu_on_event(void* context, uint32_t event) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     if(event == SubmenuIndexBankCard) { | ||||||
|  |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } else if(event == SubmenuIndexMifareUltralight) { | ||||||
|  |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_read_mifare_ul); | ||||||
|  |         view_dispatcher_send_navigation_event( | ||||||
|  |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void nfc_scene_scripts_menu_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = (Nfc*)context; | ||||||
|  | 
 | ||||||
|  |     submenu_clean(nfc->submenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_scripts_menu_alloc() { | ||||||
|  |     AppScene* scene = furi_alloc(sizeof(AppScene)); | ||||||
|  |     scene->id = NfcSceneScriptsMenu; | ||||||
|  |     scene->on_enter = nfc_scene_scripts_menu_on_enter; | ||||||
|  |     scene->on_event = nfc_scene_scripts_menu_on_event; | ||||||
|  |     scene->on_exit = nfc_scene_scripts_menu_on_exit; | ||||||
|  | 
 | ||||||
|  |     return scene; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_scripts_menu_free(AppScene* scene) { | ||||||
|  |     free(scene); | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								applications/nfc/scenes/nfc_scene_scripts_menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								applications/nfc/scenes/nfc_scene_scripts_menu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "app_scene.h" | ||||||
|  | 
 | ||||||
|  | AppScene* nfc_scene_scripts_menu_alloc(); | ||||||
|  | 
 | ||||||
|  | void nfc_scene_scripts_menu_free(AppScene* scene); | ||||||
| @ -49,7 +49,7 @@ const bool nfc_scene_start_on_event(void* context, uint32_t event) { | |||||||
|             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|         return true; |         return true; | ||||||
|     } else if(event == SubmenuIndexRunScript) { |     } else if(event == SubmenuIndexRunScript) { | ||||||
|         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_not_implemented); |         view_dispatcher_add_scene(nfc->nfc_common.view_dispatcher, nfc->scene_scripts_menu); | ||||||
|         view_dispatcher_send_navigation_event( |         view_dispatcher_send_navigation_event( | ||||||
|             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); |             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||||
|         return true; |         return true; | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t id; |     uint32_t id; | ||||||
|  |     uint32_t state; | ||||||
|     const void (*on_enter)(void* context); |     const void (*on_enter)(void* context); | ||||||
|     const bool (*on_event)(void* context, uint32_t event); |     const bool (*on_event)(void* context, uint32_t event); | ||||||
|     const void (*on_exit)(void* context); |     const void (*on_exit)(void* context); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich