[FL-2714] New NFC info screens (#1605)
* nfc: add scroll element for info * widget: format lines for scroll text element * widget: fix new line generation * widget: finish element text scroll * nfc: rework ultralight and NTAG info scenes * nfc: rework mf classic info screens * nfc: rework nfca info scenes * nfc: fix mf ultralight navigation * widget: add documentation * nfc: rework bank card infO * nfc: rework device info scene * nfc: fix incorrect atqa order * mf ultralight: remove unused function * widget: add mutex for model protection * widget: fix memory leak * nfc: rework delete scene * nfc: fix selected item in saved menu scene * widget: fix naming in text scroll element * nfc: fix navigation from delete success * nfc: add dictionary icon * widget: fix memory leak
This commit is contained in:
		
							parent
							
								
									b3d7583f9b
								
							
						
					
					
						commit
						560ea5f995
					
				| @ -162,6 +162,19 @@ void widget_add_text_box_element( | |||||||
|     widget_add_element(widget, text_box_element); |     widget_add_element(widget, text_box_element); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void widget_add_text_scroll_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     const char* text) { | ||||||
|  |     furi_assert(widget); | ||||||
|  |     WidgetElement* text_scroll_element = | ||||||
|  |         widget_element_text_scroll_create(x, y, width, height, text); | ||||||
|  |     widget_add_element(widget, text_scroll_element); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void widget_add_button_element( | void widget_add_button_element( | ||||||
|     Widget* widget, |     Widget* widget, | ||||||
|     GuiButtonType button_type, |     GuiButtonType button_type, | ||||||
|  | |||||||
| @ -105,6 +105,27 @@ void widget_add_text_box_element( | |||||||
|     const char* text, |     const char* text, | ||||||
|     bool strip_to_dots); |     bool strip_to_dots); | ||||||
| 
 | 
 | ||||||
|  | /** Add Text Scroll Element
 | ||||||
|  |  * | ||||||
|  |  * @param      widget           Widget instance | ||||||
|  |  * @param      x                x coordinate | ||||||
|  |  * @param      y                y coordinate | ||||||
|  |  * @param      width            width to fit text | ||||||
|  |  * @param      height           height to fit text | ||||||
|  |  * @param[in]  text             Formatted text. Default format: align left, Secondary font. | ||||||
|  |  *                              The following formats are available: | ||||||
|  |  *                               "\e#Bold text" - sets bold font before until next '\n' symbol | ||||||
|  |  *                               "\ecBold text" - sets center horizontal align before until next '\n' symbol | ||||||
|  |  *                               "\erBold text" - sets right horizontal align before until next '\n' symbol | ||||||
|  |  */ | ||||||
|  | void widget_add_text_scroll_element( | ||||||
|  |     Widget* widget, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     const char* text); | ||||||
|  | 
 | ||||||
| /** Add Button Element
 | /** Add Button Element
 | ||||||
|  * |  * | ||||||
|  * @param      widget       Widget instance |  * @param      widget       Widget instance | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ struct WidgetElement { | |||||||
| 
 | 
 | ||||||
|     // generic model holder
 |     // generic model holder
 | ||||||
|     void* model; |     void* model; | ||||||
|  |     FuriMutex* model_mutex; | ||||||
| 
 | 
 | ||||||
|     // pointer to widget that hold our element
 |     // pointer to widget that hold our element
 | ||||||
|     Widget* parent; |     Widget* parent; | ||||||
| @ -80,3 +81,10 @@ WidgetElement* widget_element_frame_create( | |||||||
|     uint8_t width, |     uint8_t width, | ||||||
|     uint8_t height, |     uint8_t height, | ||||||
|     uint8_t radius); |     uint8_t radius); | ||||||
|  | 
 | ||||||
|  | WidgetElement* widget_element_text_scroll_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     const char* text); | ||||||
|  | |||||||
| @ -0,0 +1,245 @@ | |||||||
|  | #include "widget_element_i.h" | ||||||
|  | #include <m-string.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <m-array.h> | ||||||
|  | 
 | ||||||
|  | #define WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET (4) | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     Font font; | ||||||
|  |     Align horizontal; | ||||||
|  |     string_t text; | ||||||
|  | } TextScrollLineArray; | ||||||
|  | 
 | ||||||
|  | ARRAY_DEF(TextScrollLineArray, TextScrollLineArray, M_POD_OPLIST) | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     TextScrollLineArray_t line_array; | ||||||
|  |     uint8_t x; | ||||||
|  |     uint8_t y; | ||||||
|  |     uint8_t width; | ||||||
|  |     uint8_t height; | ||||||
|  |     string_t text; | ||||||
|  |     uint8_t scroll_pos_total; | ||||||
|  |     uint8_t scroll_pos_current; | ||||||
|  |     bool text_formatted; | ||||||
|  | } WidgetElementTextScrollModel; | ||||||
|  | 
 | ||||||
|  | static bool | ||||||
|  |     widget_element_text_scroll_process_ctrl_symbols(TextScrollLineArray* line, string_t text) { | ||||||
|  |     bool processed = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(string_get_char(text, 0) != '\e') break; | ||||||
|  |         char ctrl_symbol = string_get_char(text, 1); | ||||||
|  |         if(ctrl_symbol == 'c') { | ||||||
|  |             line->horizontal = AlignCenter; | ||||||
|  |         } else if(ctrl_symbol == 'r') { | ||||||
|  |             line->horizontal = AlignRight; | ||||||
|  |         } else if(ctrl_symbol == '#') { | ||||||
|  |             line->font = FontPrimary; | ||||||
|  |         } | ||||||
|  |         string_right(text, 2); | ||||||
|  |         processed = true; | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     return processed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void widget_element_text_scroll_add_line(WidgetElement* element, TextScrollLineArray* line) { | ||||||
|  |     WidgetElementTextScrollModel* model = element->model; | ||||||
|  |     TextScrollLineArray new_line; | ||||||
|  |     new_line.font = line->font; | ||||||
|  |     new_line.horizontal = line->horizontal; | ||||||
|  |     string_init_set(new_line.text, line->text); | ||||||
|  |     TextScrollLineArray_push_back(model->line_array, new_line); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void widget_element_text_scroll_fill_lines(Canvas* canvas, WidgetElement* element) { | ||||||
|  |     WidgetElementTextScrollModel* model = element->model; | ||||||
|  |     TextScrollLineArray line_tmp; | ||||||
|  |     bool all_text_processed = false; | ||||||
|  |     string_init(line_tmp.text); | ||||||
|  |     bool reached_new_line = true; | ||||||
|  |     uint16_t total_height = 0; | ||||||
|  | 
 | ||||||
|  |     while(!all_text_processed) { | ||||||
|  |         if(reached_new_line) { | ||||||
|  |             // Set default line properties
 | ||||||
|  |             line_tmp.font = FontSecondary; | ||||||
|  |             line_tmp.horizontal = AlignLeft; | ||||||
|  |             string_reset(line_tmp.text); | ||||||
|  |             // Process control symbols
 | ||||||
|  |             while(widget_element_text_scroll_process_ctrl_symbols(&line_tmp, model->text)) | ||||||
|  |                 ; | ||||||
|  |         } | ||||||
|  |         // Set canvas font
 | ||||||
|  |         canvas_set_font(canvas, line_tmp.font); | ||||||
|  |         CanvasFontParameters* params = canvas_get_font_params(canvas, line_tmp.font); | ||||||
|  |         total_height += params->height; | ||||||
|  |         if(total_height > model->height) { | ||||||
|  |             model->scroll_pos_total++; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint8_t line_width = 0; | ||||||
|  |         uint16_t char_i = 0; | ||||||
|  |         while(true) { | ||||||
|  |             char next_char = string_get_char(model->text, char_i++); | ||||||
|  |             if(next_char == '\0') { | ||||||
|  |                 string_push_back(line_tmp.text, '\0'); | ||||||
|  |                 widget_element_text_scroll_add_line(element, &line_tmp); | ||||||
|  |                 total_height += params->leading_default - params->height; | ||||||
|  |                 all_text_processed = true; | ||||||
|  |                 break; | ||||||
|  |             } else if(next_char == '\n') { | ||||||
|  |                 string_push_back(line_tmp.text, '\0'); | ||||||
|  |                 widget_element_text_scroll_add_line(element, &line_tmp); | ||||||
|  |                 string_right(model->text, char_i); | ||||||
|  |                 total_height += params->leading_default - params->height; | ||||||
|  |                 reached_new_line = true; | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 line_width += canvas_glyph_width(canvas, next_char); | ||||||
|  |                 if(line_width > model->width) { | ||||||
|  |                     string_push_back(line_tmp.text, '\0'); | ||||||
|  |                     widget_element_text_scroll_add_line(element, &line_tmp); | ||||||
|  |                     string_right(model->text, char_i - 1); | ||||||
|  |                     string_reset(line_tmp.text); | ||||||
|  |                     total_height += params->leading_default - params->height; | ||||||
|  |                     reached_new_line = false; | ||||||
|  |                     break; | ||||||
|  |                 } else { | ||||||
|  |                     string_push_back(line_tmp.text, next_char); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(line_tmp.text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* element) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     furi_assert(element); | ||||||
|  | 
 | ||||||
|  |     furi_mutex_acquire(element->model_mutex, FuriWaitForever); | ||||||
|  | 
 | ||||||
|  |     WidgetElementTextScrollModel* model = element->model; | ||||||
|  |     if(!model->text_formatted) { | ||||||
|  |         widget_element_text_scroll_fill_lines(canvas, element); | ||||||
|  |         model->text_formatted = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint8_t y = model->y; | ||||||
|  |     uint8_t x = model->x; | ||||||
|  |     uint16_t curr_line = 0; | ||||||
|  |     if(TextScrollLineArray_size(model->line_array)) { | ||||||
|  |         TextScrollLineArray_it_t it; | ||||||
|  |         for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it); | ||||||
|  |             TextScrollLineArray_next(it), curr_line++) { | ||||||
|  |             if(curr_line < model->scroll_pos_current) continue; | ||||||
|  |             TextScrollLineArray* line = TextScrollLineArray_ref(it); | ||||||
|  |             CanvasFontParameters* params = canvas_get_font_params(canvas, line->font); | ||||||
|  |             if(y + params->descender > model->y + model->height) break; | ||||||
|  |             canvas_set_font(canvas, line->font); | ||||||
|  |             if(line->horizontal == AlignLeft) { | ||||||
|  |                 x = model->x; | ||||||
|  |             } else if(line->horizontal == AlignCenter) { | ||||||
|  |                 x = (model->x + model->width) / 2; | ||||||
|  |             } else if(line->horizontal == AlignRight) { | ||||||
|  |                 x = model->x + model->width; | ||||||
|  |             } | ||||||
|  |             canvas_draw_str_aligned( | ||||||
|  |                 canvas, x, y, line->horizontal, AlignTop, string_get_cstr(line->text)); | ||||||
|  |             y += params->leading_default; | ||||||
|  |         } | ||||||
|  |         // Draw scroll bar
 | ||||||
|  |         if(model->scroll_pos_total > 1) { | ||||||
|  |             elements_scrollbar_pos( | ||||||
|  |                 canvas, | ||||||
|  |                 model->x + model->width + WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET, | ||||||
|  |                 model->y, | ||||||
|  |                 model->height, | ||||||
|  |                 model->scroll_pos_current, | ||||||
|  |                 model->scroll_pos_total); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_mutex_release(element->model_mutex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool widget_element_text_scroll_input(InputEvent* event, WidgetElement* element) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(element); | ||||||
|  | 
 | ||||||
|  |     furi_mutex_acquire(element->model_mutex, FuriWaitForever); | ||||||
|  | 
 | ||||||
|  |     WidgetElementTextScrollModel* model = element->model; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { | ||||||
|  |         if(event->key == InputKeyUp) { | ||||||
|  |             if(model->scroll_pos_current > 0) { | ||||||
|  |                 model->scroll_pos_current--; | ||||||
|  |             } | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event->key == InputKeyDown) { | ||||||
|  |             if((model->scroll_pos_total > 1) && | ||||||
|  |                (model->scroll_pos_current < model->scroll_pos_total - 1)) { | ||||||
|  |                 model->scroll_pos_current++; | ||||||
|  |             } | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_mutex_release(element->model_mutex); | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void widget_element_text_scroll_free(WidgetElement* text_scroll) { | ||||||
|  |     furi_assert(text_scroll); | ||||||
|  | 
 | ||||||
|  |     WidgetElementTextScrollModel* model = text_scroll->model; | ||||||
|  |     TextScrollLineArray_it_t it; | ||||||
|  |     for(TextScrollLineArray_it(it, model->line_array); !TextScrollLineArray_end_p(it); | ||||||
|  |         TextScrollLineArray_next(it)) { | ||||||
|  |         TextScrollLineArray* line = TextScrollLineArray_ref(it); | ||||||
|  |         string_clear(line->text); | ||||||
|  |     } | ||||||
|  |     TextScrollLineArray_clear(model->line_array); | ||||||
|  |     string_clear(model->text); | ||||||
|  |     free(text_scroll->model); | ||||||
|  |     furi_mutex_free(text_scroll->model_mutex); | ||||||
|  |     free(text_scroll); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WidgetElement* widget_element_text_scroll_create( | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     uint8_t width, | ||||||
|  |     uint8_t height, | ||||||
|  |     const char* text) { | ||||||
|  |     furi_assert(text); | ||||||
|  | 
 | ||||||
|  |     // Allocate and init model
 | ||||||
|  |     WidgetElementTextScrollModel* model = malloc(sizeof(WidgetElementTextScrollModel)); | ||||||
|  |     model->x = x; | ||||||
|  |     model->y = y; | ||||||
|  |     model->width = width - WIDGET_ELEMENT_TEXT_SCROLL_BAR_OFFSET; | ||||||
|  |     model->height = height; | ||||||
|  |     model->scroll_pos_current = 0; | ||||||
|  |     model->scroll_pos_total = 1; | ||||||
|  |     TextScrollLineArray_init(model->line_array); | ||||||
|  |     string_init_set_str(model->text, text); | ||||||
|  | 
 | ||||||
|  |     WidgetElement* text_scroll = malloc(sizeof(WidgetElement)); | ||||||
|  |     text_scroll->parent = NULL; | ||||||
|  |     text_scroll->draw = widget_element_text_scroll_draw; | ||||||
|  |     text_scroll->input = widget_element_text_scroll_input; | ||||||
|  |     text_scroll->free = widget_element_text_scroll_free; | ||||||
|  |     text_scroll->model = model; | ||||||
|  |     text_scroll->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
|  | 
 | ||||||
|  |     return text_scroll; | ||||||
|  | } | ||||||
| @ -89,11 +89,6 @@ Nfc* nfc_alloc() { | |||||||
|     nfc->widget = widget_alloc(); |     nfc->widget = widget_alloc(); | ||||||
|     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); |     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); | ||||||
| 
 | 
 | ||||||
|     // Bank Card
 |  | ||||||
|     nfc->bank_card = bank_card_alloc(); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card)); |  | ||||||
| 
 |  | ||||||
|     // Mifare Classic Dict Attack
 |     // Mifare Classic Dict Attack
 | ||||||
|     nfc->dict_attack = dict_attack_alloc(); |     nfc->dict_attack = dict_attack_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -159,10 +154,6 @@ void nfc_free(Nfc* nfc) { | |||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|     widget_free(nfc->widget); |     widget_free(nfc->widget); | ||||||
| 
 | 
 | ||||||
|     // Bank Card
 |  | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); |  | ||||||
|     bank_card_free(nfc->bank_card); |  | ||||||
| 
 |  | ||||||
|     // Mifare Classic Dict Attack
 |     // Mifare Classic Dict Attack
 | ||||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); |     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); | ||||||
|     dict_attack_free(nfc->dict_attack); |     dict_attack_free(nfc->dict_attack); | ||||||
|  | |||||||
| @ -25,8 +25,8 @@ | |||||||
| #include <lib/nfc/nfc_worker.h> | #include <lib/nfc/nfc_worker.h> | ||||||
| #include <lib/nfc/nfc_device.h> | #include <lib/nfc/nfc_device.h> | ||||||
| #include <lib/nfc/helpers/mf_classic_dict.h> | #include <lib/nfc/helpers/mf_classic_dict.h> | ||||||
|  | #include <lib/nfc/parsers/nfc_supported_card.h> | ||||||
| 
 | 
 | ||||||
| #include "views/bank_card.h" |  | ||||||
| #include "views/dict_attack.h" | #include "views/dict_attack.h" | ||||||
| 
 | 
 | ||||||
| #include <nfc/scenes/nfc_scene.h> | #include <nfc/scenes/nfc_scene.h> | ||||||
| @ -70,7 +70,6 @@ struct Nfc { | |||||||
|     ByteInput* byte_input; |     ByteInput* byte_input; | ||||||
|     TextBox* text_box; |     TextBox* text_box; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
|     BankCard* bank_card; |  | ||||||
|     DictAttack* dict_attack; |     DictAttack* dict_attack; | ||||||
| 
 | 
 | ||||||
|     const NfcGenerator* generator; |     const NfcGenerator* generator; | ||||||
| @ -85,7 +84,6 @@ typedef enum { | |||||||
|     NfcViewByteInput, |     NfcViewByteInput, | ||||||
|     NfcViewTextBox, |     NfcViewTextBox, | ||||||
|     NfcViewWidget, |     NfcViewWidget, | ||||||
|     NfcViewBankCard, |  | ||||||
|     NfcViewDictAttack, |     NfcViewDictAttack, | ||||||
| } NfcView; | } NfcView; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,7 +12,10 @@ ADD_SCENE(nfc, save_name, SaveName) | |||||||
| ADD_SCENE(nfc, save_success, SaveSuccess) | ADD_SCENE(nfc, save_success, SaveSuccess) | ||||||
| ADD_SCENE(nfc, file_select, FileSelect) | ADD_SCENE(nfc, file_select, FileSelect) | ||||||
| ADD_SCENE(nfc, emulate_uid, EmulateUid) | ADD_SCENE(nfc, emulate_uid, EmulateUid) | ||||||
|  | ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) | ||||||
|  | ADD_SCENE(nfc, nfca_menu, NfcaMenu) | ||||||
| ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) | ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) | ||||||
|  | ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) | ||||||
| ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) | ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) | ||||||
| ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) | ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) | ||||||
| ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) | ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) | ||||||
| @ -25,13 +28,13 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) | |||||||
| ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) | ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) | ||||||
| ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) | ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) | ||||||
| ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) | ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) | ||||||
| ADD_SCENE(nfc, mf_classic_info, MfClassicInfo) |  | ||||||
| ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) | ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) | ||||||
| ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) | ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) | ||||||
| ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) | ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) | ||||||
| ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) | ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) | ||||||
| ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) | ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) | ||||||
| ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) | ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) | ||||||
|  | ADD_SCENE(nfc, emv_menu, EmvMenu) | ||||||
| ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ||||||
| ADD_SCENE(nfc, device_info, DeviceInfo) | ADD_SCENE(nfc, device_info, DeviceInfo) | ||||||
| ADD_SCENE(nfc, delete, Delete) | ADD_SCENE(nfc, delete, Delete) | ||||||
| @ -45,3 +48,4 @@ ADD_SCENE(nfc, rpc, Rpc) | |||||||
| ADD_SCENE(nfc, exit_confirm, ExitConfirm) | ADD_SCENE(nfc, exit_confirm, ExitConfirm) | ||||||
| ADD_SCENE(nfc, retry_confirm, RetryConfirm) | ADD_SCENE(nfc, retry_confirm, RetryConfirm) | ||||||
| ADD_SCENE(nfc, detect_reader, DetectReader) | ADD_SCENE(nfc, detect_reader, DetectReader) | ||||||
|  | ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) | ||||||
|  | |||||||
| @ -9,58 +9,43 @@ void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void | |||||||
| 
 | 
 | ||||||
| void nfc_scene_delete_on_enter(void* context) { | void nfc_scene_delete_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     char temp_str[64]; |     string_t temp_str; | ||||||
|     snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name); |     string_init(temp_str); | ||||||
|  | 
 | ||||||
|  |     string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name); | ||||||
|     widget_add_text_box_element( |     widget_add_text_box_element( | ||||||
|         nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); |         nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, string_get_cstr(temp_str), false); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); |         nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); |         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |  | ||||||
|     if(data->uid_len == 4) { |  | ||||||
|         snprintf( |  | ||||||
|             temp_str, |  | ||||||
|             sizeof(temp_str), |  | ||||||
|             "UID: %02X %02X %02X %02X", |  | ||||||
|             data->uid[0], |  | ||||||
|             data->uid[1], |  | ||||||
|             data->uid[2], |  | ||||||
|             data->uid[3]); |  | ||||||
|     } else if(data->uid_len == 7) { |  | ||||||
|         snprintf( |  | ||||||
|             temp_str, |  | ||||||
|             sizeof(temp_str), |  | ||||||
|             "UID: %02X %02X %02X %02X %02X %02X %02X", |  | ||||||
|             data->uid[0], |  | ||||||
|             data->uid[1], |  | ||||||
|             data->uid[2], |  | ||||||
|             data->uid[3], |  | ||||||
|             data->uid[4], |  | ||||||
|             data->uid[5], |  | ||||||
|             data->uid[6]); |  | ||||||
|     } |  | ||||||
|     widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str); |  | ||||||
| 
 | 
 | ||||||
|     const char* protocol_name = NULL; |     string_set_str(temp_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < nfc_data->uid_len; i++) { | ||||||
|  |         string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); | ||||||
|  |     } | ||||||
|  |     widget_add_string_element( | ||||||
|  |         nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|  | 
 | ||||||
|     NfcProtocol protocol = nfc->dev->dev_data.protocol; |     NfcProtocol protocol = nfc->dev->dev_data.protocol; | ||||||
|     if(protocol == NfcDeviceProtocolEMV) { |     if(protocol == NfcDeviceProtocolEMV) { | ||||||
|         protocol_name = nfc_guess_protocol(protocol); |         string_set_str(temp_str, "EMV bank card"); | ||||||
|     } else if(protocol == NfcDeviceProtocolMifareUl) { |     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); |         string_set_str(temp_str, nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, true)); | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareClassic) { | ||||||
|  |         string_set_str(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||||
|  |         string_set_str(temp_str, "MIFARE DESFire"); | ||||||
|  |     } else { | ||||||
|  |         string_set_str(temp_str, "Unknown ISO tag"); | ||||||
|     } |     } | ||||||
|     if(protocol_name) { |  | ||||||
|     widget_add_string_element( |     widget_add_string_element( | ||||||
|             nfc->widget, 10, 33, AlignLeft, AlignTop, FontSecondary, protocol_name); |         nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, string_get_cstr(temp_str)); | ||||||
|     } |     widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); | ||||||
|     // TODO change dinamically
 |     string_clear(temp_str); | ||||||
|     widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); |  | ||||||
|     widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str); |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); |  | ||||||
|     widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str); |  | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| @ -71,7 +56,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             return scene_manager_previous_scene(nfc->scene_manager); |             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             if(nfc_device_delete(nfc->dev, true)) { |             if(nfc_device_delete(nfc->dev, true)) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == NfcCustomEventViewExit) { |         if(event.event == NfcCustomEventViewExit) { | ||||||
|             consumed = scene_manager_search_and_switch_to_previous_scene( |             consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|                 nfc->scene_manager, NfcSceneStart); |                 nfc->scene_manager, NfcSceneFileSelect); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
| @ -1,11 +1,6 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include "../helpers/nfc_emv_parser.h" | #include "../helpers/nfc_emv_parser.h" | ||||||
| 
 | 
 | ||||||
| enum { |  | ||||||
|     NfcSceneDeviceInfoUid, |  | ||||||
|     NfcSceneDeviceInfoData, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { | void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     if(type == InputTypeShort) { |     if(type == InputTypeShort) { | ||||||
| @ -13,197 +8,65 @@ void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) { |  | ||||||
|     Nfc* nfc = context; |  | ||||||
|     if(result == DialogExResultLeft) { |  | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType type, void* context) { |  | ||||||
|     UNUSED(result); |  | ||||||
|     Nfc* nfc = context; |  | ||||||
|     if(type == InputTypeShort) { |  | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void nfc_scene_device_info_on_enter(void* context) { | void nfc_scene_device_info_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
| 
 | 
 | ||||||
|     bool data_display_supported = (nfc->dev->format == NfcDeviceSaveFormatUid) || |     string_t temp_str; | ||||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatMifareUl) || |     string_init(temp_str); | ||||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) || |  | ||||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatBankCard); |  | ||||||
|     // Setup Custom Widget view
 |  | ||||||
|     widget_add_text_box_element( |  | ||||||
|         nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false); |  | ||||||
|     widget_add_button_element( |  | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); |  | ||||||
|     if(data_display_supported) { |  | ||||||
|         widget_add_button_element( |  | ||||||
|             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); |  | ||||||
|     } |  | ||||||
|     char temp_str[32]; |  | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |  | ||||||
|     if(data->uid_len == 4) { |  | ||||||
|         snprintf( |  | ||||||
|             temp_str, |  | ||||||
|             sizeof(temp_str), |  | ||||||
|             "UID: %02X %02X %02X %02X", |  | ||||||
|             data->uid[0], |  | ||||||
|             data->uid[1], |  | ||||||
|             data->uid[2], |  | ||||||
|             data->uid[3]); |  | ||||||
|     } else if(data->uid_len == 7) { |  | ||||||
|         snprintf( |  | ||||||
|             temp_str, |  | ||||||
|             sizeof(temp_str), |  | ||||||
|             "UID: %02X %02X %02X %02X %02X %02X %02X", |  | ||||||
|             data->uid[0], |  | ||||||
|             data->uid[1], |  | ||||||
|             data->uid[2], |  | ||||||
|             data->uid[3], |  | ||||||
|             data->uid[4], |  | ||||||
|             data->uid[5], |  | ||||||
|             data->uid[6]); |  | ||||||
|     } |  | ||||||
|     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str); |  | ||||||
| 
 | 
 | ||||||
|     const char* protocol_name = NULL; |     if(dev_data->protocol == NfcDeviceProtocolEMV) { | ||||||
|     NfcProtocol protocol = nfc->dev->dev_data.protocol; |         EmvData* emv_data = &dev_data->emv_data; | ||||||
|     if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { |         string_printf(temp_str, "\e#%s\n", emv_data->name); | ||||||
|         protocol_name = nfc_guess_protocol(protocol); |         for(uint8_t i = 0; i < emv_data->number_len; i += 2) { | ||||||
|     } else if(protocol == NfcDeviceProtocolMifareUl) { |             string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); | ||||||
|         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); |  | ||||||
|     } else if(protocol == NfcDeviceProtocolMifareClassic) { |  | ||||||
|         protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); |  | ||||||
|         } |         } | ||||||
|     if(protocol_name) { |         string_strim(temp_str); | ||||||
|         widget_add_string_element( |  | ||||||
|             nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); |  | ||||||
|     } |  | ||||||
|     // TODO change dinamically
 |  | ||||||
|     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); |  | ||||||
|     widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str); |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); |  | ||||||
|     widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str); |  | ||||||
| 
 | 
 | ||||||
|     // Setup Data View
 |         // Add expiration date
 | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { |  | ||||||
|         DialogEx* dialog_ex = nfc->dialog_ex; |  | ||||||
|         dialog_ex_set_left_button_text(dialog_ex, "Back"); |  | ||||||
|         dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter); |  | ||||||
|         dialog_ex_set_context(dialog_ex, nfc); |  | ||||||
|         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |  | ||||||
|         MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; |  | ||||||
|         TextBox* text_box = nfc->text_box; |  | ||||||
|         text_box_set_font(text_box, TextBoxFontHex); |  | ||||||
|         for(uint16_t i = 0; i < mf_ul_data->data_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->data[i], mf_ul_data->data[i + 1]); |  | ||||||
|         } |  | ||||||
|         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { |  | ||||||
|         MifareDesfireData* mf_df_data = &nfc->dev->dev_data.mf_df_data; |  | ||||||
|         uint16_t n_apps = 0; |  | ||||||
|         uint16_t n_files = 0; |  | ||||||
|         for(MifareDesfireApplication* app = mf_df_data->app_head; app; app = app->next) { |  | ||||||
|             n_apps++; |  | ||||||
|             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { |  | ||||||
|                 n_files++; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         nfc_text_store_set( |  | ||||||
|             nfc, |  | ||||||
|             "%d application%s, %d file%s", |  | ||||||
|             n_apps, |  | ||||||
|             n_apps == 1 ? "" : "s", |  | ||||||
|             n_files, |  | ||||||
|             n_files == 1 ? "" : "s"); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |  | ||||||
|         EmvData* emv_data = &nfc->dev->dev_data.emv_data; |  | ||||||
|         BankCard* bank_card = nfc->bank_card; |  | ||||||
|         bank_card_set_name(bank_card, emv_data->name); |  | ||||||
|         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); |  | ||||||
|         bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc); |  | ||||||
|         if(emv_data->exp_mon) { |         if(emv_data->exp_mon) { | ||||||
|             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year); |             string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); | ||||||
|         } |         } | ||||||
|         string_t display_str; |         // Parse currency code
 | ||||||
|         string_init(display_str); |         if((emv_data->currency_code)) { | ||||||
|         if(emv_data->country_code) { |             string_t currency_name; | ||||||
|  |             string_init(currency_name); | ||||||
|  |             if(nfc_emv_parser_get_currency_name( | ||||||
|  |                    nfc->dev->storage, emv_data->currency_code, currency_name)) { | ||||||
|  |                 string_cat_printf(temp_str, "\nCur: %s  ", string_get_cstr(currency_name)); | ||||||
|  |             } | ||||||
|  |             string_clear(currency_name); | ||||||
|  |         } | ||||||
|  |         // Parse country code
 | ||||||
|  |         if((emv_data->country_code)) { | ||||||
|             string_t country_name; |             string_t country_name; | ||||||
|             string_init(country_name); |             string_init(country_name); | ||||||
|             if(nfc_emv_parser_get_country_name( |             if(nfc_emv_parser_get_country_name( | ||||||
|                    nfc->dev->storage, emv_data->country_code, country_name)) { |                    nfc->dev->storage, emv_data->country_code, country_name)) { | ||||||
|                 string_printf(display_str, "Reg:%s", string_get_cstr(country_name)); |                 string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name)); | ||||||
|                 bank_card_set_country_name(bank_card, string_get_cstr(display_str)); |  | ||||||
|             } |             } | ||||||
|             string_clear(country_name); |             string_clear(country_name); | ||||||
|         } |         } | ||||||
|         if(emv_data->currency_code) { |     } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { | ||||||
|             string_t currency_name; |         string_set(temp_str, nfc->dev->dev_data.parsed_data); | ||||||
|             string_init(currency_name); |  | ||||||
|             if(nfc_emv_parser_get_currency_name( |  | ||||||
|                    nfc->dev->storage, emv_data->country_code, currency_name)) { |  | ||||||
|                 string_printf(display_str, "Cur:%s", string_get_cstr(currency_name)); |  | ||||||
|                 bank_card_set_currency_name(bank_card, string_get_cstr(display_str)); |  | ||||||
|     } |     } | ||||||
|             string_clear(currency_name); | 
 | ||||||
|         } |     widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|         string_clear(display_str); |     string_clear(temp_str); | ||||||
|     } | 
 | ||||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |     widget_add_button_element( | ||||||
|  |         nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc); | ||||||
|  | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); |  | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { |         if(event.event == GuiButtonTypeRight) { | ||||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|         } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) { |  | ||||||
|             if(nfc->dev->format == NfcDeviceSaveFormatUid) { |  | ||||||
|                 scene_manager_set_scene_state( |  | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |  | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |  | ||||||
|                 consumed = true; |  | ||||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |  | ||||||
|                 scene_manager_set_scene_state( |  | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |  | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |  | ||||||
|                 consumed = true; |  | ||||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |  | ||||||
|                 scene_manager_set_scene_state( |  | ||||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); |  | ||||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); |  | ||||||
|                 consumed = true; |  | ||||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { |  | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); |  | ||||||
|                 consumed = true; |  | ||||||
|             } |  | ||||||
|         } else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) { |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |  | ||||||
|             consumed = true; |  | ||||||
|         } |  | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |  | ||||||
|         if(state == NfcSceneDeviceInfoData) { |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -215,12 +78,4 @@ void nfc_scene_device_info_on_exit(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Clear views
 |     // Clear views
 | ||||||
|     widget_reset(nfc->widget); |     widget_reset(nfc->widget); | ||||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid) { |  | ||||||
|         dialog_ex_reset(nfc->dialog_ex); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |  | ||||||
|         text_box_reset(nfc->text_box); |  | ||||||
|         string_reset(nfc->text_box_store); |  | ||||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { |  | ||||||
|         bank_card_clear(nfc->bank_card); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										54
									
								
								applications/nfc/scenes/nfc_scene_emv_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								applications/nfc/scenes/nfc_scene_emv_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexSave, | ||||||
|  |     SubmenuIndexInfo, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_emv_menu_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     Submenu* submenu = nfc->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_emv_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); | ||||||
|  |     submenu_set_selected_item( | ||||||
|  |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMenu)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SubmenuIndexSave) { | ||||||
|  |             nfc->dev->format = NfcDeviceSaveFormatBankCard; | ||||||
|  |             // Clear device name
 | ||||||
|  |             nfc_device_set_name(nfc->dev, ""); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneEmvMenu, event.event); | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_emv_menu_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     submenu_reset(nfc->submenu); | ||||||
|  | } | ||||||
| @ -15,85 +15,48 @@ void nfc_scene_emv_read_success_widget_callback( | |||||||
| void nfc_scene_emv_read_success_on_enter(void* context) { | void nfc_scene_emv_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     EmvData* emv_data = &nfc->dev->dev_data.emv_data; |     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||||
|     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; |  | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Setup Custom Widget view
 |     // Setup Custom Widget view
 | ||||||
|     // Add frame
 |  | ||||||
|     widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6); |  | ||||||
|     // Add buttons
 |  | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); |         nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc); |         nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc); | ||||||
|     // Add card name
 | 
 | ||||||
|     widget_add_string_element( |     string_t temp_str; | ||||||
|         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); |     string_init_printf(temp_str, "\e#%s\n", emv_data->name); | ||||||
|     // Add card number
 |  | ||||||
|     string_t pan_str; |  | ||||||
|     string_init(pan_str); |  | ||||||
|     for(uint8_t i = 0; i < emv_data->number_len; i += 2) { |     for(uint8_t i = 0; i < emv_data->number_len; i += 2) { | ||||||
|         string_cat_printf(pan_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); |         string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); | ||||||
|     } |     } | ||||||
|     string_strim(pan_str); |     string_strim(temp_str); | ||||||
|     widget_add_string_element( | 
 | ||||||
|         nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, string_get_cstr(pan_str)); |  | ||||||
|     string_clear(pan_str); |  | ||||||
|     // Parse country code
 |  | ||||||
|     string_t country_name; |  | ||||||
|     string_init(country_name); |  | ||||||
|     if((emv_data->country_code) && |  | ||||||
|        nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) { |  | ||||||
|         string_t disp_country; |  | ||||||
|         string_init_printf(disp_country, "Reg:%s", country_name); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             nfc->widget, 7, 23, AlignLeft, AlignTop, FontSecondary, string_get_cstr(disp_country)); |  | ||||||
|         string_clear(disp_country); |  | ||||||
|     } |  | ||||||
|     string_clear(country_name); |  | ||||||
|     // Parse currency code
 |  | ||||||
|     string_t currency_name; |  | ||||||
|     string_init(currency_name); |  | ||||||
|     if((emv_data->currency_code) && |  | ||||||
|        nfc_emv_parser_get_currency_name( |  | ||||||
|            nfc->dev->storage, emv_data->currency_code, currency_name)) { |  | ||||||
|         string_t disp_currency; |  | ||||||
|         string_init_printf(disp_currency, "Cur:%s", currency_name); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             nfc->widget, |  | ||||||
|             121, |  | ||||||
|             23, |  | ||||||
|             AlignRight, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             string_get_cstr(disp_currency)); |  | ||||||
|         string_clear(disp_currency); |  | ||||||
|     } |  | ||||||
|     string_clear(currency_name); |  | ||||||
|     char temp_str[32]; |  | ||||||
|     // Add ATQA
 |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); |  | ||||||
|     widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str); |  | ||||||
|     // Add UID
 |  | ||||||
|     snprintf( |  | ||||||
|         temp_str, |  | ||||||
|         sizeof(temp_str), |  | ||||||
|         "UID: %02X %02X %02X %02X", |  | ||||||
|         nfc_data->uid[0], |  | ||||||
|         nfc_data->uid[1], |  | ||||||
|         nfc_data->uid[2], |  | ||||||
|         nfc_data->uid[3]); |  | ||||||
|     widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str); |  | ||||||
|     // Add SAK
 |  | ||||||
|     snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak); |  | ||||||
|     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str); |  | ||||||
|     // Add expiration date
 |     // Add expiration date
 | ||||||
|     if(emv_data->exp_mon) { |     if(emv_data->exp_mon) { | ||||||
|         char exp_str[16]; |         string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); | ||||||
|         snprintf( |  | ||||||
|             exp_str, sizeof(exp_str), "Exp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); |  | ||||||
|         widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str); |  | ||||||
|     } |     } | ||||||
|  |     // Parse currency code
 | ||||||
|  |     if((emv_data->currency_code)) { | ||||||
|  |         string_t currency_name; | ||||||
|  |         string_init(currency_name); | ||||||
|  |         if(nfc_emv_parser_get_currency_name( | ||||||
|  |                nfc->dev->storage, emv_data->currency_code, currency_name)) { | ||||||
|  |             string_cat_printf(temp_str, "\nCur: %s  ", string_get_cstr(currency_name)); | ||||||
|  |         } | ||||||
|  |         string_clear(currency_name); | ||||||
|  |     } | ||||||
|  |     // Parse country code
 | ||||||
|  |     if((emv_data->country_code)) { | ||||||
|  |         string_t country_name; | ||||||
|  |         string_init(country_name); | ||||||
|  |         if(nfc_emv_parser_get_country_name( | ||||||
|  |                nfc->dev->storage, emv_data->country_code, country_name)) { | ||||||
|  |             string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name)); | ||||||
|  |         } | ||||||
|  |         string_clear(country_name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|  |     string_clear(temp_str); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| @ -107,10 +70,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) | |||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             // Clear device name
 |             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvMenu); | ||||||
|             nfc_device_set_name(nfc->dev, ""); |  | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatBankCard; |  | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ void nfc_scene_file_select_on_enter(void* context) { | |||||||
|     // Process file_select return
 |     // Process file_select return
 | ||||||
|     nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); |     nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); | ||||||
|     if(nfc_file_select(nfc->dev)) { |     if(nfc_file_select(nfc->dev)) { | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); | ||||||
|     } else { |     } else { | ||||||
|         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); |         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); | ||||||
|  | |||||||
| @ -1,72 +0,0 @@ | |||||||
| #include "../nfc_i.h" |  | ||||||
| 
 |  | ||||||
| void nfc_scene_mf_classic_info_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_scene_mf_classic_info_on_enter(void* context) { |  | ||||||
|     Nfc* nfc = context; |  | ||||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; |  | ||||||
|     MfClassicData* mf_data = &dev_data->mf_classic_data; |  | ||||||
|     string_t str_tmp; |  | ||||||
|     string_init(str_tmp); |  | ||||||
| 
 |  | ||||||
|     // Setup view
 |  | ||||||
|     Widget* widget = nfc->widget; |  | ||||||
| 
 |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 0, AlignLeft, AlignTop, FontSecondary, mf_classic_get_type_str(mf_data->type)); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); |  | ||||||
|     string_printf(str_tmp, "UID:"); |  | ||||||
|     for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { |  | ||||||
|         string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); |  | ||||||
|     } |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|     string_printf( |  | ||||||
|         str_tmp, |  | ||||||
|         "ATQA: %02X %02X   SAK: %02X", |  | ||||||
|         dev_data->nfc_data.atqa[0], |  | ||||||
|         dev_data->nfc_data.atqa[1], |  | ||||||
|         dev_data->nfc_data.sak); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|     uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); |  | ||||||
|     uint8_t keys_total = sectors_total * 2; |  | ||||||
|     uint8_t keys_found = 0; |  | ||||||
|     uint8_t sectors_read = 0; |  | ||||||
|     mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); |  | ||||||
|     string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|     string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 55, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
| 
 |  | ||||||
|     string_clear(str_tmp); |  | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool nfc_scene_mf_classic_info_on_event(void* context, SceneManagerEvent event) { |  | ||||||
|     Nfc* nfc = context; |  | ||||||
|     bool consumed = false; |  | ||||||
| 
 |  | ||||||
|     if(event.type == SceneManagerEventTypeBack) { |  | ||||||
|         consumed = scene_manager_previous_scene(nfc->scene_manager); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return consumed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void nfc_scene_mf_classic_info_on_exit(void* context) { |  | ||||||
|     Nfc* nfc = context; |  | ||||||
| 
 |  | ||||||
|     // Clear view
 |  | ||||||
|     widget_reset(nfc->widget); |  | ||||||
| } |  | ||||||
| @ -34,6 +34,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { | |||||||
|     widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); |     widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); |         nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); | ||||||
|  |     widget_add_icon_element(nfc->widget, 90, 12, &I_Keychain); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|         } else if(event.event == SubmenuIndexInfo) { |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); |                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  | |||||||
| @ -17,8 +17,6 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
|     MfClassicData* mf_data = &dev_data->mf_classic_data; |     MfClassicData* mf_data = &dev_data->mf_classic_data; | ||||||
|     string_t str_tmp; |  | ||||||
|     string_init(str_tmp); |  | ||||||
| 
 | 
 | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
| @ -29,48 +27,27 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { | |||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); |         widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); | ||||||
| 
 | 
 | ||||||
|  |     string_t temp_str; | ||||||
|     if(string_size(nfc->dev->dev_data.parsed_data)) { |     if(string_size(nfc->dev->dev_data.parsed_data)) { | ||||||
|         widget_add_text_box_element( |         string_init_set(temp_str, nfc->dev->dev_data.parsed_data); | ||||||
|             nfc->widget, |  | ||||||
|             0, |  | ||||||
|             0, |  | ||||||
|             128, |  | ||||||
|             32, |  | ||||||
|             AlignLeft, |  | ||||||
|             AlignTop, |  | ||||||
|             string_get_cstr(nfc->dev->dev_data.parsed_data), |  | ||||||
|             true); |  | ||||||
|     } else { |     } else { | ||||||
|         widget_add_string_element( |         string_init_printf(temp_str, "\e#%s\n", nfc_mf_classic_type(mf_data->type)); | ||||||
|             widget, |         string_cat_printf(temp_str, "UID:"); | ||||||
|             0, |  | ||||||
|             0, |  | ||||||
|             AlignLeft, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             mf_classic_get_type_str(mf_data->type)); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)"); |  | ||||||
|         string_printf(str_tmp, "UID:"); |  | ||||||
|         for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { |         for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { | ||||||
|             string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]); |             string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); | ||||||
|         } |         } | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|         uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); |         uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); | ||||||
|         uint8_t keys_total = sectors_total * 2; |         uint8_t keys_total = sectors_total * 2; | ||||||
|         uint8_t keys_found = 0; |         uint8_t keys_found = 0; | ||||||
|         uint8_t sectors_read = 0; |         uint8_t sectors_read = 0; | ||||||
|         mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); |         mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); | ||||||
|         string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total); |         string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); | ||||||
|         widget_add_string_element( |         string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); | ||||||
|             widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|         string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     string_clear(str_tmp); |     widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|  |     string_clear(temp_str); | ||||||
|  | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| enum SubmenuIndex { | enum SubmenuIndex { | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
|  |     SubmenuIndexEmulateUid, | ||||||
|  |     SubmenuIndexInfo, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { | void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -16,6 +18,15 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); |         submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Emulate UID", | ||||||
|  |         SubmenuIndexEmulateUid, | ||||||
|  |         nfc_scene_mf_desfire_menu_submenu_callback, | ||||||
|  |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); | ||||||
|  | 
 | ||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); | ||||||
| 
 | 
 | ||||||
| @ -35,6 +46,12 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) | |||||||
|             nfc_device_set_name(nfc->dev, ""); |             nfc_device_set_name(nfc->dev, ""); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexEmulateUid) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,91 +1,86 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | void nfc_scene_mf_desfire_read_success_widget_callback( | ||||||
| 
 |     GuiButtonType result, | ||||||
| enum { |     InputType type, | ||||||
|     MfDesfireReadSuccessStateShowUID, |     void* context) { | ||||||
|     MfDesfireReadSuccessStateShowData, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) { |  | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     if(type == InputTypeShort) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_desfire_read_success_on_enter(void* context) { | void nfc_scene_mf_desfire_read_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; |     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     Widget* widget = nfc->widget; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | 
 | ||||||
|     dialog_ex_set_center_button_text(dialog_ex, "Data"); |     // Prepare string for data display
 | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |     string_t temp_str; | ||||||
|     dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); |     string_init_printf(temp_str, "\e#MIFARE DESfire\n"); | ||||||
|  |     string_cat_printf(temp_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < nfc_data->uid_len; i++) { | ||||||
|  |         string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); | ||||||
|  |     uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; | ||||||
|  |     string_cat_printf(temp_str, "\n%d", bytes_total); | ||||||
|  |     if(data->version.sw_storage & 1) { | ||||||
|  |         string_push_back(temp_str, '+'); | ||||||
|  |     } | ||||||
|  |     string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free); | ||||||
| 
 | 
 | ||||||
|     uint16_t n_apps = 0; |     uint16_t n_apps = 0; | ||||||
|     uint16_t n_files = 0; |     uint16_t n_files = 0; | ||||||
| 
 |  | ||||||
|     for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { |     for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||||
|         n_apps++; |         n_apps++; | ||||||
|         for(MifareDesfireFile* file = app->file_head; file; file = file->next) { |         for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||||
|             n_files++; |             n_files++; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     string_cat_printf(temp_str, "%d Application", n_apps); | ||||||
|  |     if(n_apps != 1) { | ||||||
|  |         string_push_back(temp_str, 's'); | ||||||
|  |     } | ||||||
|  |     string_cat_printf(temp_str, ", %d file", n_files); | ||||||
|  |     if(n_files != 1) { | ||||||
|  |         string_push_back(temp_str, 's'); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // TODO rework info view
 |     // Add text scroll element
 | ||||||
|     nfc_text_store_set( |     widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|         nfc, |     string_clear(temp_str); | ||||||
|         NFC_SCENE_READ_SUCCESS_SHIFT "Mifare DESFire\n" NFC_SCENE_READ_SUCCESS_SHIFT |  | ||||||
|                                      "%d%s bytes\n" NFC_SCENE_READ_SUCCESS_SHIFT "%d bytes free\n" |  | ||||||
|                                      "%d application%s, %d file%s", |  | ||||||
|         1 << (data->version.sw_storage >> 1), |  | ||||||
|         (data->version.sw_storage & 1) ? "+" : "", |  | ||||||
|         data->free_memory ? data->free_memory->bytes : 0, |  | ||||||
|         n_apps, |  | ||||||
|         n_apps == 1 ? "" : "s", |  | ||||||
|         n_files, |  | ||||||
|         n_files == 1 ? "" : "s"); |  | ||||||
|     dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop); |  | ||||||
|     dialog_ex_set_context(dialog_ex, nfc); |  | ||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback); |  | ||||||
| 
 | 
 | ||||||
|     scene_manager_set_scene_state( |     // Add button elements
 | ||||||
|         nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID); |     widget_add_button_element( | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |         widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); | ||||||
|  |     widget_add_button_element( | ||||||
|  |         widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     uint32_t state = |  | ||||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); |  | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); |  | ||||||
|             consumed = true; |  | ||||||
|         } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) { |  | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(state == MfDesfireReadSuccessStateShowData) { |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, |  | ||||||
|                 NfcSceneMfDesfireReadSuccess, |  | ||||||
|                 MfDesfireReadSuccessStateShowUID); |  | ||||||
|             consumed = true; |  | ||||||
|         } else { |  | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| @ -94,5 +89,5 @@ void nfc_scene_mf_desfire_read_success_on_exit(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clean dialog
 |     // Clean dialog
 | ||||||
|     dialog_ex_reset(nfc->dialog_ex); |     widget_reset(nfc->widget); | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										32
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_data.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								applications/nfc/scenes/nfc_scene_mf_ultralight_data.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_data_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|  |     TextBox* text_box = nfc->text_box; | ||||||
|  | 
 | ||||||
|  |     text_box_set_font(text_box, TextBoxFontHex); | ||||||
|  |     for(uint16_t i = 0; i < data->data_size; i += 2) { | ||||||
|  |         if(!(i % 8) && i) { | ||||||
|  |             string_push_back(nfc->text_box_store, '\n'); | ||||||
|  |         } | ||||||
|  |         string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]); | ||||||
|  |     } | ||||||
|  |     text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     UNUSED(context); | ||||||
|  |     UNUSED(event); | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_mf_ultralight_data_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clean view
 | ||||||
|  |     text_box_reset(nfc->text_box); | ||||||
|  |     string_reset(nfc->text_box_store); | ||||||
|  | } | ||||||
| @ -4,6 +4,7 @@ enum SubmenuIndex { | |||||||
|     SubmenuIndexUnlock, |     SubmenuIndexUnlock, | ||||||
|     SubmenuIndexSave, |     SubmenuIndexSave, | ||||||
|     SubmenuIndexEmulate, |     SubmenuIndexEmulate, | ||||||
|  |     SubmenuIndexInfo, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { | void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { | ||||||
| @ -33,6 +34,9 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { | |||||||
|         SubmenuIndexEmulate, |         SubmenuIndexEmulate, | ||||||
|         nfc_scene_mf_ultralight_menu_submenu_callback, |         nfc_scene_mf_ultralight_menu_submenu_callback, | ||||||
|         nfc); |         nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); | ||||||
|  | 
 | ||||||
|     submenu_set_selected_item( |     submenu_set_selected_item( | ||||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); | ||||||
| 
 | 
 | ||||||
| @ -56,6 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even | |||||||
|         } else if(event.event == SubmenuIndexUnlock) { |         } else if(event.event == SubmenuIndexUnlock) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,11 +1,6 @@ | |||||||
| #include "../nfc_i.h" | #include "../nfc_i.h" | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| enum { |  | ||||||
|     ReadMifareUlStateShowInfo, |  | ||||||
|     ReadMifareUlStateShowData, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void nfc_scene_mf_ultralight_read_success_widget_callback( | void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||||
|     GuiButtonType result, |     GuiButtonType result, | ||||||
|     InputType type, |     InputType type, | ||||||
| @ -31,12 +26,6 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | |||||||
|         "Retry", |         "Retry", | ||||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, |         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||||
|         nfc); |         nfc); | ||||||
|     widget_add_button_element( |  | ||||||
|         widget, |  | ||||||
|         GuiButtonTypeCenter, |  | ||||||
|         "Data", |  | ||||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, |  | ||||||
|         nfc); |  | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         widget, |         widget, | ||||||
|         GuiButtonTypeRight, |         GuiButtonTypeRight, | ||||||
| @ -44,72 +33,39 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | |||||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, |         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||||
|         nfc); |         nfc); | ||||||
| 
 | 
 | ||||||
|     widget_add_string_element( |     string_t temp_str; | ||||||
|         widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); |     string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); | ||||||
|     string_t data_str; |     string_cat_printf(temp_str, "UID:"); | ||||||
|     string_init_printf(data_str, "UID:"); |  | ||||||
|     for(size_t i = 0; i < data->uid_len; i++) { |     for(size_t i = 0; i < data->uid_len; i++) { | ||||||
|         string_cat_printf(data_str, " %02X", data->uid[i]); |         string_cat_printf(temp_str, " %02X", data->uid[i]); | ||||||
|     } |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 13, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); |  | ||||||
|     string_printf( |  | ||||||
|         data_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         widget, 0, 24, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); |  | ||||||
|     if(mf_ul_data->data_read != mf_ul_data->data_size) { |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!"); |  | ||||||
|     } |  | ||||||
|     string_clear(data_str); |  | ||||||
| 
 |  | ||||||
|     // Setup TextBox view
 |  | ||||||
|     TextBox* text_box = nfc->text_box; |  | ||||||
|     text_box_set_font(text_box, TextBoxFontHex); |  | ||||||
|     for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { |  | ||||||
|         if(!(i % 8) && i) { |  | ||||||
|             string_push_back(nfc->text_box_store, '\n'); |  | ||||||
|     } |     } | ||||||
|     string_cat_printf( |     string_cat_printf( | ||||||
|             nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); |         temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); | ||||||
|  |     if(mf_ul_data->data_read != mf_ul_data->data_size) { | ||||||
|  |         string_cat_printf(temp_str, "\nPassword-protected pages!"); | ||||||
|     } |     } | ||||||
|     text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); |     widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|  |     string_clear(temp_str); | ||||||
| 
 | 
 | ||||||
|     scene_manager_set_scene_state( |  | ||||||
|         nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); |  | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
|     uint32_t state = |  | ||||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); |  | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeCenter) { |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData); |  | ||||||
|             consumed = true; |  | ||||||
|         } |         } | ||||||
|     } else if(event.type == SceneManagerEventTypeBack) { |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|         if(state == ReadMifareUlStateShowData) { |  | ||||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |  | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); |  | ||||||
|             consumed = true; |  | ||||||
|         } else { |  | ||||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); |         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||||
|         consumed = true; |         consumed = true; | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| @ -117,8 +73,6 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv | |||||||
| void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { | void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     // Clean views
 |     // Clean view
 | ||||||
|     widget_reset(nfc->widget); |     widget_reset(nfc->widget); | ||||||
|     text_box_reset(nfc->text_box); |  | ||||||
|     string_reset(nfc->text_box_store); |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										133
									
								
								applications/nfc/scenes/nfc_scene_nfc_data_info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								applications/nfc/scenes/nfc_scene_nfc_data_info.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     if(type == InputTypeShort) { | ||||||
|  |         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfc_data_info_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     Widget* widget = nfc->widget; | ||||||
|  |     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||||
|  |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
|  |     NfcProtocol protocol = dev_data->protocol; | ||||||
|  |     uint8_t text_scroll_height = 0; | ||||||
|  |     if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) { | ||||||
|  |         widget_add_button_element( | ||||||
|  |             widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); | ||||||
|  |         text_scroll_height = 52; | ||||||
|  |     } else { | ||||||
|  |         text_scroll_height = 64; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  |     // Set name if present
 | ||||||
|  |     if(nfc->dev->dev_name[0] != '\0') { | ||||||
|  |         string_printf(temp_str, "\ec%s\n", nfc->dev->dev_name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Set tag type
 | ||||||
|  |     if(protocol == NfcDeviceProtocolEMV) { | ||||||
|  |         string_cat_printf(temp_str, "\e#EMV Bank Card\n"); | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|  |         string_cat_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true)); | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareClassic) { | ||||||
|  |         string_cat_printf( | ||||||
|  |             temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||||
|  |         string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); | ||||||
|  |     } else { | ||||||
|  |         string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Set tag iso data
 | ||||||
|  |     char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; | ||||||
|  |     string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); | ||||||
|  |     string_cat_printf(temp_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < nfc_data->uid_len; i++) { | ||||||
|  |         string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); | ||||||
|  |     } | ||||||
|  |     string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); | ||||||
|  |     string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); | ||||||
|  | 
 | ||||||
|  |     // Set application specific data
 | ||||||
|  |     if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||||
|  |         MifareDesfireData* data = &dev_data->mf_df_data; | ||||||
|  |         uint32_t bytes_total = 1 << (data->version.sw_storage >> 1); | ||||||
|  |         uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; | ||||||
|  |         string_cat_printf(temp_str, "\n%d", bytes_total); | ||||||
|  |         if(data->version.sw_storage & 1) { | ||||||
|  |             string_push_back(temp_str, '+'); | ||||||
|  |         } | ||||||
|  |         string_cat_printf(temp_str, " bytes, %d bytes free\n", bytes_free); | ||||||
|  | 
 | ||||||
|  |         uint16_t n_apps = 0; | ||||||
|  |         uint16_t n_files = 0; | ||||||
|  |         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||||
|  |             n_apps++; | ||||||
|  |             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||||
|  |                 n_files++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         string_cat_printf(temp_str, "%d Application", n_apps); | ||||||
|  |         if(n_apps != 1) { | ||||||
|  |             string_push_back(temp_str, 's'); | ||||||
|  |         } | ||||||
|  |         string_cat_printf(temp_str, ", %d file", n_files); | ||||||
|  |         if(n_files != 1) { | ||||||
|  |             string_push_back(temp_str, 's'); | ||||||
|  |         } | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|  |         MfUltralightData* data = &dev_data->mf_ul_data; | ||||||
|  |         string_cat_printf( | ||||||
|  |             temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4); | ||||||
|  |         if(data->data_size > data->data_read) { | ||||||
|  |             string_cat_printf(temp_str, "\nPassword-protected"); | ||||||
|  |         } | ||||||
|  |     } else if(protocol == NfcDeviceProtocolMifareClassic) { | ||||||
|  |         MfClassicData* data = &dev_data->mf_classic_data; | ||||||
|  |         uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); | ||||||
|  |         uint8_t keys_total = sectors_total * 2; | ||||||
|  |         uint8_t keys_found = 0; | ||||||
|  |         uint8_t sectors_read = 0; | ||||||
|  |         mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); | ||||||
|  |         string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); | ||||||
|  |         string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Add text scroll widget
 | ||||||
|  |     widget_add_text_scroll_element( | ||||||
|  |         widget, 0, 0, 128, text_scroll_height, string_get_cstr(temp_str)); | ||||||
|  |     string_clear(temp_str); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     NfcProtocol protocol = nfc->dev->dev_data.protocol; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == GuiButtonTypeRight) { | ||||||
|  |             if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||||
|  |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); | ||||||
|  |                 consumed = true; | ||||||
|  |             } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|  |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); | ||||||
|  |                 consumed = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfc_data_info_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     widget_reset(nfc->widget); | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								applications/nfc/scenes/nfc_scene_nfca_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								applications/nfc/scenes/nfc_scene_nfca_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexSaveUid, | ||||||
|  |     SubmenuIndexEmulateUid, | ||||||
|  |     SubmenuIndexInfo, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfca_menu_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     Submenu* submenu = nfc->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Save UID", SubmenuIndexSaveUid, nfc_scene_nfca_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Emulate UID", SubmenuIndexEmulateUid, nfc_scene_nfca_menu_submenu_callback, nfc); | ||||||
|  |     submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfca_menu_submenu_callback, nfc); | ||||||
|  | 
 | ||||||
|  |     submenu_set_selected_item( | ||||||
|  |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaMenu)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SubmenuIndexSaveUid) { | ||||||
|  |             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||||
|  |             // Clear device name
 | ||||||
|  |             nfc_device_set_name(nfc->dev, ""); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexEmulateUid) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event); | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfca_menu_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     submenu_reset(nfc->submenu); | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								applications/nfc/scenes/nfc_scene_nfca_read_success.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								applications/nfc/scenes/nfc_scene_nfca_read_success.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | #include "../nfc_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfca_read_success_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_scene_nfca_read_success_on_enter(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|  |     Widget* widget = nfc->widget; | ||||||
|  | 
 | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init_set_str(temp_str, "\e#Unknown ISO tag\n"); | ||||||
|  | 
 | ||||||
|  |     char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3'; | ||||||
|  |     string_cat_printf(temp_str, "ISO 14443-%c (NFC-A)\n", iso_type); | ||||||
|  |     string_cat_printf(temp_str, "UID:"); | ||||||
|  |     for(size_t i = 0; i < data->uid_len; i++) { | ||||||
|  |         string_cat_printf(temp_str, " %02X", data->uid[i]); | ||||||
|  |     } | ||||||
|  |     string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); | ||||||
|  |     string_cat_printf(temp_str, " SAK: %02X", data->sak); | ||||||
|  | 
 | ||||||
|  |     widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||||
|  |     string_clear(temp_str); | ||||||
|  | 
 | ||||||
|  |     widget_add_button_element( | ||||||
|  |         widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfca_read_success_widget_callback, nfc); | ||||||
|  |     widget_add_button_element( | ||||||
|  |         widget, GuiButtonTypeRight, "More", nfc_scene_nfca_read_success_widget_callback, nfc); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == GuiButtonTypeLeft) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaMenu); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void nfc_scene_nfca_read_success_on_exit(void* context) { | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     widget_reset(nfc->widget); | ||||||
|  | } | ||||||
| @ -59,11 +59,14 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if((event.event == NfcWorkerEventReadUidNfcB) || |         if((event.event == NfcWorkerEventReadUidNfcB) || | ||||||
|            (event.event == NfcWorkerEventReadUidNfcF) || |            (event.event == NfcWorkerEventReadUidNfcF) || | ||||||
|            (event.event == NfcWorkerEventReadUidNfcV) || |            (event.event == NfcWorkerEventReadUidNfcV)) { | ||||||
|            (event.event == NfcWorkerEventReadUidNfcA)) { |  | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|  |         } else if(event.event == NfcWorkerEventReadUidNfcA) { | ||||||
|  |             notification_message(nfc->notifications, &sequence_success); | ||||||
|  |             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); | ||||||
|  |             consumed = true; | ||||||
|         } else if(event.event == NfcWorkerEventReadMfUltralight) { |         } else if(event.event == NfcWorkerEventReadMfUltralight) { | ||||||
|             notification_message(nfc->notifications, &sequence_success); |             notification_message(nfc->notifications, &sequence_success); | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||||
|  | |||||||
| @ -16,44 +16,26 @@ void nfc_scene_read_card_success_widget_callback( | |||||||
| void nfc_scene_read_card_success_on_enter(void* context) { | void nfc_scene_read_card_success_on_enter(void* context) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     string_t data_str; |     string_t temp_str; | ||||||
|     string_t uid_str; |     string_init(temp_str); | ||||||
|     string_init(data_str); |  | ||||||
|     string_init(uid_str); |  | ||||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); |     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||||
| 
 | 
 | ||||||
|     // Setup view
 |     // Setup view
 | ||||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; |     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|     Widget* widget = nfc->widget; |     Widget* widget = nfc->widget; | ||||||
|     string_set_str(data_str, nfc_get_dev_type(data->type)); |     string_set_str(temp_str, nfc_get_dev_type(data->type)); | ||||||
|     string_set_str(uid_str, "UID:"); |     widget_add_string_element( | ||||||
|  |         widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(temp_str)); | ||||||
|  |     string_set_str(temp_str, "UID:"); | ||||||
|     for(uint8_t i = 0; i < data->uid_len; i++) { |     for(uint8_t i = 0; i < data->uid_len; i++) { | ||||||
|         string_cat_printf(uid_str, " %02X", data->uid[i]); |         string_cat_printf(temp_str, " %02X", data->uid[i]); | ||||||
|     } |     } | ||||||
| 
 |     widget_add_string_element( | ||||||
|  |         widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(temp_str)); | ||||||
|     widget_add_button_element( |     widget_add_button_element( | ||||||
|         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); |         widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); | ||||||
|     if(data->type == FuriHalNfcTypeA) { |  | ||||||
|         widget_add_button_element( |  | ||||||
|             widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc); |  | ||||||
|         widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str)); |  | ||||||
|         string_printf( |  | ||||||
|             data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak); |  | ||||||
|         widget_add_string_multiline_element( |  | ||||||
|             widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str)); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 64, 46, AlignCenter, AlignBottom, FontSecondary, string_get_cstr(uid_str)); |  | ||||||
|     } else { |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, string_get_cstr(data_str)); |  | ||||||
|         widget_add_string_element( |  | ||||||
|             widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(uid_str)); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     string_clear(data_str); |     string_clear(temp_str); | ||||||
|     string_clear(uid_str); |  | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||||
| } | } | ||||||
| @ -65,11 +47,6 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); |             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||||
|         } else if(event.event == GuiButtonTypeRight) { |  | ||||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; |  | ||||||
|             nfc_device_set_name(nfc->dev, ""); |  | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); |  | ||||||
|             consumed = true; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
| @ -44,8 +44,6 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     submenu_set_selected_item( |  | ||||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); |  | ||||||
|     if(nfc->dev->shadow_file_exist) { |     if(nfc->dev->shadow_file_exist) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
| @ -58,12 +56,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { | |||||||
|         submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); |         submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); | ||||||
|  |     submenu_set_selected_item( | ||||||
|  |         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); |     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|  |     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
| @ -87,7 +88,18 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | |||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexInfo) { |         } else if(event.event == SubmenuIndexInfo) { | ||||||
|  |             bool application_info_present = false; | ||||||
|  |             if(dev_data->protocol == NfcDeviceProtocolEMV) { | ||||||
|  |                 application_info_present = true; | ||||||
|  |             } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { | ||||||
|  |                 application_info_present = nfc_supported_card_verify_and_parse(dev_data); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(application_info_present) { | ||||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); | ||||||
|  |             } else { | ||||||
|  |                 scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||||
|  |             } | ||||||
|             consumed = true; |             consumed = true; | ||||||
|         } else if(event.event == SubmenuIndexRestoreOriginal) { |         } else if(event.event == SubmenuIndexRestoreOriginal) { | ||||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); |             scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); | ||||||
|  | |||||||
| @ -1,80 +0,0 @@ | |||||||
| #include "bank_card.h" |  | ||||||
| #include "../helpers/nfc_emv_parser.h" |  | ||||||
| #include <m-string.h> |  | ||||||
| 
 |  | ||||||
| struct BankCard { |  | ||||||
|     Widget* widget; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| BankCard* bank_card_alloc() { |  | ||||||
|     BankCard* bank_card = malloc(sizeof(BankCard)); |  | ||||||
|     bank_card->widget = widget_alloc(); |  | ||||||
|     return bank_card; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_free(BankCard* bank_card) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     widget_free(bank_card->widget); |  | ||||||
|     free(bank_card); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| View* bank_card_get_view(BankCard* bank_card) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     return widget_get_view(bank_card->widget); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_clear(BankCard* bank_card) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     widget_reset(bank_card->widget); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_name(BankCard* bank_card, char* name) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     furi_assert(name); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         bank_card->widget, 64, 6, AlignCenter, AlignTop, FontSecondary, name); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     furi_assert(number); |  | ||||||
|     string_t num_str; |  | ||||||
|     string_init(num_str); |  | ||||||
|     for(uint8_t i = 0; i < len; i += 2) { |  | ||||||
|         string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]); |  | ||||||
|     } |  | ||||||
|     // Add number
 |  | ||||||
|     widget_add_string_element( |  | ||||||
|         bank_card->widget, 64, 32, AlignCenter, AlignTop, FontSecondary, string_get_cstr(num_str)); |  | ||||||
|     string_clear(num_str); |  | ||||||
|     // Add icon
 |  | ||||||
|     widget_add_icon_element(bank_card->widget, 8, 15, &I_Detailed_chip_17x13); |  | ||||||
|     // Add frame
 |  | ||||||
|     widget_add_frame_element(bank_card->widget, 0, 0, 128, 64, 6); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     furi_assert(callback); |  | ||||||
|     widget_add_button_element(bank_card->widget, GuiButtonTypeLeft, "Back", callback, context); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     char exp_date_str[16]; |  | ||||||
|     snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02X/%02X", mon, year); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_country_name(BankCard* bank_card, const char* country_name) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) { |  | ||||||
|     furi_assert(bank_card); |  | ||||||
|     widget_add_string_element( |  | ||||||
|         bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name); |  | ||||||
| } |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <gui/view.h> |  | ||||||
| #include <gui/modules/widget.h> |  | ||||||
| 
 |  | ||||||
| typedef struct BankCard BankCard; |  | ||||||
| 
 |  | ||||||
| BankCard* bank_card_alloc(); |  | ||||||
| 
 |  | ||||||
| void bank_card_free(BankCard* bank_card); |  | ||||||
| 
 |  | ||||||
| void bank_card_clear(BankCard* bank_card); |  | ||||||
| 
 |  | ||||||
| View* bank_card_get_view(BankCard* bank_card); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_back_callback(BankCard* bank_card, ButtonCallback callback, void* context); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_name(BankCard* bank_card, char* name); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_country_name(BankCard* bank_card, const char* country_name); |  | ||||||
| 
 |  | ||||||
| void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name); |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/NFC/Keychain.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/NFC/Keychain.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.7 KiB | 
| @ -1217,6 +1217,7 @@ void nfc_device_data_clear(NfcDeviceData* dev_data) { | |||||||
| void nfc_device_clear(NfcDevice* dev) { | void nfc_device_clear(NfcDevice* dev) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
|  |     nfc_device_set_name(dev, ""); | ||||||
|     nfc_device_data_clear(&dev->dev_data); |     nfc_device_data_clear(&dev->dev_data); | ||||||
|     dev->format = NfcDeviceSaveFormatUid; |     dev->format = NfcDeviceSaveFormatUid; | ||||||
|     string_reset(dev->load_path); |     string_reset(dev->load_path); | ||||||
|  | |||||||
| @ -143,7 +143,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont | |||||||
|                 if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { |                 if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { | ||||||
|                     if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { |                     if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { | ||||||
|                         read_success = true; |                         read_success = true; | ||||||
|                         nfc_supported_card[i].parse(nfc_worker); |                         nfc_supported_card[i].parse(nfc_worker->dev_data); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -11,3 +11,17 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { | |||||||
|             .parse = troyka_parser_parse, |             .parse = troyka_parser_parse, | ||||||
|         }, |         }, | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { | ||||||
|  |     furi_assert(dev_data); | ||||||
|  | 
 | ||||||
|  |     bool card_parsed = false; | ||||||
|  |     for(size_t i = 0; i < COUNT_OF(nfc_supported_card); i++) { | ||||||
|  |         if(nfc_supported_card[i].parse(dev_data)) { | ||||||
|  |             card_parsed = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return card_parsed; | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <furi_hal_nfc.h> | #include <furi_hal_nfc.h> | ||||||
| #include "../nfc_worker.h" | #include "../nfc_worker.h" | ||||||
|  | #include "../nfc_device.h" | ||||||
| 
 | 
 | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| 
 | 
 | ||||||
| @ -15,7 +16,7 @@ typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxCont | |||||||
| 
 | 
 | ||||||
| typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); | typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); | ||||||
| 
 | 
 | ||||||
| typedef bool (*NfcSupportedCardParse)(NfcWorker* nfc_worker); | typedef bool (*NfcSupportedCardParse)(NfcDeviceData* dev_data); | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     NfcProtocol protocol; |     NfcProtocol protocol; | ||||||
| @ -25,3 +26,5 @@ typedef struct { | |||||||
| } NfcSupportedCard; | } NfcSupportedCard; | ||||||
| 
 | 
 | ||||||
| extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; | extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; | ||||||
|  | 
 | ||||||
|  | bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); | ||||||
|  | |||||||
| @ -49,8 +49,17 @@ bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { | |||||||
|     return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; |     return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool troyka_parser_parse(NfcWorker* nfc_worker) { | bool troyka_parser_parse(NfcDeviceData* dev_data) { | ||||||
|     MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; |     MfClassicData* data = &dev_data->mf_classic_data; | ||||||
|  |     bool troyka_parsed = false; | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         // Verify key
 | ||||||
|  |         MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); | ||||||
|  |         uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); | ||||||
|  |         if(key != troyka_keys[8].key_a) break; | ||||||
|  | 
 | ||||||
|  |         // Parse data
 | ||||||
|         uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; |         uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; | ||||||
|         uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; |         uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; | ||||||
|         temp_ptr = &data->block[8 * 4].value[3]; |         temp_ptr = &data->block[8 * 4].value[3]; | ||||||
| @ -62,10 +71,9 @@ bool troyka_parser_parse(NfcWorker* nfc_worker) { | |||||||
|         number >>= 4; |         number >>= 4; | ||||||
| 
 | 
 | ||||||
|         string_printf( |         string_printf( | ||||||
|         nfc_worker->dev_data->parsed_data, |             dev_data->parsed_data, "\e#Troyka\nNum: %ld\nBalance: %d rur.", number, balance); | ||||||
|         "Troyka Transport card\nNumber: %ld\nBalance: %d rub", |         troyka_parsed = true; | ||||||
|         number, |     } while(false); | ||||||
|         balance); |  | ||||||
| 
 | 
 | ||||||
|     return true; |     return troyka_parsed; | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,4 +6,4 @@ bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); | |||||||
| 
 | 
 | ||||||
| bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); | bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); | ||||||
| 
 | 
 | ||||||
| bool troyka_parser_parse(NfcWorker* nfc_worker); | bool troyka_parser_parse(NfcDeviceData* dev_data); | ||||||
|  | |||||||
| @ -191,7 +191,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if(pack != NULL) { |         if(pack != NULL) { | ||||||
|             *pack = (tx_rx->rx_data[0] << 8) | tx_rx->rx_data[1]; |             *pack = (tx_rx->rx_data[1] << 8) | tx_rx->rx_data[0]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack); |         FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack); | ||||||
| @ -697,48 +697,6 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* | |||||||
|     return counter_read == (is_single_counter ? 1 : 3); |     return counter_read == (is_single_counter ? 1 : 3); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int16_t mf_ultralight_get_authlim( |  | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |  | ||||||
|     MfUltralightReader* reader, |  | ||||||
|     MfUltralightData* data) { |  | ||||||
|     mf_ultralight_read_version(tx_rx, reader, data); |  | ||||||
|     if(!(reader->supported_features & MfUltralightSupportAuth)) { |  | ||||||
|         // No authentication
 |  | ||||||
|         return -2; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     uint8_t config_pages_index; |  | ||||||
|     if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) { |  | ||||||
|         config_pages_index = reader->pages_to_read - 4; |  | ||||||
|     } else if( |  | ||||||
|         data->type >= MfUltralightTypeNTAGI2CPlus1K && |  | ||||||
|         data->type <= MfUltralightTypeNTAGI2CPlus1K) { |  | ||||||
|         config_pages_index = 0xe3; |  | ||||||
|     } else { |  | ||||||
|         // No config pages
 |  | ||||||
|         return -2; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(!mf_ultralight_read_pages_direct(tx_rx, config_pages_index, data->data)) { |  | ||||||
|         // Config pages are not readable due to protection
 |  | ||||||
|         return -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     MfUltralightConfigPages* config_pages = (MfUltralightConfigPages*)&data->data; |  | ||||||
|     if(config_pages->auth0 >= reader->pages_to_read) { |  | ||||||
|         // Authentication is not configured
 |  | ||||||
|         return -2; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     int16_t authlim = config_pages->access.authlim; |  | ||||||
|     if(authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K && |  | ||||||
|        data->type <= MfUltralightTypeNTAGI2CPlus2K) { |  | ||||||
|         authlim = 1 << authlim; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return authlim; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { | bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { | ||||||
|     uint8_t flag_read = 0; |     uint8_t flag_read = 0; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -56,13 +56,6 @@ typedef enum { | |||||||
|     MfUltralightTypeNum, |     MfUltralightTypeNum, | ||||||
| } MfUltralightType; | } MfUltralightType; | ||||||
| 
 | 
 | ||||||
| typedef enum { |  | ||||||
|     MfUltralightAuthLimitUnknown, |  | ||||||
|     MfUltralightAuthLimitNotSupported, |  | ||||||
|     MfUltralightAuthLimitConfigured, |  | ||||||
|     MfUltralightAuthLimitNotConfigured, |  | ||||||
| } MfUltralightAuthLimit; |  | ||||||
| 
 |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     MfUltralightSupportNone = 0, |     MfUltralightSupportNone = 0, | ||||||
|     MfUltralightSupportFastRead = 1 << 0, |     MfUltralightSupportFastRead = 1 << 0, | ||||||
| @ -245,11 +238,6 @@ bool mf_ul_prepare_emulation_response( | |||||||
|     uint32_t* data_type, |     uint32_t* data_type, | ||||||
|     void* context); |     void* context); | ||||||
| 
 | 
 | ||||||
| int16_t mf_ultralight_get_authlim( |  | ||||||
|     FuriHalNfcTxRxContext* tx_rx, |  | ||||||
|     MfUltralightReader* reader, |  | ||||||
|     MfUltralightData* data); |  | ||||||
| 
 |  | ||||||
| uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data); | uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data); | ||||||
| 
 | 
 | ||||||
| uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data); | uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich