[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); | ||||
| } | ||||
| 
 | ||||
| uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { | ||||
|     furi_assert(canvas); | ||||
|     return u8g2_GetGlyphWidth(&canvas->fb, symbol); | ||||
| } | ||||
| 
 | ||||
| void canvas_draw_icon_animation( | ||||
|     Canvas* canvas, | ||||
|     uint8_t x, | ||||
|  | ||||
| @ -91,6 +91,11 @@ void canvas_draw_str_aligned( | ||||
|  */ | ||||
| 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.
 | ||||
|  * @param canvas - canvas instance | ||||
|  * @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( | ||||
|         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
 | ||||
|     nfc->nfc_detect = nfc_detect_alloc(&nfc->nfc_common); | ||||
|     view_dispatcher_add_view( | ||||
| @ -85,6 +91,10 @@ Nfc* nfc_alloc() { | ||||
|     nfc->scene_set_sak = nfc_scene_set_sak_alloc(); | ||||
|     nfc->scene_set_atqa = nfc_scene_set_atqa_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); | ||||
| 
 | ||||
| @ -114,6 +124,11 @@ void nfc_free(Nfc* nfc) { | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewByteInput); | ||||
|     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
 | ||||
|     view_dispatcher_remove_view(nfc->nfc_common.view_dispatcher, NfcViewDetect); | ||||
|     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_atqa_free(nfc->scene_set_atqa); | ||||
|     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_free(nfc->nfc_common.view_dispatcher); | ||||
|  | ||||
| @ -6,6 +6,8 @@ | ||||
| #define NFC_DEV_NAME_MAX_LEN 22 | ||||
| #define NFC_FILE_NAME_MAX_LEN 120 | ||||
| 
 | ||||
| #define NFC_MIFARE_UL_MAX_SIZE 256 | ||||
| 
 | ||||
| typedef enum { | ||||
|     NfcDeviceNfca, | ||||
|     NfcDeviceNfcb, | ||||
| @ -36,6 +38,9 @@ typedef struct { | ||||
| 
 | ||||
| typedef struct { | ||||
|     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 otp[4]; | ||||
| } 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/text_input.h> | ||||
| #include <gui/modules/byte_input.h> | ||||
| #include <gui/modules/text_box.h> | ||||
| 
 | ||||
| #include "views/nfc_detect.h" | ||||
| #include "views/nfc_emulate.h" | ||||
| @ -38,6 +39,10 @@ | ||||
| #include "scenes/nfc_scene_set_sak.h" | ||||
| #include "scenes/nfc_scene_set_atqa.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
 | ||||
| #include "scenes/nfc_scene_debug_menu.h" | ||||
| @ -55,6 +60,7 @@ struct Nfc { | ||||
|     NfcDevice device; | ||||
| 
 | ||||
|     char text_store[NFC_TEXT_STORE_SIZE + 1]; | ||||
|     string_t text_box_store; | ||||
| 
 | ||||
|     // Nfc Views
 | ||||
|     NfcDetect* nfc_detect; | ||||
| @ -68,6 +74,7 @@ struct Nfc { | ||||
|     Popup* popup; | ||||
|     TextInput* text_input; | ||||
|     ByteInput* byte_input; | ||||
|     TextBox* text_box; | ||||
| 
 | ||||
|     // Scenes
 | ||||
|     AppScene* scene_start; | ||||
| @ -84,6 +91,10 @@ struct Nfc { | ||||
|     AppScene* scene_set_sak; | ||||
|     AppScene* scene_set_atqa; | ||||
|     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
 | ||||
|     AppScene* scene_debug_menu; | ||||
| @ -99,6 +110,7 @@ typedef enum { | ||||
|     NfcViewPopup, | ||||
|     NfcViewTextInput, | ||||
|     NfcViewByteInput, | ||||
|     NfcViewTextBox, | ||||
|     NfcViewDetect, | ||||
|     NfcViewEmulate, | ||||
|     NfcViewEmv, | ||||
| @ -125,6 +137,10 @@ typedef enum { | ||||
|     NfcSceneSetSak, | ||||
|     NfcSceneSetAtqa, | ||||
|     NfcSceneSetUid, | ||||
|     NfcSceneScriptsMenu, | ||||
|     NfcSceneReadMifareUl, | ||||
|     NfcSceneReadMifareUlSuccess, | ||||
|     NfcSceneReadMifareUlMenu, | ||||
| } NfcScene; | ||||
| 
 | ||||
| Nfc* nfc_alloc(); | ||||
|  | ||||
| @ -383,7 +383,7 @@ void nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|                     mf_ul_set_default_version(&mf_ul_read); | ||||
|                     // Reinit device
 | ||||
|                     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"); | ||||
|                         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); | ||||
|                 memcpy(result->man_block, mf_ul_read.dump, 4 * 3); | ||||
|                 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) { | ||||
|                     printf("Page %2d: ", i / 4); | ||||
|                     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); | ||||
|         return true; | ||||
|     } 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( | ||||
|             nfc->nfc_common.view_dispatcher, ViewNavigatorEventNext); | ||||
|         return true; | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t id; | ||||
|     uint32_t state; | ||||
|     const void (*on_enter)(void* context); | ||||
|     const bool (*on_event)(void* context, uint32_t event); | ||||
|     const void (*on_exit)(void* context); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich