From 560ea5f995df0a179632bcdae9075599d97a214f Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 Aug 2022 18:08:13 +0300 Subject: [PATCH 01/11] [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 --- applications/gui/modules/widget.c | 13 + applications/gui/modules/widget.h | 21 ++ .../widget_elements/widget_element_i.h | 8 + .../widget_element_text_scroll.c | 245 ++++++++++++++++++ applications/nfc/nfc.c | 9 - applications/nfc/nfc_i.h | 4 +- applications/nfc/scenes/nfc_scene_config.h | 6 +- applications/nfc/scenes/nfc_scene_delete.c | 69 ++--- .../nfc/scenes/nfc_scene_delete_success.c | 2 +- .../nfc/scenes/nfc_scene_device_info.c | 217 +++------------- applications/nfc/scenes/nfc_scene_emv_menu.c | 54 ++++ .../nfc/scenes/nfc_scene_emv_read_success.c | 104 +++----- .../nfc/scenes/nfc_scene_file_select.c | 1 + .../nfc/scenes/nfc_scene_mf_classic_info.c | 72 ----- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 1 + .../nfc/scenes/nfc_scene_mf_classic_menu.c | 2 +- .../nfc_scene_mf_classic_read_success.c | 43 +-- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 17 ++ .../nfc_scene_mf_desfire_read_success.c | 101 ++++---- .../nfc/scenes/nfc_scene_mf_ultralight_data.c | 32 +++ .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 7 + .../nfc_scene_mf_ultralight_read_success.c | 74 +----- .../nfc/scenes/nfc_scene_nfc_data_info.c | 133 ++++++++++ applications/nfc/scenes/nfc_scene_nfca_menu.c | 62 +++++ .../nfc/scenes/nfc_scene_nfca_read_success.c | 72 +++++ applications/nfc/scenes/nfc_scene_read.c | 7 +- .../nfc/scenes/nfc_scene_read_card_success.c | 43 +-- .../nfc/scenes/nfc_scene_saved_menu.c | 18 +- applications/nfc/views/bank_card.c | 80 ------ applications/nfc/views/bank_card.h | 26 -- assets/icons/NFC/Keychain.png | Bin 0 -> 3750 bytes lib/nfc/nfc_device.c | 1 + lib/nfc/nfc_worker.c | 2 +- lib/nfc/parsers/nfc_supported_card.c | 14 + lib/nfc/parsers/nfc_supported_card.h | 5 +- lib/nfc/parsers/troyka_parser.c | 42 +-- lib/nfc/parsers/troyka_parser.h | 2 +- lib/nfc/protocols/mifare_ultralight.c | 44 +--- lib/nfc/protocols/mifare_ultralight.h | 12 - 39 files changed, 918 insertions(+), 747 deletions(-) create mode 100644 applications/gui/modules/widget_elements/widget_element_text_scroll.c create mode 100644 applications/nfc/scenes/nfc_scene_emv_menu.c delete mode 100644 applications/nfc/scenes/nfc_scene_mf_classic_info.c create mode 100644 applications/nfc/scenes/nfc_scene_mf_ultralight_data.c create mode 100644 applications/nfc/scenes/nfc_scene_nfc_data_info.c create mode 100644 applications/nfc/scenes/nfc_scene_nfca_menu.c create mode 100644 applications/nfc/scenes/nfc_scene_nfca_read_success.c delete mode 100755 applications/nfc/views/bank_card.c delete mode 100644 applications/nfc/views/bank_card.h create mode 100644 assets/icons/NFC/Keychain.png diff --git a/applications/gui/modules/widget.c b/applications/gui/modules/widget.c index 8d7acb013..b37a64701 100644 --- a/applications/gui/modules/widget.c +++ b/applications/gui/modules/widget.c @@ -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, diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h index 55af59d7c..587fa3c65 100755 --- a/applications/gui/modules/widget.h +++ b/applications/gui/modules/widget.h @@ -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 diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/gui/modules/widget_elements/widget_element_i.h index bcbd4afdb..316ed7400 100755 --- a/applications/gui/modules/widget_elements/widget_element_i.h +++ b/applications/gui/modules/widget_elements/widget_element_i.h @@ -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); diff --git a/applications/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/gui/modules/widget_elements/widget_element_text_scroll.c new file mode 100644 index 000000000..6682b106a --- /dev/null +++ b/applications/gui/modules/widget_elements/widget_element_text_scroll.c @@ -0,0 +1,245 @@ +#include "widget_element_i.h" +#include +#include +#include + +#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; +} diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index 6b8843db2..3422e91af 100644 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -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); diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 5a916e803..bcfe4a219 100644 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -25,8 +25,8 @@ #include #include #include +#include -#include "views/bank_card.h" #include "views/dict_attack.h" #include @@ -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; diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 2b5cb5cf1..ff34a11d8 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -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) diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c index 1946b9290..987927e19 100755 --- a/applications/nfc/scenes/nfc_scene_delete.c +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -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); diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/nfc/scenes/nfc_scene_delete_success.c index 547aeab7e..713b99ebf 100755 --- a/applications/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/nfc/scenes/nfc_scene_delete_success.c @@ -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; diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index b79c51046..8228c7ea3 100644 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -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); - } } diff --git a/applications/nfc/scenes/nfc_scene_emv_menu.c b/applications/nfc/scenes/nfc_scene_emv_menu.c new file mode 100644 index 000000000..1da630fcf --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_emv_menu.c @@ -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); +} diff --git a/applications/nfc/scenes/nfc_scene_emv_read_success.c b/applications/nfc/scenes/nfc_scene_emv_read_success.c index eefe560e3..9cf7ff9e9 100644 --- a/applications/nfc/scenes/nfc_scene_emv_read_success.c +++ b/applications/nfc/scenes/nfc_scene_emv_read_success.c @@ -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) { diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/nfc/scenes/nfc_scene_file_select.c index 0278c3b9c..693fdec20 100755 --- a/applications/nfc/scenes/nfc_scene_file_select.c +++ b/applications/nfc/scenes/nfc_scene_file_select.c @@ -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); diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_info.c b/applications/nfc/scenes/nfc_scene_mf_classic_info.c deleted file mode 100644 index b658dfa48..000000000 --- a/applications/nfc/scenes/nfc_scene_mf_classic_info.c +++ /dev/null @@ -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); -} diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c index 0faa73673..fcb8bc189 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -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); } diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c index 6ee0ad868..76d02e01e 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -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) { diff --git a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c index bd782305c..efe676706 100644 --- a/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -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); } diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c index f15251143..1e2f2d2f2 100644 --- a/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -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; } } diff --git a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c index a04f4e55c..4827c2851 100644 --- a/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -1,90 +1,85 @@ #include "../nfc_i.h" #include -#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); } diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c new file mode 100644 index 000000000..d4184a6b4 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_data.c @@ -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); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 9174a8b19..ba9f22338 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -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); diff --git a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 65750b963..d775bb71d 100644 --- a/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,11 +1,6 @@ #include "../nfc_i.h" #include -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); } diff --git a/applications/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/nfc/scenes/nfc_scene_nfc_data_info.c new file mode 100644 index 000000000..33f5e44af --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfc_data_info.c @@ -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); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_nfca_menu.c b/applications/nfc/scenes/nfc_scene_nfca_menu.c new file mode 100644 index 000000000..00d0d943d --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfca_menu.c @@ -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); +} diff --git a/applications/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/nfc/scenes/nfc_scene_nfca_read_success.c new file mode 100644 index 000000000..3467a03b6 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_nfca_read_success.c @@ -0,0 +1,72 @@ +#include "../nfc_i.h" +#include + +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); +} diff --git a/applications/nfc/scenes/nfc_scene_read.c b/applications/nfc/scenes/nfc_scene_read.c index 491b419ef..00b7c8fac 100644 --- a/applications/nfc/scenes/nfc_scene_read.c +++ b/applications/nfc/scenes/nfc_scene_read.c @@ -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); diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index b889ce08d..0cb38cbdf 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -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; diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index e6b08e71b..c7aec5d87 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -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); diff --git a/applications/nfc/views/bank_card.c b/applications/nfc/views/bank_card.c deleted file mode 100755 index 31cc56ee8..000000000 --- a/applications/nfc/views/bank_card.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "bank_card.h" -#include "../helpers/nfc_emv_parser.h" -#include - -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); -} diff --git a/applications/nfc/views/bank_card.h b/applications/nfc/views/bank_card.h deleted file mode 100644 index 628d9deb8..000000000 --- a/applications/nfc/views/bank_card.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -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); diff --git a/assets/icons/NFC/Keychain.png b/assets/icons/NFC/Keychain.png new file mode 100644 index 0000000000000000000000000000000000000000..7ba1b11da6fde4e2b4b148a35593937f2a2ac471 GIT binary patch literal 3750 zcmaJ@c{r5&+kYIguVo48j3ryln6WiupT!bG7#T?!j3JE~V`?lVlr0^Soruc5Bx-6b zWy_KfqU;Gt4o;RR;T`99I=}aixA(c8=lOoW_jP|h_vc=o>w4l&*jfnj%kTpLAY^5U zc3`h6>_>x_ll|_iwQmIgevB^)b;1gT0#RucZ{PDo00u!Mb+7zV>7+mRQ`nUD~EL&9D|@H+oHo*DVO30LpM zUVphY6?)HasD9&P_s-+D#&hMXIW@gJjl6?q}5i}sc3p8T08?_F_?23FwW}fBPdaAJ8!ir* zh9n>h0aJ61@SF@~M<9<2aPRW;m=6~H26zPlE&JFgHGnG=aPLr53<9oY z0^;T?&W2x(R*KH4vn!QZZOBrBVIbsHOlgMGx!S(SX#*gd1>& zlXvbOS>p0JBanAtBi_4O#Pl(cH$URMO5LjsCjTaDczAYZ=H2mDq$}a2^W_~<^Vvq{ z?epKl41a8_zkl{YDFWseVZpWezWLRfO~IkwTYT3%#y%!m{CFa;`$KL(q1DQRg;y7! zw%;F+fX=$H3M){EL*7z*aio9O>%*kR7N_x~E>LyOm?Jbvv)Ij(^Q*OrD4yQL^WbRCzhWeXdURGIp0uwk`6G0O8(Nw*mm*3|a|{ds$=B&Ih6#?rgA!s_CC?cRAF$l(^Fw1 zs>pW&Z*G%neFPtuSqJX{g8WD2WcTAi`lYOS}!<_MK%h=#Y|**a)9KALljuW)+3xV(UlBwPN2|4|>3$ zF?dT2#i9L)2Oy%Mv8YykrTuXzm)WD9&q?Wb0VUC?;U#t;;Wmbls;OH!52KFD*BB+WSZAj76mdLUl99jB!aUC5Zr6v?DG;nkVymn4#2 z@~0k8RZf*vhu}&|3ri6T5MYEQ1|Wg9-f`9ZvzQ5QJ$&h+dR@l0 zTwT0TX-PgDrF~r6xyE5N#oL5uIwN57HrtdQ|4BdSGLA}#x7+! zU|EG~g$6bTHtpT7y6<)mW$I=dLEpmWvgfkjW=}qGKNWOJgIUacO0=q;IaTPg#H{y^ zIt6zrz&o9Ct1++0sW>uJS5a3aR>ZPRwk^vYBDGX~VRkZ0o=8{CzT+OPWRjVe2_z3G z(vugJElbG_$(L&{|FLbvBNQ_%Tqbu)E-dg7O&oC&F_G1Cd&%VTi?y_Q2npXS+WSs> znt7m0t<^WjF?+y*Bt>EcUR{likF$>K0;d~;vt`@HI~rz=)7Jysrb7DHbFyo)n-_~m zA1vuD`7Xtb-Fc;RM=jSyJMeW&2kO23Y@dn1om4Hq$?`BelwAbr@th*W6O!ay@wVzo z0i$$-uqu+0|A(!NzCzv2ciC?RS7tL zBJ9)9YaYT!LVQb@ph{FslykI60yP#d(+5r0W%P}q0w>Ym(P`+3Y!cKC{y_7%uDWq4 z_?+R0eyvWeNgLSP<<%fQ2XA%W`VbtfUa9AQ{@LV@#nqS(IUfY3L!~kx9d6X%{GR5u zs3OS{@O}+MnyF2!?Xi@<%tY0TC2t&AIlwrQz#rT!*Gy7?^y&4*zC)c>KWw{Vsg4b~ z^=DGOZm`k|?E;Ni)-{!qoAowAHsjfdT*<79ATrDd(Ez=AE9qtcvQ!?M%p`p#ee}NA zRZfhm-g)64{{(V4m8a9M=4Sam7fpU9vhWk`l`S?@LLdY;-8JWyfF55(ajDIahZHf_#T}jYb+6Wy;6KsDqZ5r zJJqqES=kuM%jcP6DUV9ZT3KGb-u>S5A15?(U4_$1(?6yQ`wI<^JQA8b`Dk(dD`pgu z-mN-Xca@1^-Ft5Mw4PYh+0$)cg1e7f!+po;E%lE-CcNGB?^}`$t^ca?=isPo{l>O& z=d)2K4kzrO_aJf0YO7|$q%y8_elu;0>{ek*4p?mG?C0F(Q50srWxW}c>o>wVBn};2 zun=zl{n<{=GDA~HPsr(y+if2dsp#OD`3=6wjl)8Sk&8D%%cpn-e!nP3l7pN>X02qI zXFFzXxq7(P+PyOF8~QvE^21{EcahsVhAzR!S8<)bBlD31$)uIu8#$>tm&3r{#@t8m zGDGJ)dnV6`P?l>&=~Mlf-S|0!dV`+RD^KYw)uXcqoS!;pJwTi#f2Myn+({m=Yp=Uq zmsQC+?Z;XQX?Ps!y)iGFtKT!e))4$fa(8Gj7j87(uo^&0GRqQQh_V_HfK?pVhnMfyqg2?Cn0}(++3V-t=*!w**L;>`-3*FC1;Xk7A*b^WWg+>JF zgQ1$9T3T8leK?rtMSyu|dlNi0Krk&B6ar=6`kGLE1WX$Ng@gXN6xac2Ufu`?wD~{b z*e4?eA3B|ifIt`w2AH7@rqD#!lXu%*bm?qmpGceenP6*QU4^;fgfF=fd(tN3O zUy46ykCEU(xj;8kV2k}v7G&zbwEltrREk|QNDzSvfr7R6vij+W#s2@UWb(h>fpiDr zfA#*K#DTbADiPv945VD3d9r)wt+*G8ia^nb1UiL=qfpNOEaV9v3Y`+@L!p9T+F&S1 z6-)5+_209o{SCol5mx?zbb`Mp(F$#(z$O9v`g$Ss%rQ{yW6)z-x|m~7CjrXGG2U~bFwXi~nObWxEF+N1LG)vAL*y4V znZdc7@J&n`SL#XXY9}k7)0r8V0;wPHVQ>|=|K$#i_yQ>PR>QbidiqjLu%1ovk{e`n zvwDI75yjixLswvHKnnpN;w1fRT6NKTL0;1J>92DXdev_data); dev->format = NfcDeviceSaveFormatUid; string_reset(dev->load_path); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index a92f148a2..45bbc5f41 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -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); } } } diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/parsers/nfc_supported_card.c index 59482a123..480c970e7 100644 --- a/lib/nfc/parsers/nfc_supported_card.c +++ b/lib/nfc/parsers/nfc_supported_card.c @@ -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; +} diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/parsers/nfc_supported_card.h index 5c94c78cd..9b5d1c053 100644 --- a/lib/nfc/parsers/nfc_supported_card.h +++ b/lib/nfc/parsers/nfc_supported_card.h @@ -2,6 +2,7 @@ #include #include "../nfc_worker.h" +#include "../nfc_device.h" #include @@ -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); diff --git a/lib/nfc/parsers/troyka_parser.c b/lib/nfc/parsers/troyka_parser.c index 3167b5181..51ffa42e1 100644 --- a/lib/nfc/parsers/troyka_parser.c +++ b/lib/nfc/parsers/troyka_parser.c @@ -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; } diff --git a/lib/nfc/parsers/troyka_parser.h b/lib/nfc/parsers/troyka_parser.h index 0d5cee233..445fe40e5 100644 --- a/lib/nfc/parsers/troyka_parser.h +++ b/lib/nfc/parsers/troyka_parser.h @@ -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); diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/protocols/mifare_ultralight.c index c043f2069..f637d378a 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/protocols/mifare_ultralight.c @@ -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; diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/protocols/mifare_ultralight.h index 727bffab2..9642824f7 100644 --- a/lib/nfc/protocols/mifare_ultralight.h +++ b/lib/nfc/protocols/mifare_ultralight.h @@ -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); From 6c268ec58190d2296cb0101be9d063e70fc896ef Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 17 Aug 2022 18:40:06 +0300 Subject: [PATCH 02/11] U2F: counter file migration (#1604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/u2f/u2f_data.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/applications/u2f/u2f_data.c b/applications/u2f/u2f_data.c index 0419fc7e1..117fbdbe3 100644 --- a/applications/u2f/u2f_data.c +++ b/applications/u2f/u2f_data.c @@ -1,5 +1,5 @@ #include -#include "u2f_hid.h" +#include "u2f_data.h" #include #include #include @@ -28,7 +28,8 @@ #define U2F_DEVICE_KEY_VERSION 1 #define U2F_COUNTER_FILE_TYPE "Flipper U2F Counter File" -#define U2F_COUNTER_VERSION 1 +#define U2F_COUNTER_VERSION 2 +#define U2F_COUNTER_VERSION_OLD 1 #define U2F_COUNTER_CONTROL_VAL 0xAA5500FF @@ -359,6 +360,7 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) { furi_assert(cnt_val); bool state = false; + bool old_counter = false; uint8_t iv[16]; U2fCounterData cnt; uint8_t cnt_encr[48]; @@ -376,9 +378,16 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) { FURI_LOG_E(TAG, "Missing or incorrect header"); break; } - if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0 || - version != U2F_COUNTER_VERSION) { - FURI_LOG_E(TAG, "Type or version mismatch"); + if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0) { + FURI_LOG_E(TAG, "Type mismatch"); + break; + } + if(version == U2F_COUNTER_VERSION_OLD) { + // Counter is from previous U2F app version with endianness bug + FURI_LOG_W(TAG, "Counter from old version"); + old_counter = true; + } else if(version != U2F_COUNTER_VERSION) { + FURI_LOG_E(TAG, "Version mismatch"); break; } if(!flipper_format_read_hex(flipper_format, "IV", iv, 16)) { @@ -409,6 +418,13 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) { flipper_format_free(flipper_format); furi_record_close(RECORD_STORAGE); string_clear(filetype); + + if(old_counter && state) { + // Change counter endianness and rewrite counter file + *cnt_val = __REV(cnt.counter); + state = u2f_data_cnt_write(*cnt_val); + } + return state; } From 831da59ed012e56a5d629837e3fd33550b575e6f Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Wed, 17 Aug 2022 17:44:08 +0200 Subject: [PATCH 03/11] Fix U2F counter endianness (#1592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/u2f/u2f.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/applications/u2f/u2f.c b/applications/u2f/u2f.c index 051dca696..94fd9f2da 100644 --- a/applications/u2f/u2f.c +++ b/applications/u2f/u2f.c @@ -4,6 +4,7 @@ #include "u2f_data.h" #include #include +#include // for lfs_tobe32 #include "toolbox/sha256.h" #include "toolbox/hmac_sha256.h" @@ -256,6 +257,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { uint8_t flags = 0; uint8_t hash[32]; uint8_t signature[64]; + uint32_t be_u2f_counter; if(u2f_data_check(false) == false) { U2F->ready = false; @@ -275,11 +277,14 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { } U2F->user_present = false; + // The 4 byte counter is represented in big endian + be_u2f_counter = lfs_tobe32(U2F->counter); + // Generate hash sha256_start(&sha_ctx); sha256_update(&sha_ctx, req->app_id, 32); sha256_update(&sha_ctx, &flags, 1); - sha256_update(&sha_ctx, (uint8_t*)&(U2F->counter), 4); + sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4); sha256_update(&sha_ctx, req->challenge, 32); sha256_finish(&sha_ctx, hash); @@ -309,7 +314,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); resp->user_present = flags; - resp->counter = U2F->counter; + resp->counter = be_u2f_counter; uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature); memcpy(resp->signature + signature_len, state_no_error, 2); From c964099c8cbaff194e3f6db66be820771e7a2482 Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Wed, 17 Aug 2022 18:23:13 +0200 Subject: [PATCH 04/11] Increment U2F counter before authentication (#1595) * Fix U2F counter endianness * Increment U2F counter before using it * U2F: increment counter before use * U2F: don't increment on U2fCheckOnly Co-authored-by: Aleksandr Kutuzov --- applications/u2f/u2f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/u2f/u2f.c b/applications/u2f/u2f.c index 94fd9f2da..767733ce6 100644 --- a/applications/u2f/u2f.c +++ b/applications/u2f/u2f.c @@ -277,8 +277,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { } U2F->user_present = false; - // The 4 byte counter is represented in big endian - be_u2f_counter = lfs_tobe32(U2F->counter); + // The 4 byte counter is represented in big endian. Increment it before use + be_u2f_counter = lfs_tobe32(U2F->counter + 1); // Generate hash sha256_start(&sha_ctx); @@ -318,8 +318,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature); memcpy(resp->signature + signature_len, state_no_error, 2); - FURI_LOG_D(TAG, "Counter: %lu", U2F->counter); U2F->counter++; + FURI_LOG_D(TAG, "Counter: %lu", U2F->counter); u2f_data_cnt_write(U2F->counter); if(U2F->callback != NULL) U2F->callback(U2fNotifyAuthSuccess, U2F->context); From 9b138424671e0e1bdea7e93ca152703427af6bee Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 17 Aug 2022 19:40:09 +0300 Subject: [PATCH 05/11] Fix typos in subghz (#1588) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../subghz/scenes/subghz_scene_receiver_config.c | 4 ++-- applications/subghz/subghz_i.c | 2 +- lib/subghz/blocks/encoder.h | 2 +- lib/subghz/protocols/bett.c | 10 +++++----- lib/subghz/protocols/came.c | 10 +++++----- lib/subghz/protocols/came_twee.c | 10 +++++----- lib/subghz/protocols/chamberlain_code.c | 10 +++++----- lib/subghz/protocols/doitrand.c | 10 +++++----- lib/subghz/protocols/gate_tx.c | 10 +++++----- lib/subghz/protocols/holtek.c | 10 +++++----- lib/subghz/protocols/honeywell_wdb.c | 10 +++++----- lib/subghz/protocols/hormann.c | 10 +++++----- lib/subghz/protocols/keeloq.c | 10 +++++----- lib/subghz/protocols/linear.c | 10 +++++----- lib/subghz/protocols/marantec.c | 10 +++++----- lib/subghz/protocols/megacode.c | 10 +++++----- lib/subghz/protocols/nero_radio.c | 10 +++++----- lib/subghz/protocols/nero_sketch.c | 10 +++++----- lib/subghz/protocols/nice_flo.c | 10 +++++----- lib/subghz/protocols/phoenix_v2.c | 10 +++++----- lib/subghz/protocols/power_smart.c | 10 +++++----- lib/subghz/protocols/princeton.c | 10 +++++----- lib/subghz/protocols/raw.c | 12 ++++++------ lib/subghz/protocols/scher_khan.c | 6 +++--- lib/subghz/protocols/secplus_v1.c | 10 +++++----- lib/subghz/protocols/secplus_v2.c | 10 +++++----- 26 files changed, 118 insertions(+), 118 deletions(-) diff --git a/applications/subghz/scenes/subghz_scene_receiver_config.c b/applications/subghz/scenes/subghz_scene_receiver_config.c index bf2f0cdba..c59630f7e 100644 --- a/applications/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/subghz/scenes/subghz_scene_receiver_config.c @@ -100,7 +100,7 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) { subghz_setting_get_preset_data_size(subghz->setting, index)); } -static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) { +static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -176,7 +176,7 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz->variable_item_list, "Hopping:", HOPPING_COUNT, - subghz_scene_receiver_config_set_hopping_runing, + subghz_scene_receiver_config_set_hopping_running, subghz); value_index = subghz_scene_receiver_config_hopper_value_index( subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz); diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index de2df681c..dc0d71e56 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -296,7 +296,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) { //Todo add Custom_preset_module - //delete peset if it already exists + //delete preset if it already exists subghz_setting_delete_custom_preset( subghz->setting, string_get_cstr(subghz->txrx->preset->name)); //load custom preset from file diff --git a/lib/subghz/blocks/encoder.h b/lib/subghz/blocks/encoder.h index 80ffe4900..6ad734cbd 100644 --- a/lib/subghz/blocks/encoder.h +++ b/lib/subghz/blocks/encoder.h @@ -7,7 +7,7 @@ #include typedef struct { - bool is_runing; + bool is_running; size_t repeat; size_t front; size_t size_upload; diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c index bd3b45feb..aca8b8c4f 100644 --- a/lib/subghz/protocols/bett.c +++ b/lib/subghz/protocols/bett.c @@ -94,7 +94,7 @@ void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -174,7 +174,7 @@ bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flip flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_bett_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -184,14 +184,14 @@ bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flip void subghz_protocol_encoder_bett_stop(void* context) { SubGhzProtocolEncoderBETT* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_bett_yield(void* context) { SubGhzProtocolEncoderBETT* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/came.c b/lib/subghz/protocols/came.c index d28b735c5..37048017e 100644 --- a/lib/subghz/protocols/came.c +++ b/lib/subghz/protocols/came.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -157,7 +157,7 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_came_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -167,14 +167,14 @@ bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flip void subghz_protocol_encoder_came_stop(void* context) { SubGhzProtocolEncoderCame* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_came_yield(void* context) { SubGhzProtocolEncoderCame* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/came_twee.c b/lib/subghz/protocols/came_twee.c index 9bf87ea2b..b5b409c59 100644 --- a/lib/subghz/protocols/came_twee.c +++ b/lib/subghz/protocols/came_twee.c @@ -112,7 +112,7 @@ void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!! instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -261,7 +261,7 @@ bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* subghz_protocol_came_twee_remote_controller(&instance->generic); subghz_protocol_encoder_came_twee_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -271,14 +271,14 @@ bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_came_twee_stop(void* context) { SubGhzProtocolEncoderCameTwee* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_came_twee_yield(void* context) { SubGhzProtocolEncoderCameTwee* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/chamberlain_code.c b/lib/subghz/protocols/chamberlain_code.c index 3128b71ec..6c99d8451 100644 --- a/lib/subghz/protocols/chamberlain_code.c +++ b/lib/subghz/protocols/chamberlain_code.c @@ -108,7 +108,7 @@ void* subghz_protocol_encoder_chamb_code_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 24; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -225,7 +225,7 @@ bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_chamb_code_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -235,14 +235,14 @@ bool subghz_protocol_encoder_chamb_code_deserialize(void* context, FlipperFormat void subghz_protocol_encoder_chamb_code_stop(void* context) { SubGhzProtocolEncoderChamb_Code* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_chamb_code_yield(void* context) { SubGhzProtocolEncoderChamb_Code* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c index c26cbc5b6..9a0a58190 100644 --- a/lib/subghz/protocols/doitrand.c +++ b/lib/subghz/protocols/doitrand.c @@ -85,7 +85,7 @@ void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -155,7 +155,7 @@ bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_doitrand_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -165,14 +165,14 @@ bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_doitrand_stop(void* context) { SubGhzProtocolEncoderDoitrand* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_doitrand_yield(void* context) { SubGhzProtocolEncoderDoitrand* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 66174d011..d7efb3862 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -148,7 +148,7 @@ bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* f flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_gate_tx_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -158,14 +158,14 @@ bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* f void subghz_protocol_encoder_gate_tx_stop(void* context) { SubGhzProtocolEncoderGateTx* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context) { SubGhzProtocolEncoderGateTx* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c index ed5e4fb54..137ba85d3 100644 --- a/lib/subghz/protocols/holtek.c +++ b/lib/subghz/protocols/holtek.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_holtek_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -161,7 +161,7 @@ bool subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* fl flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_holtek_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -171,14 +171,14 @@ bool subghz_protocol_encoder_holtek_deserialize(void* context, FlipperFormat* fl void subghz_protocol_encoder_holtek_stop(void* context) { SubGhzProtocolEncoderHoltek* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_holtek_yield(void* context) { SubGhzProtocolEncoderHoltek* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/honeywell_wdb.c b/lib/subghz/protocols/honeywell_wdb.c index 292229130..e1e21426d 100644 --- a/lib/subghz/protocols/honeywell_wdb.c +++ b/lib/subghz/protocols/honeywell_wdb.c @@ -91,7 +91,7 @@ void* subghz_protocol_encoder_honeywell_wdb_alloc(SubGhzEnvironment* environment instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -163,7 +163,7 @@ bool subghz_protocol_encoder_honeywell_wdb_deserialize( flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_honeywell_wdb_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -173,14 +173,14 @@ bool subghz_protocol_encoder_honeywell_wdb_deserialize( void subghz_protocol_encoder_honeywell_wdb_stop(void* context) { SubGhzProtocolEncoderHoneywell_WDB* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_honeywell_wdb_yield(void* context) { SubGhzProtocolEncoderHoneywell_WDB* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/hormann.c b/lib/subghz/protocols/hormann.c index ac6312511..0197f59e6 100644 --- a/lib/subghz/protocols/hormann.c +++ b/lib/subghz/protocols/hormann.c @@ -81,7 +81,7 @@ void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 2048; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -164,7 +164,7 @@ bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* f flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_hormann_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -174,14 +174,14 @@ bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* f void subghz_protocol_encoder_hormann_stop(void* context) { SubGhzProtocolEncoderHormann* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_hormann_yield(void* context) { SubGhzProtocolEncoderHormann* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 526a6b34e..88738f3fb 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -102,7 +102,7 @@ void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -295,7 +295,7 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl break; } - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -305,14 +305,14 @@ bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* fl void subghz_protocol_encoder_keeloq_stop(void* context) { SubGhzProtocolEncoderKeeloq* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) { SubGhzProtocolEncoderKeeloq* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/linear.c b/lib/subghz/protocols/linear.c index c989a6183..92ba02a8f 100644 --- a/lib/subghz/protocols/linear.c +++ b/lib/subghz/protocols/linear.c @@ -84,7 +84,7 @@ void* subghz_protocol_encoder_linear_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 28; //max 10bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -166,7 +166,7 @@ bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* fl flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_linear_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -176,14 +176,14 @@ bool subghz_protocol_encoder_linear_deserialize(void* context, FlipperFormat* fl void subghz_protocol_encoder_linear_stop(void* context) { SubGhzProtocolEncoderLinear* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_linear_yield(void* context) { SubGhzProtocolEncoderLinear* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c index d46927246..bdce6593d 100644 --- a/lib/subghz/protocols/marantec.c +++ b/lib/subghz/protocols/marantec.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -208,7 +208,7 @@ bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* subghz_protocol_marantec_remote_controller(&instance->generic); subghz_protocol_encoder_marantec_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -218,14 +218,14 @@ bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_marantec_stop(void* context) { SubGhzProtocolEncoderMarantec* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_marantec_yield(void* context) { SubGhzProtocolEncoderMarantec* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/megacode.c b/lib/subghz/protocols/megacode.c index bfe1a76b9..909e72171 100644 --- a/lib/subghz/protocols/megacode.c +++ b/lib/subghz/protocols/megacode.c @@ -90,7 +90,7 @@ void* subghz_protocol_encoder_megacode_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -194,7 +194,7 @@ bool subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_megacode_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -204,14 +204,14 @@ bool subghz_protocol_encoder_megacode_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_megacode_stop(void* context) { SubGhzProtocolEncoderMegaCode* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_megacode_yield(void* context) { SubGhzProtocolEncoderMegaCode* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/nero_radio.c b/lib/subghz/protocols/nero_radio.c index b6b1587ff..69326f5a0 100644 --- a/lib/subghz/protocols/nero_radio.c +++ b/lib/subghz/protocols/nero_radio.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -173,7 +173,7 @@ bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_nero_radio_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -183,14 +183,14 @@ bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat void subghz_protocol_encoder_nero_radio_stop(void* context) { SubGhzProtocolEncoderNeroRadio* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context) { SubGhzProtocolEncoderNeroRadio* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/nero_sketch.c b/lib/subghz/protocols/nero_sketch.c index 0b87ec11b..c93b36a53 100644 --- a/lib/subghz/protocols/nero_sketch.c +++ b/lib/subghz/protocols/nero_sketch.c @@ -79,7 +79,7 @@ void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -167,7 +167,7 @@ bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperForma flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_nero_sketch_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -177,14 +177,14 @@ bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperForma void subghz_protocol_encoder_nero_sketch_stop(void* context) { SubGhzProtocolEncoderNeroSketch* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context) { SubGhzProtocolEncoderNeroSketch* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/nice_flo.c b/lib/subghz/protocols/nice_flo.c index 236b42223..07b18e3ea 100644 --- a/lib/subghz/protocols/nice_flo.c +++ b/lib/subghz/protocols/nice_flo.c @@ -78,7 +78,7 @@ void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -150,7 +150,7 @@ bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_nice_flo_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -160,14 +160,14 @@ bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_nice_flo_stop(void* context) { SubGhzProtocolEncoderNiceFlo* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context) { SubGhzProtocolEncoderNiceFlo* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c index e71e28349..3d2796e44 100644 --- a/lib/subghz/protocols/phoenix_v2.c +++ b/lib/subghz/protocols/phoenix_v2.c @@ -80,7 +80,7 @@ void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -151,7 +151,7 @@ bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_phoenix_v2_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -161,14 +161,14 @@ bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat void subghz_protocol_encoder_phoenix_v2_stop(void* context) { SubGhzProtocolEncoderPhoenix_V2* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context) { SubGhzProtocolEncoderPhoenix_V2* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/power_smart.c b/lib/subghz/protocols/power_smart.c index 53e9f3380..bd009d887 100644 --- a/lib/subghz/protocols/power_smart.c +++ b/lib/subghz/protocols/power_smart.c @@ -87,7 +87,7 @@ void* subghz_protocol_encoder_power_smart_alloc(SubGhzEnvironment* environment) instance->encoder.repeat = 10; instance->encoder.size_upload = 1024; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -212,7 +212,7 @@ bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperForma subghz_protocol_power_smart_remote_controller(&instance->generic); subghz_protocol_encoder_power_smart_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -222,14 +222,14 @@ bool subghz_protocol_encoder_power_smart_deserialize(void* context, FlipperForma void subghz_protocol_encoder_power_smart_stop(void* context) { SubGhzProtocolEncoderPowerSmart* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_power_smart_yield(void* context) { SubGhzProtocolEncoderPowerSmart* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c index 3fdeaae94..2ddfa2cb6 100644 --- a/lib/subghz/protocols/princeton.c +++ b/lib/subghz/protocols/princeton.c @@ -89,7 +89,7 @@ void* subghz_protocol_encoder_princeton_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop) instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -168,7 +168,7 @@ bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); subghz_protocol_encoder_princeton_get_upload(instance); - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -178,14 +178,14 @@ bool subghz_protocol_encoder_princeton_deserialize(void* context, FlipperFormat* void subghz_protocol_encoder_princeton_stop(void* context) { SubGhzProtocolEncoderPrinceton* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_princeton_yield(void* context) { SubGhzProtocolEncoderPrinceton* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index 9ab649a7b..0419a39a0 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -37,7 +37,7 @@ struct SubGhzProtocolDecoderRAW { struct SubGhzProtocolEncoderRAW { SubGhzProtocolEncoderBase base; - bool is_runing; + bool is_running; string_t file_name; SubGhzFileEncoderWorker* file_worker_encoder; }; @@ -269,13 +269,13 @@ void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_raw; string_init(instance->file_name); - instance->is_runing = false; + instance->is_running = false; return instance; } void subghz_protocol_encoder_raw_stop(void* context) { SubGhzProtocolEncoderRAW* instance = context; - instance->is_runing = false; + instance->is_running = false; if(subghz_file_encoder_worker_is_running(instance->file_worker_encoder)) { subghz_file_encoder_worker_stop(instance->file_worker_encoder); subghz_file_encoder_worker_free(instance->file_worker_encoder); @@ -308,11 +308,11 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in instance->file_worker_encoder, string_get_cstr(instance->file_name))) { //the worker needs a file in order to open and read part of the file furi_delay_ms(100); - instance->is_runing = true; + instance->is_running = true; } else { subghz_protocol_encoder_raw_stop(instance); } - return instance->is_runing; + return instance->is_running; } void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path) { @@ -357,6 +357,6 @@ bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipp LevelDuration subghz_protocol_encoder_raw_yield(void* context) { SubGhzProtocolEncoderRAW* instance = context; - if(!instance->is_runing) return level_duration_reset(); + if(!instance->is_running) return level_duration_reset(); return subghz_file_encoder_worker_get_level_duration(instance->file_worker_encoder); } diff --git a/lib/subghz/protocols/scher_khan.c b/lib/subghz/protocols/scher_khan.c index dd8d4c8fa..1c044e9db 100644 --- a/lib/subghz/protocols/scher_khan.c +++ b/lib/subghz/protocols/scher_khan.c @@ -210,7 +210,7 @@ static void subghz_protocol_scher_khan_check_remote_controller( SubGhzBlockGeneric* instance, const char** protocol_name) { /* - * MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dinamic + * MAGICAR 51 bit 00000001A99121DE83C3 MAGIC CODE, Dynamic * 0E8C1619E830C -> 000011101000110000010110 0001 1001 1110 1000001100001100 * 0E8C1629D830D -> 000011101000110000010110 0010 1001 1101 1000001100001101 * 0E8C1649B830E -> 000011101000110000010110 0100 1001 1011 1000001100001110 @@ -222,8 +222,8 @@ static void subghz_protocol_scher_khan_check_remote_controller( // case 35: //MAGIC CODE, Static // instance->protocol_name = "MAGIC CODE, Static"; // break; - case 51: //MAGIC CODE, Dinamic - *protocol_name = "MAGIC CODE, Dinamic"; + case 51: //MAGIC CODE, Dynamic + *protocol_name = "MAGIC CODE, Dynamic"; instance->serial = ((instance->data >> 24) & 0xFFFFFF0) | ((instance->data >> 20) & 0x0F); instance->btn = (instance->data >> 24) & 0x0F; instance->cnt = instance->data & 0xFFFF; diff --git a/lib/subghz/protocols/secplus_v1.c b/lib/subghz/protocols/secplus_v1.c index 25c35ce55..77a0c62a2 100644 --- a/lib/subghz/protocols/secplus_v1.c +++ b/lib/subghz/protocols/secplus_v1.c @@ -101,7 +101,7 @@ void* subghz_protocol_encoder_secplus_v1_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 128; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -298,7 +298,7 @@ bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat break; } - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -308,14 +308,14 @@ bool subghz_protocol_encoder_secplus_v1_deserialize(void* context, FlipperFormat void subghz_protocol_encoder_secplus_v1_stop(void* context) { SubGhzProtocolEncoderSecPlus_v1* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_secplus_v1_yield(void* context) { SubGhzProtocolEncoderSecPlus_v1* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 37dc1c823..c242d0b4d 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -93,7 +93,7 @@ void* subghz_protocol_encoder_secplus_v2_alloc(SubGhzEnvironment* environment) { instance->encoder.repeat = 10; instance->encoder.size_upload = 256; instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); - instance->encoder.is_runing = false; + instance->encoder.is_running = false; return instance; } @@ -555,7 +555,7 @@ bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat break; } - instance->encoder.is_runing = true; + instance->encoder.is_running = true; res = true; } while(false); @@ -565,14 +565,14 @@ bool subghz_protocol_encoder_secplus_v2_deserialize(void* context, FlipperFormat void subghz_protocol_encoder_secplus_v2_stop(void* context) { SubGhzProtocolEncoderSecPlus_v2* instance = context; - instance->encoder.is_runing = false; + instance->encoder.is_running = false; } LevelDuration subghz_protocol_encoder_secplus_v2_yield(void* context) { SubGhzProtocolEncoderSecPlus_v2* instance = context; - if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) { - instance->encoder.is_runing = false; + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; return level_duration_reset(); } From e243a0e0e4ee588a48c1be1b7ac3c26a1577a7c0 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:43:28 +0300 Subject: [PATCH 06/11] Add MFC 1/4K 4/7bUID to "Add Manually" (#1584) * Add MFC 1/4K 4/7bUID to the "Add Manually" section * Small cleanup * Improve readability * Fix comment on the text box element * Review fixes --- applications/gui/modules/widget.h | 4 +- applications/nfc/helpers/nfc_generators.c | 167 ++++++++++++++++++++-- 2 files changed, 156 insertions(+), 15 deletions(-) diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h index 587fa3c65..03586165c 100755 --- a/applications/gui/modules/widget.h +++ b/applications/gui/modules/widget.h @@ -115,8 +115,8 @@ void widget_add_text_box_element( * @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 + * "\ecCenter-aligned text" - sets center horizontal align until the next '\n' symbol + * "\erRight-aligned text" - sets right horizontal align until the next '\n' symbol */ void widget_add_text_scroll_element( Widget* widget, diff --git a/applications/nfc/helpers/nfc_generators.c b/applications/nfc/helpers/nfc_generators.c index 3ec78a127..b94adbd7b 100644 --- a/applications/nfc/helpers/nfc_generators.c +++ b/applications/nfc/helpers/nfc_generators.c @@ -25,6 +25,39 @@ static void nfc_generate_mf_ul_uid(uint8_t* uid) { uid[6] |= 0x80; } +static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { + uid[0] = NXP_MANUFACTURER_ID; + furi_hal_random_fill_buf(&uid[1], length - 1); +} + +static void nfc_generate_mf_classic_block_0(uint8_t* block, uint8_t uid_len) { + // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes + furi_assert(uid_len == 4 || uid_len == 7); + furi_assert(block); + nfc_generate_mf_classic_uid(block, uid_len); + for(int i = uid_len; i < 16; i++) { + block[i] = 0xFF; + } +} + +static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { + // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. + MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value; + sec_tr->access_bits[0] = 0xFF; + sec_tr->access_bits[1] = 0x07; + sec_tr->access_bits[2] = 0x80; + sec_tr->access_bits[3] = 0x69; // Nice + + memset(sec_tr->key_a, 0xff, sizeof(sec_tr->key_a)); + memset(sec_tr->key_b, 0xff, sizeof(sec_tr->key_b)); + + mf_classic_set_block_read(data, block, &data->block[block]); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); +} + static void nfc_generate_mf_ul_common(NfcDeviceData* data) { data->nfc_data.type = FuriHalNfcTypeA; data->nfc_data.interface = FuriHalNfcInterfaceRf; @@ -36,6 +69,19 @@ static void nfc_generate_mf_ul_common(NfcDeviceData* data) { data->protocol = NfcDeviceProtocolMifareUl; } +static void + nfc_generate_mf_classic_common(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { + data->nfc_data.type = FuriHalNfcTypeA; + data->nfc_data.interface = FuriHalNfcInterfaceRf; + data->nfc_data.uid_len = uid_len; + nfc_generate_mf_classic_block_0(data->mf_classic_data.block[0].value, uid_len); + data->nfc_data.atqa[0] = 0x44; + data->nfc_data.atqa[1] = 0x00; + data->nfc_data.sak = 0x08; + data->protocol = NfcDeviceProtocolMifareClassic; + data->mf_classic_data.type = type; +} + static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; @@ -268,70 +314,161 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { mful->version.storage_size = 0x15; } +static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { + nfc_generate_common_start(data); + nfc_generate_mf_classic_common(data, uid_len, type); + + // Set the UID + data->nfc_data.uid[0] = NXP_MANUFACTURER_ID; + for(int i = 1; i < uid_len; i++) { + data->nfc_data.uid[i] = data->mf_classic_data.block[0].value[i]; + } + + MfClassicData* mfc = &data->mf_classic_data; + mf_classic_set_block_read(mfc, 0, &mfc->block[0]); + + if(type == MfClassicType4k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < 256; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc, i); + } else { + memset(&mfc->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc, i, &mfc->block[i]); + } + } else if(type == MfClassicType1k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc, i); + } else { + memset(&mfc->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc, i, &mfc->block[i]); + } + } + + mfc->type = type; +} + +static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) { + nfc_generate_mf_classic(data, 4, MfClassicType1k); +} + +static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) { + nfc_generate_mf_classic(data, 7, MfClassicType1k); +} + +static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) { + nfc_generate_mf_classic(data, 4, MfClassicType4k); +} + +static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) { + nfc_generate_mf_classic(data, 7, MfClassicType4k); +} + static const NfcGenerator mf_ul_generator = { .name = "Mifare Ultralight", .generator_func = nfc_generate_mf_ul_orig, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator mf_ul_11_generator = { .name = "Mifare Ultralight EV1 11", .generator_func = nfc_generate_mf_ul_11, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator mf_ul_h11_generator = { .name = "Mifare Ultralight EV1 H11", .generator_func = nfc_generate_mf_ul_h11, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator mf_ul_21_generator = { .name = "Mifare Ultralight EV1 21", .generator_func = nfc_generate_mf_ul_21, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator mf_ul_h21_generator = { .name = "Mifare Ultralight EV1 H21", .generator_func = nfc_generate_mf_ul_h21, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag203_generator = { .name = "NTAG203", .generator_func = nfc_generate_mf_ul_ntag203, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag213_generator = { .name = "NTAG213", .generator_func = nfc_generate_ntag213, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag215_generator = { .name = "NTAG215", .generator_func = nfc_generate_ntag215, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag216_generator = { .name = "NTAG216", .generator_func = nfc_generate_ntag216, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag_i2c_1k_generator = { .name = "NTAG I2C 1k", .generator_func = nfc_generate_ntag_i2c_1k, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag_i2c_2k_generator = { .name = "NTAG I2C 2k", .generator_func = nfc_generate_ntag_i2c_2k, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag_i2c_plus_1k_generator = { .name = "NTAG I2C Plus 1k", .generator_func = nfc_generate_ntag_i2c_plus_1k, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; static const NfcGenerator ntag_i2c_plus_2k_generator = { .name = "NTAG I2C Plus 2k", .generator_func = nfc_generate_ntag_i2c_plus_2k, - .next_scene = NfcSceneMfUltralightMenu}; + .next_scene = NfcSceneMfUltralightMenu, +}; + +static const NfcGenerator mifare_classic_1k_4b_uid_generator = { + .name = "Mifare Classic 1k 4byte UID", + .generator_func = nfc_generate_mf_classic_1k_4b_uid, + .next_scene = NfcSceneMfClassicMenu, +}; + +static const NfcGenerator mifare_classic_1k_7b_uid_generator = { + .name = "Mifare Classic 1k 7byte UID", + .generator_func = nfc_generate_mf_classic_1k_7b_uid, + .next_scene = NfcSceneMfClassicMenu, +}; + +static const NfcGenerator mifare_classic_4k_4b_uid_generator = { + .name = "Mifare Classic 4k 4byte UID", + .generator_func = nfc_generate_mf_classic_4k_4b_uid, + .next_scene = NfcSceneMfClassicMenu, +}; + +static const NfcGenerator mifare_classic_4k_7b_uid_generator = { + .name = "Mifare Classic 4k 7byte UID", + .generator_func = nfc_generate_mf_classic_4k_7b_uid, + .next_scene = NfcSceneMfClassicMenu, +}; const NfcGenerator* const nfc_generators[] = { &mf_ul_generator, @@ -347,5 +484,9 @@ const NfcGenerator* const nfc_generators[] = { &ntag_i2c_2k_generator, &ntag_i2c_plus_1k_generator, &ntag_i2c_plus_2k_generator, + &mifare_classic_1k_4b_uid_generator, + &mifare_classic_1k_7b_uid_generator, + &mifare_classic_4k_4b_uid_generator, + &mifare_classic_4k_7b_uid_generator, NULL, }; From 2e993b0a58153b0848387783761d1e3be0116eef Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 18 Aug 2022 19:46:43 +0300 Subject: [PATCH 07/11] [FL-2748] disabled automatic poweroff for single-frame slideshows #1621 --- applications/desktop/helpers/slideshow.c | 4 ++++ applications/desktop/helpers/slideshow.h | 1 + .../desktop/views/desktop_view_slideshow.c | 14 +++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/applications/desktop/helpers/slideshow.c b/applications/desktop/helpers/slideshow.c index 63bd42b55..b4d85cb90 100644 --- a/applications/desktop/helpers/slideshow.c +++ b/applications/desktop/helpers/slideshow.c @@ -94,6 +94,10 @@ bool slideshow_is_loaded(Slideshow* slideshow) { return slideshow->loaded; } +bool slideshow_is_one_page(Slideshow* slideshow) { + return slideshow->loaded && (slideshow->icon.frame_count == 1); +} + bool slideshow_advance(Slideshow* slideshow) { uint8_t next_frame = slideshow->current_frame + 1; if(next_frame < slideshow->icon.frame_count) { diff --git a/applications/desktop/helpers/slideshow.h b/applications/desktop/helpers/slideshow.h index eeaac0e8b..9083e0dcf 100644 --- a/applications/desktop/helpers/slideshow.h +++ b/applications/desktop/helpers/slideshow.h @@ -9,6 +9,7 @@ Slideshow* slideshow_alloc(); void slideshow_free(Slideshow* slideshow); bool slideshow_load(Slideshow* slideshow, const char* fspath); bool slideshow_is_loaded(Slideshow* slideshow); +bool slideshow_is_one_page(Slideshow* slideshow); void slideshow_goback(Slideshow* slideshow); bool slideshow_advance(Slideshow* slideshow); void slideshow_draw(Slideshow* slideshow, Canvas* canvas, uint8_t x, uint8_t y); diff --git a/applications/desktop/views/desktop_view_slideshow.c b/applications/desktop/views/desktop_view_slideshow.c index 26ae95eae..58a8f6d0c 100644 --- a/applications/desktop/views/desktop_view_slideshow.c +++ b/applications/desktop/views/desktop_view_slideshow.c @@ -35,8 +35,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) { furi_assert(event); DesktopSlideshowView* instance = context; + DesktopSlideshowViewModel* model = view_get_model(instance->view); + bool update_view = false; if(event->type == InputTypeShort) { - DesktopSlideshowViewModel* model = view_get_model(instance->view); bool end_slideshow = false; switch(event->key) { case InputKeyLeft: @@ -54,15 +55,18 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) { if(end_slideshow) { instance->callback(DesktopSlideshowCompleted, instance->context); } - view_commit_model(instance->view, true); + update_view = true; } else if(event->key == InputKeyOk) { if(event->type == InputTypePress) { furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT); } else if(event->type == InputTypeRelease) { furi_timer_stop(instance->timer); - furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); + if(!slideshow_is_one_page(model->slideshow)) { + furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); + } } } + view_commit_model(instance->view, update_view); return true; } @@ -79,12 +83,12 @@ static void desktop_view_slideshow_enter(void* context) { instance->timer = furi_timer_alloc(desktop_first_start_timer_callback, FuriTimerTypeOnce, instance); - furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); - DesktopSlideshowViewModel* model = view_get_model(instance->view); model->slideshow = slideshow_alloc(); if(!slideshow_load(model->slideshow, SLIDESHOW_FS_PATH)) { instance->callback(DesktopSlideshowCompleted, instance->context); + } else if(!slideshow_is_one_page(model->slideshow)) { + furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); } view_commit_model(instance->view, false); } From 2a452063c62e35111073cf68623322d7388dc1e5 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Thu, 18 Aug 2022 19:54:17 +0300 Subject: [PATCH 08/11] [FL-2747, FL-2745] Browser worker fix, Device Info screen update #1620 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/desktop/views/desktop_view_debug.c | 15 ++++++++------- applications/gui/modules/file_browser_worker.c | 5 +++++ firmware/targets/f7/ble_glue/ble_glue.c | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/applications/desktop/views/desktop_view_debug.c b/applications/desktop/views/desktop_view_debug.c index 69c82bdbe..c965432f1 100644 --- a/applications/desktop/views/desktop_view_debug.c +++ b/applications/desktop/views/desktop_view_debug.c @@ -23,11 +23,12 @@ void desktop_debug_render(Canvas* canvas, void* model) { const Version* ver; char buffer[64]; - static const char* headers[] = {"FW Version Info:", "Dolphin Info:"}; + static const char* headers[] = {"Device Info:", "Dolphin Info:"}; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 9 + STATUS_BAR_Y_SHIFT, headers[m->screen]); + canvas_draw_str_aligned( + canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, headers[m->screen]); canvas_set_font(canvas, FontSecondary); if(m->screen != DesktopViewStatsMeta) { @@ -44,7 +45,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { furi_hal_version_get_hw_region_name(), furi_hal_region_get_name(), my_name ? my_name : "Unknown"); - canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); + canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); ver = furi_hal_version_get_firmware_version(); const BleGlueC2Info* c2_ver = NULL; @@ -52,7 +53,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { c2_ver = ble_glue_get_c2_info(); #endif if(!ver) { - canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, "No info"); + canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info"); return; } @@ -62,7 +63,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { "%s [%s]", version_get_version(ver), version_get_builddate(ver)); - canvas_draw_str(canvas, 5, 28 + STATUS_BAR_Y_SHIFT, buffer); + canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer); snprintf( buffer, @@ -72,11 +73,11 @@ void desktop_debug_render(Canvas* canvas, void* model) { version_get_githash(ver), version_get_gitbranchnum(ver), c2_ver ? c2_ver->StackTypeString : ""); - canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); + canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer); snprintf( buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver)); - canvas_draw_str(canvas, 5, 50 + STATUS_BAR_Y_SHIFT, buffer); + canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer); } else { Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); diff --git a/applications/gui/modules/file_browser_worker.c b/applications/gui/modules/file_browser_worker.c index d705e5c3a..36df6cc83 100644 --- a/applications/gui/modules/file_browser_worker.c +++ b/applications/gui/modules/file_browser_worker.c @@ -99,6 +99,11 @@ static bool browser_folder_check_and_switch(string_t path) { FileInfo file_info; Storage* storage = furi_record_open(RECORD_STORAGE); bool is_root = false; + + if(string_search_rchar(path, '/') == 0) { + is_root = true; + } + while(1) { // Check if folder is existing and navigate back if not if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) { diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index be2ae0ee5..585a89820 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -156,7 +156,7 @@ static void ble_glue_update_c2_fw_info() { snprintf( local_info->StackTypeString, BLE_GLUE_MAX_VERSION_STRING_LEN, - "%d.%d.%d.%s", + "%d.%d.%d:%s", local_info->VersionMajor, local_info->VersionMinor, local_info->VersionSub, From fdb181b1586f69af7a39c5a99ba5cad255127d0b Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 19 Aug 2022 14:31:45 +0300 Subject: [PATCH 09/11] Fix BT Remote 'stay' button on first launch bug (#1626) --- applications/bt/bt_hid_app/bt_hid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/bt/bt_hid_app/bt_hid.c b/applications/bt/bt_hid_app/bt_hid.c index b6f00e939..3189042c0 100755 --- a/applications/bt/bt_hid_app/bt_hid.c +++ b/applications/bt/bt_hid_app/bt_hid.c @@ -134,7 +134,8 @@ BtHid* bt_hid_app_alloc() { app->view_dispatcher, BtHidViewMouse, bt_hid_mouse_get_view(app->bt_hid_mouse)); // TODO switch to menu after Media is done - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewKeynote); + app->view_id = BtHidViewKeynote; + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); return app; } From 0a6d775fa7935039de8c81ce669f084c003996d0 Mon Sep 17 00:00:00 2001 From: Anna Prosvetova Date: Sun, 21 Aug 2022 14:51:04 +0200 Subject: [PATCH 10/11] Github: Update CODEOWNERS (#1631) --- .github/CODEOWNERS | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 71acb5f14..ea165de2f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,7 +17,6 @@ /applications/gui/ @skotopes @DrZlo13 @hedger /applications/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov /applications/infrared/ @skotopes @DrZlo13 @hedger @gsurkov -/applications/infrared_monitor/ @skotopes @DrZlo13 @hedger @gsurkov /applications/input/ @skotopes @DrZlo13 @hedger /applications/lfrfid/ @skotopes @DrZlo13 @hedger /applications/lfrfid_debug/ @skotopes @DrZlo13 @hedger @@ -46,11 +45,11 @@ /debug/ @skotopes @DrZlo13 @hedger # Docker -/docker/ @skotopes @DrZlo13 @hedger @aprosvetova -/docker-compose.yml @skotopes @DrZlo13 @hedger @aprosvetova +/docker/ @skotopes @DrZlo13 @hedger @drunkbatya +/docker-compose.yml @skotopes @DrZlo13 @hedger @drunkbatya # Documentation -/documentation/ @skotopes @DrZlo13 @hedger @aprosvetova +/documentation/ @skotopes @DrZlo13 @hedger @drunkbatya # Firmware targets /firmware/ @skotopes @DrZlo13 @hedger @@ -84,8 +83,5 @@ /lib/u8g2/ @skotopes @DrZlo13 @hedger /lib/update_util/ @skotopes @DrZlo13 @hedger -# Make tools -/make/ @skotopes @DrZlo13 @hedger @aprosvetova - # Helper scripts /scripts/ @skotopes @DrZlo13 @hedger From cfc0383b96c0f386a20bd142fb72b650b36e9fea Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Mon, 22 Aug 2022 19:19:03 +0300 Subject: [PATCH 11/11] Archive: dont start browser worker on favourites tab (#1628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../archive/helpers/archive_browser.c | 28 +++++++++++++------ .../archive/helpers/archive_browser.h | 1 - .../archive/views/archive_browser_view.c | 9 ++---- .../archive/views/archive_browser_view.h | 1 + 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index 54759dadc..2dfb9484b 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -77,14 +77,24 @@ static void archive_long_load_cb(void* context) { }); } -void archive_file_browser_set_callbacks(ArchiveBrowserView* browser) { +static void archive_file_browser_set_path( + ArchiveBrowserView* browser, + string_t path, + const char* filter_ext, + bool skip_assets) { furi_assert(browser); - - file_browser_worker_set_callback_context(browser->worker, browser); - file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb); - file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb); - file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb); - file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb); + if(!browser->worker_running) { + browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets); + file_browser_worker_set_callback_context(browser->worker, browser); + file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb); + file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb); + file_browser_worker_set_item_callback(browser->worker, archive_list_item_cb); + file_browser_worker_set_long_load_callback(browser->worker, archive_long_load_cb); + browser->worker_running = true; + } else { + furi_assert(browser->worker); + file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets); + } } bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) { @@ -438,8 +448,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { tab = archive_get_tab(browser); if(archive_is_dir_exists(browser->path)) { bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true; - file_browser_worker_set_config( - browser->worker, browser->path, archive_get_tab_ext(tab), skip_assets); + archive_file_browser_set_path( + browser, browser->path, archive_get_tab_ext(tab), skip_assets); tab_empty = false; // Empty check will be performed later } else { tab_empty = true; diff --git a/applications/archive/helpers/archive_browser.h b/applications/archive/helpers/archive_browser.h index d6c79817a..ad64a9845 100644 --- a/applications/archive/helpers/archive_browser.h +++ b/applications/archive/helpers/archive_browser.h @@ -87,4 +87,3 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key); void archive_enter_dir(ArchiveBrowserView* browser, string_t name); void archive_leave_dir(ArchiveBrowserView* browser); void archive_refresh_dir(ArchiveBrowserView* browser); -void archive_file_browser_set_callbacks(ArchiveBrowserView* browser); diff --git a/applications/archive/views/archive_browser_view.c b/applications/archive/views/archive_browser_view.c index 810d5c8f7..174071ad4 100644 --- a/applications/archive/views/archive_browser_view.c +++ b/applications/archive/views/archive_browser_view.c @@ -370,18 +370,15 @@ ArchiveBrowserView* browser_alloc() { return true; }); - browser->worker = file_browser_worker_alloc(browser->path, "*", false); - archive_file_browser_set_callbacks(browser); - - file_browser_worker_set_callback_context(browser->worker, browser); - return browser; } void browser_free(ArchiveBrowserView* browser) { furi_assert(browser); - file_browser_worker_free(browser->worker); + if(browser->worker_running) { + file_browser_worker_free(browser->worker); + } with_view_model( browser->view, (ArchiveBrowserViewModel * model) { diff --git a/applications/archive/views/archive_browser_view.h b/applications/archive/views/archive_browser_view.h index 2de04a166..5c649c389 100644 --- a/applications/archive/views/archive_browser_view.h +++ b/applications/archive/views/archive_browser_view.h @@ -74,6 +74,7 @@ typedef enum { struct ArchiveBrowserView { View* view; BrowserWorker* worker; + bool worker_running; ArchiveBrowserViewCallback callback; void* context; string_t path;