[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); | ||||
| } | ||||
| 
 | ||||
| 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( | ||||
|     Widget* widget, | ||||
|     GuiButtonType button_type, | ||||
|  | ||||
| @ -105,6 +105,27 @@ void widget_add_text_box_element( | ||||
|     const char* text, | ||||
|     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
 | ||||
|  * | ||||
|  * @param      widget       Widget instance | ||||
|  | ||||
| @ -29,6 +29,7 @@ struct WidgetElement { | ||||
| 
 | ||||
|     // generic model holder
 | ||||
|     void* model; | ||||
|     FuriMutex* model_mutex; | ||||
| 
 | ||||
|     // pointer to widget that hold our element
 | ||||
|     Widget* parent; | ||||
| @ -80,3 +81,10 @@ WidgetElement* widget_element_frame_create( | ||||
|     uint8_t width, | ||||
|     uint8_t height, | ||||
|     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(); | ||||
|     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
 | ||||
|     nfc->dict_attack = dict_attack_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -159,10 +154,6 @@ void nfc_free(Nfc* nfc) { | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); | ||||
|     widget_free(nfc->widget); | ||||
| 
 | ||||
|     // Bank Card
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); | ||||
|     bank_card_free(nfc->bank_card); | ||||
| 
 | ||||
|     // Mifare Classic Dict Attack
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); | ||||
|     dict_attack_free(nfc->dict_attack); | ||||
|  | ||||
| @ -25,8 +25,8 @@ | ||||
| #include <lib/nfc/nfc_worker.h> | ||||
| #include <lib/nfc/nfc_device.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 <nfc/scenes/nfc_scene.h> | ||||
| @ -70,7 +70,6 @@ struct Nfc { | ||||
|     ByteInput* byte_input; | ||||
|     TextBox* text_box; | ||||
|     Widget* widget; | ||||
|     BankCard* bank_card; | ||||
|     DictAttack* dict_attack; | ||||
| 
 | ||||
|     const NfcGenerator* generator; | ||||
| @ -85,7 +84,6 @@ typedef enum { | ||||
|     NfcViewByteInput, | ||||
|     NfcViewTextBox, | ||||
|     NfcViewWidget, | ||||
|     NfcViewBankCard, | ||||
|     NfcViewDictAttack, | ||||
| } NfcView; | ||||
| 
 | ||||
|  | ||||
| @ -12,7 +12,10 @@ ADD_SCENE(nfc, save_name, SaveName) | ||||
| ADD_SCENE(nfc, save_success, SaveSuccess) | ||||
| ADD_SCENE(nfc, file_select, FileSelect) | ||||
| 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_data, MfUltralightData) | ||||
| ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) | ||||
| ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) | ||||
| 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_app, MfDesfireApp) | ||||
| 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_emulate, MfClassicEmulate) | ||||
| ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) | ||||
| ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) | ||||
| ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) | ||||
| ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) | ||||
| ADD_SCENE(nfc, emv_menu, EmvMenu) | ||||
| ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ||||
| ADD_SCENE(nfc, device_info, DeviceInfo) | ||||
| ADD_SCENE(nfc, delete, Delete) | ||||
| @ -45,3 +48,4 @@ ADD_SCENE(nfc, rpc, Rpc) | ||||
| ADD_SCENE(nfc, exit_confirm, ExitConfirm) | ||||
| ADD_SCENE(nfc, retry_confirm, RetryConfirm) | ||||
| 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) { | ||||
|     Nfc* nfc = context; | ||||
|     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||
| 
 | ||||
|     // Setup Custom Widget view
 | ||||
|     char temp_str[64]; | ||||
|     snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
| 
 | ||||
|     string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name); | ||||
|     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( | ||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); | ||||
|         nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); | ||||
|     widget_add_button_element( | ||||
|         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; | ||||
|     if(protocol == NfcDeviceProtocolEMV) { | ||||
|         protocol_name = nfc_guess_protocol(protocol); | ||||
|         string_set_str(temp_str, "EMV bank card"); | ||||
|     } 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( | ||||
|             nfc->widget, 10, 33, AlignLeft, AlignTop, FontSecondary, protocol_name); | ||||
|     } | ||||
|     // TODO change dinamically
 | ||||
|     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); | ||||
|     widget_add_string_element( | ||||
|         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"); | ||||
|     string_clear(temp_str); | ||||
| 
 | ||||
|     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.event == GuiButtonTypeLeft) { | ||||
|             return scene_manager_previous_scene(nfc->scene_manager); | ||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             if(nfc_device_delete(nfc->dev, true)) { | ||||
|                 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.event == NfcCustomEventViewExit) { | ||||
|             consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                 nfc->scene_manager, NfcSceneStart); | ||||
|                 nfc->scene_manager, NfcSceneFileSelect); | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
|  | ||||
| @ -1,11 +1,6 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include "../helpers/nfc_emv_parser.h" | ||||
| 
 | ||||
| enum { | ||||
|     NfcSceneDeviceInfoUid, | ||||
|     NfcSceneDeviceInfoData, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     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) { | ||||
|     Nfc* nfc = context; | ||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||
| 
 | ||||
|     bool data_display_supported = (nfc->dev->format == NfcDeviceSaveFormatUid) || | ||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatMifareUl) || | ||||
|                                   (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); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
| 
 | ||||
|     const char* protocol_name = NULL; | ||||
|     NfcProtocol protocol = nfc->dev->dev_data.protocol; | ||||
|     if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|         protocol_name = nfc_guess_protocol(protocol); | ||||
|     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||
|         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) { | ||||
|         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
 | ||||
|     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]); | ||||
|     if(dev_data->protocol == NfcDeviceProtocolEMV) { | ||||
|         EmvData* emv_data = &dev_data->emv_data; | ||||
|         string_printf(temp_str, "\e#%s\n", emv_data->name); | ||||
|         for(uint8_t i = 0; i < emv_data->number_len; i += 2) { | ||||
|             string_cat_printf(temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[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); | ||||
|         string_strim(temp_str); | ||||
| 
 | ||||
|         // Add expiration date
 | ||||
|         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; | ||||
|         string_init(display_str); | ||||
|         if(emv_data->country_code) { | ||||
|         // 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_printf(display_str, "Reg:%s", string_get_cstr(country_name)); | ||||
|                 bank_card_set_country_name(bank_card, string_get_cstr(display_str)); | ||||
|                 string_cat_printf(temp_str, "Reg: %s", string_get_cstr(country_name)); | ||||
|             } | ||||
|             string_clear(country_name); | ||||
|         } | ||||
|         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->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); | ||||
|         } | ||||
|         string_clear(display_str); | ||||
|     } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { | ||||
|         string_set(temp_str, nfc->dev->dev_data.parsed_data); | ||||
|     } | ||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid); | ||||
| 
 | ||||
|     widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||
|     string_clear(temp_str); | ||||
| 
 | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo); | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) { | ||||
|             consumed = scene_manager_previous_scene(nfc->scene_manager); | ||||
|         } 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); | ||||
|         if(event.event == GuiButtonTypeRight) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
| @ -215,12 +78,4 @@ void nfc_scene_device_info_on_exit(void* context) { | ||||
| 
 | ||||
|     // Clear views
 | ||||
|     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) { | ||||
|     Nfc* nfc = context; | ||||
|     EmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup Custom Widget view
 | ||||
|     // Add frame
 | ||||
|     widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6); | ||||
|     // Add buttons
 | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc); | ||||
|     // Add card name
 | ||||
|     widget_add_string_element( | ||||
|         nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name); | ||||
|     // Add card number
 | ||||
|     string_t pan_str; | ||||
|     string_init(pan_str); | ||||
|         nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc); | ||||
| 
 | ||||
|     string_t temp_str; | ||||
|     string_init_printf(temp_str, "\e#%s\n", emv_data->name); | ||||
|     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); | ||||
|     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); | ||||
|     string_strim(temp_str); | ||||
| 
 | ||||
|     // Add expiration date
 | ||||
|     if(emv_data->exp_mon) { | ||||
|         char exp_str[16]; | ||||
|         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); | ||||
|         string_cat_printf(temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); | ||||
|     } | ||||
|     // 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); | ||||
| } | ||||
| @ -107,10 +70,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||
|             consumed = true; | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             // Clear device name
 | ||||
|             nfc_device_set_name(nfc->dev, ""); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatBankCard; | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvMenu); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|  | ||||
| @ -6,6 +6,7 @@ void nfc_scene_file_select_on_enter(void* context) { | ||||
|     // Process file_select return
 | ||||
|     nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); | ||||
|     if(nfc_file_select(nfc->dev)) { | ||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); | ||||
|     } else { | ||||
|         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_button_element( | ||||
|         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); | ||||
| } | ||||
|  | ||||
| @ -50,7 +50,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) | ||||
|         } else if(event.event == SubmenuIndexInfo) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicInfo); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|  | ||||
| @ -17,8 +17,6 @@ void nfc_scene_mf_classic_read_success_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); | ||||
| 
 | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
| @ -29,48 +27,27 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { | ||||
|     widget_add_button_element( | ||||
|         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)) { | ||||
|         widget_add_text_box_element( | ||||
|             nfc->widget, | ||||
|             0, | ||||
|             0, | ||||
|             128, | ||||
|             32, | ||||
|             AlignLeft, | ||||
|             AlignTop, | ||||
|             string_get_cstr(nfc->dev->dev_data.parsed_data), | ||||
|             true); | ||||
|         string_init_set(temp_str, nfc->dev->dev_data.parsed_data); | ||||
|     } else { | ||||
|         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:"); | ||||
|         string_init_printf(temp_str, "\e#%s\n", nfc_mf_classic_type(mf_data->type)); | ||||
|         string_cat_printf(temp_str, "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]); | ||||
|             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 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, 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_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); | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,8 @@ | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexSave, | ||||
|     SubmenuIndexEmulateUid, | ||||
|     SubmenuIndexInfo, | ||||
| }; | ||||
| 
 | ||||
| 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, "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( | ||||
|         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, ""); | ||||
|             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; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,90 +1,85 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | ||||
| 
 | ||||
| enum { | ||||
|     MfDesfireReadSuccessStateShowUID, | ||||
|     MfDesfireReadSuccessStateShowData, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) { | ||||
| void nfc_scene_mf_desfire_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
|     InputType type, | ||||
|     void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||
|     if(type == InputTypeShort) { | ||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mf_desfire_read_success_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; | ||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||
|     DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||
|     dialog_ex_set_center_button_text(dialog_ex, "Data"); | ||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||
|     dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); | ||||
|     Widget* widget = nfc->widget; | ||||
| 
 | ||||
|     // Prepare string for data display
 | ||||
|     string_t temp_str; | ||||
|     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_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'); | ||||
|     } | ||||
| 
 | ||||
|     // TODO rework info view
 | ||||
|     nfc_text_store_set( | ||||
|         nfc, | ||||
|         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); | ||||
|     // Add text scroll element
 | ||||
|     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, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||
|     // Add button elements
 | ||||
|     widget_add_button_element( | ||||
|         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) { | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) { | ||||
|         if(event.event == GuiButtonTypeLeft) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||
|             consumed = true; | ||||
|         } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); | ||||
|             consumed = true; | ||||
|         } else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) { | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } 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); | ||||
|             consumed = true; | ||||
|         } | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||
|         consumed = true; | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| @ -94,5 +89,5 @@ void nfc_scene_mf_desfire_read_success_on_exit(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     // 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, | ||||
|     SubmenuIndexSave, | ||||
|     SubmenuIndexEmulate, | ||||
|     SubmenuIndexInfo, | ||||
| }; | ||||
| 
 | ||||
| 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, | ||||
|         nfc_scene_mf_ultralight_menu_submenu_callback, | ||||
|         nfc); | ||||
|     submenu_add_item( | ||||
|         submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); | ||||
| 
 | ||||
|     submenu_set_selected_item( | ||||
|         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) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); | ||||
|             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); | ||||
| 
 | ||||
|  | ||||
| @ -1,11 +1,6 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| enum { | ||||
|     ReadMifareUlStateShowInfo, | ||||
|     ReadMifareUlStateShowData, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_mf_ultralight_read_success_widget_callback( | ||||
|     GuiButtonType result, | ||||
|     InputType type, | ||||
| @ -31,12 +26,6 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | ||||
|         "Retry", | ||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||
|         nfc); | ||||
|     widget_add_button_element( | ||||
|         widget, | ||||
|         GuiButtonTypeCenter, | ||||
|         "Data", | ||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||
|         nfc); | ||||
|     widget_add_button_element( | ||||
|         widget, | ||||
|         GuiButtonTypeRight, | ||||
| @ -44,71 +33,38 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { | ||||
|         nfc_scene_mf_ultralight_read_success_widget_callback, | ||||
|         nfc); | ||||
| 
 | ||||
|     widget_add_string_element( | ||||
|         widget, 0, 0, AlignLeft, AlignTop, FontSecondary, nfc_mf_ul_type(mf_ul_data->type, true)); | ||||
|     string_t data_str; | ||||
|     string_init_printf(data_str, "UID:"); | ||||
|     string_t temp_str; | ||||
|     string_init_printf(temp_str, "\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); | ||||
|     string_cat_printf(temp_str, "UID:"); | ||||
|     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)); | ||||
|     string_cat_printf( | ||||
|         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) { | ||||
|         widget_add_string_element( | ||||
|             widget, 0, 35, AlignLeft, AlignTop, FontSecondary, "Password-protected pages!"); | ||||
|         string_cat_printf(temp_str, "\nPassword-protected pages!"); | ||||
|     } | ||||
|     string_clear(data_str); | ||||
|     widget_add_text_scroll_element(widget, 0, 0, 128, 52, string_get_cstr(temp_str)); | ||||
|     string_clear(temp_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( | ||||
|             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)); | ||||
| 
 | ||||
|     scene_manager_set_scene_state( | ||||
|         nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowInfo); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeLeft) { | ||||
|         if(event.event == GuiButtonTypeLeft) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); | ||||
|             consumed = true; | ||||
|         } else if(state == ReadMifareUlStateShowInfo && event.event == GuiButtonTypeRight) { | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); | ||||
|             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) { | ||||
|         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); | ||||
|             consumed = true; | ||||
|         } | ||||
|         scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); | ||||
|         consumed = true; | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     // Clean views
 | ||||
|     // Clean view
 | ||||
|     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.event == NfcWorkerEventReadUidNfcB) || | ||||
|            (event.event == NfcWorkerEventReadUidNfcF) || | ||||
|            (event.event == NfcWorkerEventReadUidNfcV) || | ||||
|            (event.event == NfcWorkerEventReadUidNfcA)) { | ||||
|            (event.event == NfcWorkerEventReadUidNfcV)) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); | ||||
|             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) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             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) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     string_t data_str; | ||||
|     string_t uid_str; | ||||
|     string_init(data_str); | ||||
|     string_init(uid_str); | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; | ||||
|     Widget* widget = nfc->widget; | ||||
|     string_set_str(data_str, nfc_get_dev_type(data->type)); | ||||
|     string_set_str(uid_str, "UID:"); | ||||
|     string_set_str(temp_str, nfc_get_dev_type(data->type)); | ||||
|     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++) { | ||||
|         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, 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(uid_str); | ||||
|     string_clear(temp_str); | ||||
| 
 | ||||
|     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.event == GuiButtonTypeLeft) { | ||||
|             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; | ||||
|  | ||||
| @ -44,8 +44,6 @@ void nfc_scene_saved_menu_on_enter(void* context) { | ||||
|     } | ||||
|     submenu_add_item( | ||||
|         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) { | ||||
|         submenu_add_item( | ||||
|             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_add_item( | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     NfcDeviceData* dev_data = &nfc->dev->dev_data; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     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); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexInfo) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); | ||||
|             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); | ||||
|             } else { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); | ||||
|             } | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexRestoreOriginal) { | ||||
|             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) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     nfc_device_set_name(dev, ""); | ||||
|     nfc_device_data_clear(&dev->dev_data); | ||||
|     dev->format = NfcDeviceSaveFormatUid; | ||||
|     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].read(nfc_worker, tx_rx)) { | ||||
|                         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, | ||||
|         }, | ||||
| }; | ||||
| 
 | ||||
| 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 "../nfc_worker.h" | ||||
| #include "../nfc_device.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 (*NfcSupportedCardParse)(NfcWorker* nfc_worker); | ||||
| typedef bool (*NfcSupportedCardParse)(NfcDeviceData* dev_data); | ||||
| 
 | ||||
| typedef struct { | ||||
|     NfcProtocol protocol; | ||||
| @ -25,3 +26,5 @@ typedef struct { | ||||
| } NfcSupportedCard; | ||||
| 
 | ||||
| extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; | ||||
| 
 | ||||
| bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); | ||||
|  | ||||
| @ -49,23 +49,31 @@ 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; | ||||
| } | ||||
| 
 | ||||
| bool troyka_parser_parse(NfcWorker* nfc_worker) { | ||||
|     MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; | ||||
|     uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; | ||||
|     uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; | ||||
|     temp_ptr = &data->block[8 * 4].value[3]; | ||||
|     uint32_t number = 0; | ||||
|     for(size_t i = 0; i < 4; i++) { | ||||
|         number <<= 8; | ||||
|         number |= temp_ptr[i]; | ||||
|     } | ||||
|     number >>= 4; | ||||
| bool troyka_parser_parse(NfcDeviceData* dev_data) { | ||||
|     MfClassicData* data = &dev_data->mf_classic_data; | ||||
|     bool troyka_parsed = false; | ||||
| 
 | ||||
|     string_printf( | ||||
|         nfc_worker->dev_data->parsed_data, | ||||
|         "Troyka Transport card\nNumber: %ld\nBalance: %d rub", | ||||
|         number, | ||||
|         balance); | ||||
|     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; | ||||
| 
 | ||||
|     return true; | ||||
|         // Parse data
 | ||||
|         uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5]; | ||||
|         uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; | ||||
|         temp_ptr = &data->block[8 * 4].value[3]; | ||||
|         uint32_t number = 0; | ||||
|         for(size_t i = 0; i < 4; i++) { | ||||
|             number <<= 8; | ||||
|             number |= temp_ptr[i]; | ||||
|         } | ||||
|         number >>= 4; | ||||
| 
 | ||||
|         string_printf( | ||||
|             dev_data->parsed_data, "\e#Troyka\nNum: %ld\nBalance: %d rur.", number, balance); | ||||
|         troyka_parsed = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     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_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) { | ||||
|             *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); | ||||
| @ -697,48 +697,6 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* | ||||
|     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) { | ||||
|     uint8_t flag_read = 0; | ||||
| 
 | ||||
|  | ||||
| @ -56,13 +56,6 @@ typedef enum { | ||||
|     MfUltralightTypeNum, | ||||
| } MfUltralightType; | ||||
| 
 | ||||
| typedef enum { | ||||
|     MfUltralightAuthLimitUnknown, | ||||
|     MfUltralightAuthLimitNotSupported, | ||||
|     MfUltralightAuthLimitConfigured, | ||||
|     MfUltralightAuthLimitNotConfigured, | ||||
| } MfUltralightAuthLimit; | ||||
| 
 | ||||
| typedef enum { | ||||
|     MfUltralightSupportNone = 0, | ||||
|     MfUltralightSupportFastRead = 1 << 0, | ||||
| @ -245,11 +238,6 @@ bool mf_ul_prepare_emulation_response( | ||||
|     uint32_t* data_type, | ||||
|     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_xiaomi(FuriHalNfcDevData* data); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich