Просмотр исходного кода

[FL-1643] NFC emv assets (#661)

* assets: add EMV AID table for NFC app
* file-worker: add searching for value by the key
* nfc: add emv parser helpers
* assets: add country and currency codes
* nfc: add country and currency code parsing
* emv_decoder: add country and currency code support
* nfc: add AID. currency and country display
* nfc: rework bank_card view
* nfc: add currency and country save
* assets: change emv chip asset
* nfc: change asset in bank card
* gui: add frame element to widget
* nfc: add bank card frame, add documentation
* rfal: fix long APDU command emulation
* nfc: fix typos
* Scripts ReadMe: assets delivery command

Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
gornekich 4 лет назад
Родитель
Сommit
ecff31d228
31 измененных файлов с 1031 добавлено и 99 удалено
  1. 12 0
      applications/gui/modules/widget.c
  2. 18 2
      applications/gui/modules/widget.h
  3. 48 0
      applications/gui/modules/widget_elements/widget_element_frame.c
  4. 9 1
      applications/gui/modules/widget_elements/widget_element_i.h
  5. 0 1
      applications/gui/modules/widget_elements/widget_element_icon.c
  6. 49 0
      applications/nfc/helpers/nfc_emv_parser.c
  7. 27 0
      applications/nfc/helpers/nfc_emv_parser.h
  8. 36 13
      applications/nfc/nfc_device.c
  9. 2 1
      applications/nfc/nfc_device.h
  10. 6 0
      applications/nfc/nfc_worker.c
  11. 18 13
      applications/nfc/scenes/nfc_scene_device_info.c
  12. 7 3
      applications/nfc/scenes/nfc_scene_read_emv_app_success.c
  13. 2 0
      applications/nfc/scenes/nfc_scene_read_emv_data.c
  14. 40 0
      applications/nfc/scenes/nfc_scene_read_emv_data_success.c
  15. 50 6
      applications/nfc/views/bank_card.c
  16. 6 3
      applications/nfc/views/bank_card.h
  17. 0 0
      assets/compiled/assets_icons.c
  18. 52 52
      assets/compiled/assets_icons.h
  19. BIN
      assets/icons/NFC/Detailed_chip_17x13.png
  20. BIN
      assets/icons/NFC/EMV_Chip_14x11.png
  21. 148 0
      assets/resources/nfc/emv/aid.nfc
  22. 249 0
      assets/resources/nfc/emv/country_code.nfc
  23. 168 0
      assets/resources/nfc/emv/currency_code.nfc
  24. 3 1
      lib/ST25RFAL002/source/rfal_nfc.c
  25. 4 0
      lib/app-scened-template/file-worker-cpp.cpp
  26. 11 0
      lib/app-scened-template/file-worker-cpp.h
  27. 28 0
      lib/app-scened-template/file-worker.c
  28. 11 0
      lib/app-scened-template/file-worker.h
  29. 15 2
      lib/nfc_protocols/emv_decoder.c
  30. 4 1
      lib/nfc_protocols/emv_decoder.h
  31. 8 0
      scripts/ReadMe.md

+ 12 - 0
applications/gui/modules/widget.c

@@ -150,3 +150,15 @@ void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* i
     WidgetElement* icon_element = widget_element_icon_create(x, y, icon);
     widget_add_element(widget, icon_element);
 }
+
+void widget_add_frame_element(
+    Widget* widget,
+    uint8_t x,
+    uint8_t y,
+    uint8_t width,
+    uint8_t height,
+    uint8_t radius) {
+    furi_assert(widget);
+    WidgetElement* frame_element = widget_element_frame_create(x, y, width, height, radius);
+    widget_add_element(widget, frame_element);
+}

+ 18 - 2
applications/gui/modules/widget.h

@@ -59,8 +59,24 @@ void widget_add_button_element(
 
 /** Add Icon Element
  * @param widget Widget instance
- * @param x - x coordinate
- * @param y - y coordinate
+ * @param x top left x coordinate
+ * @param y top left y coordinate
  * @param icon Icon instance
  */
 void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon);
+
+/** Add Frame Element
+ * @param widget Widget instance
+ * @param x top left x coordinate
+ * @param y top left y coordinate
+ * @param width frame width
+ * @param height frame height
+ * @param radius frame radius
+ */
+void widget_add_frame_element(
+    Widget* widget,
+    uint8_t x,
+    uint8_t y,
+    uint8_t width,
+    uint8_t height,
+    uint8_t radius);

+ 48 - 0
applications/gui/modules/widget_elements/widget_element_frame.c

@@ -0,0 +1,48 @@
+#include "widget_element_i.h"
+
+typedef struct {
+    uint8_t x;
+    uint8_t y;
+    uint8_t width;
+    uint8_t height;
+    uint8_t radius;
+} GuiFrameModel;
+
+static void gui_frame_draw(Canvas* canvas, WidgetElement* element) {
+    furi_assert(canvas);
+    furi_assert(element);
+    GuiFrameModel* model = element->model;
+    canvas_draw_rframe(canvas, model->x, model->y, model->width, model->height, model->radius);
+}
+
+static void gui_frame_free(WidgetElement* gui_frame) {
+    furi_assert(gui_frame);
+
+    free(gui_frame->model);
+    free(gui_frame);
+}
+
+WidgetElement* widget_element_frame_create(
+    uint8_t x,
+    uint8_t y,
+    uint8_t width,
+    uint8_t height,
+    uint8_t radius) {
+    // Allocate and init model
+    GuiFrameModel* model = furi_alloc(sizeof(GuiFrameModel));
+    model->x = x;
+    model->y = y;
+    model->width = width;
+    model->height = height;
+    model->radius = radius;
+
+    // Allocate and init Element
+    WidgetElement* gui_frame = furi_alloc(sizeof(WidgetElement));
+    gui_frame->parent = NULL;
+    gui_frame->input = NULL;
+    gui_frame->draw = gui_frame_draw;
+    gui_frame->free = gui_frame_free;
+    gui_frame->model = model;
+
+    return gui_frame;
+}

+ 9 - 1
applications/gui/modules/widget_elements/widget_element_i.h

@@ -44,5 +44,13 @@ WidgetElement* widget_element_button_create(
     ButtonCallback callback,
     void* context);
 
-/* Create icon element element */
+/* Create icon element */
 WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon);
+
+/* Create frame element */
+WidgetElement* widget_element_frame_create(
+    uint8_t x,
+    uint8_t y,
+    uint8_t width,
+    uint8_t height,
+    uint8_t radius);

+ 0 - 1
applications/gui/modules/widget_elements/widget_element_icon.c

@@ -1,5 +1,4 @@
 #include "widget_element_i.h"
-#include <m-string.h>
 
 typedef struct {
     uint8_t x;

+ 49 - 0
applications/nfc/helpers/nfc_emv_parser.c

@@ -0,0 +1,49 @@
+#include "nfc_emv_parser.h"
+
+#include <file-worker.h>
+
+static bool
+    nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) {
+    bool found = false;
+    FileWorker* file_worker = file_worker_alloc(true);
+
+    if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
+        if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) {
+            found = true;
+        }
+    }
+
+    file_worker_close(file_worker);
+    file_worker_free(file_worker);
+    return found;
+}
+
+bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) {
+    bool result = false;
+    string_t key;
+    string_init(key);
+    for(uint8_t i = 0; i < aid_len; i++) {
+        string_cat_printf(key, "%02X", aid[i]);
+    }
+    result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name);
+    string_clear(key);
+    return result;
+}
+
+bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) {
+    bool result = false;
+    string_t key;
+    string_init_printf(key, "%04X", country_code);
+    result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name);
+    string_clear(key);
+    return result;
+}
+
+bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) {
+    bool result = false;
+    string_t key;
+    string_init_printf(key, "%04X", currency_code);
+    result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name);
+    string_clear(key);
+    return result;
+}

+ 27 - 0
applications/nfc/helpers/nfc_emv_parser.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <m-string.h>
+
+/** Get EMV application name by number
+ * @param aid - AID number array
+ * @param aid_len - AID length
+ * @param aid_name - string to keep AID name
+ * @return - true if AID found, false otherwies
+ */
+bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name);
+
+/** Get country name by country code
+ * @param country_code - ISO 3166 country code
+ * @param country_name - string to keep country name
+ * @return - true if country found, false otherwies
+ */
+bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name);
+
+/** Get currency name by currency code
+ * @param currency_code - ISO 3166 currency code
+ * @param currency_name - string to keep currency name
+ * @return - true if currency found, false otherwies
+ */
+bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name);

+ 36 - 13
applications/nfc/nfc_device.c

@@ -10,7 +10,7 @@ static const char* nfc_app_folder = "/any/nfc";
 static const char* nfc_app_extension = ".nfc";
 static const char* nfc_app_shadow_extension = ".shd";
 
-static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) {
+static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len, uint8_t delim_len) {
     string_strim(str);
     uint8_t nibble_high = 0;
     uint8_t nibble_low = 0;
@@ -20,7 +20,7 @@ static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len) {
         if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) &&
            hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) {
             buff[i] = (nibble_high << 4) | nibble_low;
-            string_right(str, 3);
+            string_right(str, delim_len + 2);
         } else {
             parsed = false;
             break;
@@ -81,22 +81,22 @@ bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) {
     do {
         // strlen("UID len: ") = 9
         string_right(uid_string, 9);
-        if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1)) {
+        if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1, 1)) {
             break;
         }
         // strlen("UID: ") = 5
         string_right(uid_string, 5);
-        if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len)) {
+        if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len, 1)) {
             break;
         }
         // strlen("ATQA: ") = 6
         string_right(uid_string, 6);
-        if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2)) {
+        if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2, 1)) {
             break;
         }
         // strlen("SAK: ") = 5
         string_right(uid_string, 5);
-        if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1)) {
+        if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1, 1)) {
             break;
         }
         parsed = true;
@@ -149,13 +149,13 @@ bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string
     do {
         // strlen("Signature: ") = 11
         string_right(mifare_ul_string, 11);
-        if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature))) {
+        if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) {
             break;
         }
         // strlen("Version: ") = 9
         string_right(mifare_ul_string, 9);
         if(!nfc_device_read_hex(
-               mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version))) {
+               mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) {
             break;
         }
         string_strim(mifare_ul_string);
@@ -184,7 +184,7 @@ bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string
         string_right(mifare_ul_string, ws + 1);
         // Read data
         for(uint16_t i = 0; i < data->data_size; i += 4) {
-            if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4)) {
+            if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4, 1)) {
                 break;
             }
         }
@@ -208,6 +208,12 @@ uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_
         string_cat_printf(
             bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year);
     }
+    if(data->country_code) {
+        string_cat_printf(bank_card_string, "\nCountry code: %04X", data->country_code);
+    }
+    if(data->currency_code) {
+        string_cat_printf(bank_card_string, "\nCurrency code: %04X", data->currency_code);
+    }
     return string_size(bank_card_string);
 }
 
@@ -215,6 +221,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
     NfcEmvData* data = &dev->dev_data.emv_data;
     bool parsed = false;
     int res = 0;
+    uint8_t code[2] = {};
     memset(data, 0, sizeof(NfcEmvData));
 
     do {
@@ -226,7 +233,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
         string_right(bank_card_string, 9);
         size_t ws = string_search_char(bank_card_string, ':');
         string_right(bank_card_string, ws + 1);
-        if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len)) {
+        if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) {
             break;
         }
         res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name);
@@ -237,7 +244,7 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
         string_right(bank_card_string, ws + 1);
         // strlen("Number: ") = 8
         string_right(bank_card_string, 8);
-        if(!nfc_device_read_hex(bank_card_string, data->number, sizeof(data->number))) {
+        if(!nfc_device_read_hex(bank_card_string, data->number, sizeof(data->number), 1)) {
             break;
         }
         parsed = true;
@@ -246,8 +253,24 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
         if(ws != STRING_FAILURE) {
             // strlen("Exp date: ") = 10
             string_right(bank_card_string, 10);
-            nfc_device_read_hex(bank_card_string, &data->exp_mon, 1);
-            nfc_device_read_hex(bank_card_string, &data->exp_year, 1);
+            nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 1);
+            nfc_device_read_hex(bank_card_string, &data->exp_year, 1, 1);
+        }
+        // Check country code presence
+        ws = string_search_str(bank_card_string, "Country code: ");
+        if(ws != STRING_FAILURE) {
+            // strlen("Country code: ") = 14
+            string_right(bank_card_string, 14);
+            nfc_device_read_hex(bank_card_string, code, 2, 0);
+            data->country_code = code[0] << 8 | code[1];
+        }
+        // Check currency code presence
+        ws = string_search_str(bank_card_string, "Currency code: ");
+        if(ws != STRING_FAILURE) {
+            // strlen("Currency code: ") = 15
+            string_right(bank_card_string, 15);
+            nfc_device_read_hex(bank_card_string, code, 2, 0);
+            data->currency_code = code[0] << 8 | code[1];
         }
     } while(0);
 

+ 2 - 1
applications/nfc/nfc_device.h

@@ -43,7 +43,8 @@ typedef struct {
     uint8_t number[8];
     uint8_t exp_mon;
     uint8_t exp_year;
-    char cardholder[32];
+    uint16_t country_code;
+    uint16_t currency_code;
 } NfcEmvData;
 
 typedef struct {

+ 6 - 0
applications/nfc/nfc_worker.c

@@ -328,6 +328,12 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                             result->emv_data.exp_mon = emv_app.exp_month;
                             result->emv_data.exp_year = emv_app.exp_year;
                         }
+                        if(emv_app.country_code) {
+                            result->emv_data.country_code = emv_app.country_code;
+                        }
+                        if(emv_app.currency_code) {
+                            result->emv_data.currency_code = emv_app.currency_code;
+                        }
                         // Notify caller and exit
                         if(nfc_worker->callback) {
                             nfc_worker->callback(nfc_worker->context);

+ 18 - 13
applications/nfc/scenes/nfc_scene_device_info.c

@@ -1,6 +1,6 @@
 #include "../nfc_i.h"
 
-#define NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT (0UL)
+#define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL)
 
 enum {
     NfcSceneDeviceInfoUid,
@@ -8,26 +8,27 @@ enum {
 };
 
 void nfc_scene_device_info_widget_callback(GuiButtonType result, void* context) {
-    Nfc* nfc = (Nfc*)context;
-
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 }
 
 void nfc_scene_device_info_dialog_callback(DialogExResult result, void* context) {
-    Nfc* nfc = (Nfc*)context;
-
+    Nfc* nfc = context;
     view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
 }
 
 void nfc_scene_device_info_text_box_callback(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
+    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
+}
 
-    view_dispatcher_send_custom_event(
-        nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_TEXTBOX_CUSTOM_EVENT);
+void nfc_scene_device_info_bank_card_callback(GuiButtonType result, void* context) {
+    Nfc* nfc = context;
+    view_dispatcher_send_custom_event(nfc->view_dispatcher, NFC_SCENE_DEVICE_INFO_BACK_EVENT);
 }
 
 void nfc_scene_device_info_on_enter(void* context) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
 
     // Setup Custom Widget view
     widget_add_string_element(
@@ -107,19 +108,23 @@ void nfc_scene_device_info_on_enter(void* context) {
         BankCard* bank_card = nfc->bank_card;
         bank_card_set_name(bank_card, emv_data->name);
         bank_card_set_number(bank_card, emv_data->number);
-        if(!strcmp(emv_data->name, "")) {
-            bank_card_set_cardholder_name(bank_card, emv_data->cardholder);
-        }
+        bank_card_set_back_callback(bank_card, nfc_scene_device_info_bank_card_callback, nfc);
         if(emv_data->exp_mon) {
             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year);
         }
+        if(emv_data->country_code) {
+            bank_card_set_country_name(bank_card, emv_data->country_code);
+        }
+        if(emv_data->currency_code) {
+            bank_card_set_currency_name(bank_card, emv_data->currency_code);
+        }
     }
     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
 }
 
 const bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
-    Nfc* nfc = (Nfc*)context;
+    Nfc* nfc = context;
     bool consumed = false;
     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDeviceInfo);
 

+ 7 - 3
applications/nfc/scenes/nfc_scene_read_emv_app_success.c

@@ -1,4 +1,5 @@
 #include "../nfc_i.h"
+#include "../helpers/nfc_emv_parser.h"
 
 #define NFC_SCENE_READ_SUCCESS_SHIFT "              "
 
@@ -21,9 +22,12 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21);
     // Display UID and AID
     string_t aid;
-    string_init_printf(aid, "AID:");
-    for(uint8_t i = 0; i < emv_data->aid_len; i++) {
-        string_cat_printf(aid, " %02X", emv_data->aid[i]);
+    string_init(aid);
+    bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, aid);
+    if(!aid_found) {
+        for(uint8_t i = 0; i < emv_data->aid_len; i++) {
+            string_cat_printf(aid, " %02X", emv_data->aid[i]);
+        }
     }
     nfc_text_store_set(
         nfc,

+ 2 - 0
applications/nfc/scenes/nfc_scene_read_emv_data.c

@@ -16,6 +16,8 @@ const void nfc_scene_read_emv_data_on_enter(void* context) {
     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
 
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
+    // Clear emv data
+    memset(&nfc->dev.dev_data.emv_data, 0, sizeof(nfc->dev.dev_data.emv_data));
     // Start worker
     nfc_worker_start(
         nfc->worker,

+ 40 - 0
applications/nfc/scenes/nfc_scene_read_emv_data_success.c

@@ -1,4 +1,5 @@
 #include "../nfc_i.h"
+#include "../helpers/nfc_emv_parser.h"
 
 void nfc_scene_read_emv_data_success_widget_callback(GuiButtonType result, void* context) {
     Nfc* nfc = (Nfc*)context;
@@ -15,6 +16,9 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
     nfc_device_set_name(&nfc->dev, "");
 
     // 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,
@@ -27,8 +31,10 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
         "Save",
         nfc_scene_read_emv_data_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 cad number
     char pan_str[32];
     snprintf(
         pan_str,
@@ -43,9 +49,41 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
         emv_data->number[6],
         emv_data->number[7]);
     widget_add_string_element(nfc->widget, 64, 13, AlignCenter, AlignTop, FontSecondary, pan_str);
+    // Parse country code
+    string_t country_name;
+    string_init(country_name);
+    if((emv_data->country_code) &&
+       nfc_emv_parser_get_country_name(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(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);
+    // Add ATQA
     char atqa_str[16];
     snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]);
     widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str);
+    // Add UID
     char uid_str[32];
     snprintf(
         uid_str,
@@ -56,9 +94,11 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
         nfc_data->uid[2],
         nfc_data->uid[3]);
     widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str);
+    // Add SAK
     char sak_str[16];
     snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
     widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
+    // Add expiration date
     if(emv_data->exp_mon) {
         char exp_str[16];
         snprintf(

+ 50 - 6
applications/nfc/views/bank_card.c

@@ -1,5 +1,5 @@
 #include "bank_card.h"
-#include <gui/modules/widget.h>
+#include "../helpers/nfc_emv_parser.h"
 #include <m-string.h>
 
 struct BankCard {
@@ -43,10 +43,20 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number) {
     for(uint8_t i = 0; i < 8; i += 2) {
         string_cat_printf(num_str, "%02X%02X ", number[i], number[i + 1]);
     }
+    // Add number
     widget_add_string_element(
-        bank_card->widget, 25, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(num_str));
-    widget_add_icon_element(bank_card->widget, 6, 20, &I_EMV_Chip_14x11);
+        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) {
@@ -57,8 +67,42 @@ void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) {
         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
 }
 
-void bank_card_set_cardholder_name(BankCard* bank_card, char* name) {
+void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code) {
     furi_assert(bank_card);
-    furi_assert(name);
-    widget_add_string_element(bank_card->widget, 6, 37, AlignLeft, AlignTop, FontSecondary, name);
+    string_t country_name;
+    string_init(country_name);
+    if(nfc_emv_parser_get_country_name(country_code, country_name)) {
+        string_t disp_country;
+        string_init_printf(disp_country, "Reg:%s", country_name);
+        widget_add_string_element(
+            bank_card->widget,
+            120,
+            18,
+            AlignRight,
+            AlignTop,
+            FontSecondary,
+            string_get_cstr(disp_country));
+        string_clear(disp_country);
+    }
+    string_clear(country_name);
+}
+
+void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code) {
+    furi_assert(bank_card);
+    string_t currency_name;
+    string_init(currency_name);
+    if(nfc_emv_parser_get_currency_name(currency_code, currency_name)) {
+        string_t disp_currency;
+        string_init_printf(disp_currency, "Cur:%s", currency_name);
+        widget_add_string_element(
+            bank_card->widget,
+            31,
+            18,
+            AlignLeft,
+            AlignTop,
+            FontSecondary,
+            string_get_cstr(disp_currency));
+        string_clear(disp_currency);
+    }
+    string_clear(currency_name);
 }

+ 6 - 3
applications/nfc/views/bank_card.h

@@ -1,11 +1,10 @@
 #pragma once
 #include <stdint.h>
 #include <gui/view.h>
+#include <gui/modules/widget.h>
 
 typedef struct BankCard BankCard;
 
-typedef void (*BankCardBackCallback)(void);
-
 BankCard* bank_card_alloc();
 
 void bank_card_free(BankCard* bank_card);
@@ -14,10 +13,14 @@ 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);
 
 void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year);
 
-void bank_card_set_cardholder_name(BankCard* bank_card, char* name);
+void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code);
+
+void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code);

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
assets/compiled/assets_icons.c


+ 52 - 52
assets/compiled/assets_icons.h

@@ -3,61 +3,61 @@
 
 extern const Icon A_WatchingTV_128x64;
 extern const Icon A_Wink_128x64;
-extern const Icon I_dir_10px;
 extern const Icon I_Nfc_10px;
-extern const Icon I_sub1_10px;
 extern const Icon I_ir_10px;
-extern const Icon I_ibutt_10px;
-extern const Icon I_unknown_10px;
 extern const Icon I_ble_10px;
+extern const Icon I_sub1_10px;
+extern const Icon I_dir_10px;
+extern const Icon I_unknown_10px;
+extern const Icon I_ibutt_10px;
 extern const Icon I_125_10px;
-extern const Icon I_ButtonRightSmall_3x5;
 extern const Icon I_ButtonLeft_4x7;
-extern const Icon I_ButtonLeftSmall_3x5;
-extern const Icon I_Warning_30x23;
 extern const Icon I_ButtonRight_4x7;
+extern const Icon I_Warning_30x23;
+extern const Icon I_ButtonRightSmall_3x5;
 extern const Icon I_ButtonCenter_7x7;
+extern const Icon I_ButtonLeftSmall_3x5;
 extern const Icon I_DolphinOkay_41x43;
+extern const Icon I_DolphinFirstStart7_61x51;
 extern const Icon I_DolphinFirstStart4_67x53;
-extern const Icon I_DolphinFirstStart2_59x51;
-extern const Icon I_DolphinFirstStart5_54x49;
+extern const Icon I_DolphinFirstStart3_57x48;
+extern const Icon I_Flipper_young_80x60;
 extern const Icon I_DolphinFirstStart0_70x53;
+extern const Icon I_DolphinFirstStart2_59x51;
 extern const Icon I_DolphinFirstStart6_58x54;
-extern const Icon I_DolphinFirstStart1_59x53;
+extern const Icon I_DolphinFirstStart5_54x49;
 extern const Icon I_DolphinFirstStart8_56x51;
-extern const Icon I_DolphinFirstStart7_61x51;
-extern const Icon I_Flipper_young_80x60;
-extern const Icon I_DolphinFirstStart3_57x48;
-extern const Icon I_PassportBottom_128x17;
-extern const Icon I_DoorLeft_8x56;
+extern const Icon I_DolphinFirstStart1_59x53;
+extern const Icon I_DoorRight_70x55;
 extern const Icon I_DoorLocked_10x56;
-extern const Icon I_DoorRight_8x56;
 extern const Icon I_DoorLeft_70x55;
 extern const Icon I_PassportLeft_6x47;
-extern const Icon I_DoorRight_70x55;
+extern const Icon I_DoorRight_8x56;
+extern const Icon I_DoorLeft_8x56;
 extern const Icon I_LockPopup_100x49;
-extern const Icon I_Mute_25x27;
+extern const Icon I_PassportBottom_128x17;
+extern const Icon I_Vol_up_25x27;
+extern const Icon I_Fill_marker_7x7;
 extern const Icon I_IrdaArrowUp_4x8;
+extern const Icon I_Down_hvr_25x27;
+extern const Icon I_Vol_up_hvr_25x27;
+extern const Icon I_Power_25x27;
+extern const Icon I_Vol_down_25x27;
+extern const Icon I_IrdaSend_128x64;
 extern const Icon I_Up_hvr_25x27;
+extern const Icon I_Back_15x10;
+extern const Icon I_IrdaSendShort_128x34;
 extern const Icon I_Mute_hvr_25x27;
-extern const Icon I_Vol_down_25x27;
-extern const Icon I_Down_25x27;
-extern const Icon I_Power_hvr_25x27;
 extern const Icon I_IrdaLearnShort_128x31;
-extern const Icon I_IrdaArrowDown_4x8;
+extern const Icon I_Down_25x27;
+extern const Icon I_Up_25x27;
+extern const Icon I_Mute_25x27;
 extern const Icon I_Vol_down_hvr_25x27;
+extern const Icon I_Power_hvr_25x27;
 extern const Icon I_IrdaLearn_128x64;
-extern const Icon I_Down_hvr_25x27;
-extern const Icon I_Fill_marker_7x7;
-extern const Icon I_Power_25x27;
-extern const Icon I_Vol_up_25x27;
-extern const Icon I_Up_25x27;
-extern const Icon I_Back_15x10;
-extern const Icon I_IrdaSend_128x64;
-extern const Icon I_IrdaSendShort_128x34;
-extern const Icon I_Vol_up_hvr_25x27;
-extern const Icon I_KeySave_24x11;
+extern const Icon I_IrdaArrowDown_4x8;
 extern const Icon I_KeyBackspaceSelected_16x9;
+extern const Icon I_KeySave_24x11;
 extern const Icon I_KeySaveSelected_24x11;
 extern const Icon I_KeyBackspace_16x9;
 extern const Icon A_125khz_14;
@@ -76,38 +76,38 @@ extern const Icon A_Tamagotchi_14;
 extern const Icon A_U2F_14;
 extern const Icon A_iButton_14;
 extern const Icon I_Medium_chip_22x21;
-extern const Icon I_EMV_Chip_14x11;
+extern const Icon I_Detailed_chip_17x13;
 extern const Icon I_Health_16x16;
-extern const Icon I_FaceCharging_29x14;
-extern const Icon I_BatteryBody_52x28;
-extern const Icon I_Voltage_16x16;
-extern const Icon I_Temperature_16x16;
 extern const Icon I_FaceNopower_29x14;
-extern const Icon I_FaceNormal_29x14;
 extern const Icon I_Battery_16x16;
+extern const Icon I_BatteryBody_52x28;
 extern const Icon I_FaceConfused_29x14;
-extern const Icon I_RFIDDolphinSuccess_108x57;
-extern const Icon I_RFIDBigChip_37x36;
-extern const Icon I_RFIDDolphinSend_97x61;
+extern const Icon I_FaceCharging_29x14;
+extern const Icon I_FaceNormal_29x14;
+extern const Icon I_Voltage_16x16;
+extern const Icon I_Temperature_16x16;
 extern const Icon I_RFIDDolphinReceive_97x61;
+extern const Icon I_RFIDDolphinSend_97x61;
+extern const Icon I_RFIDBigChip_37x36;
+extern const Icon I_RFIDDolphinSuccess_108x57;
 extern const Icon I_SDQuestion_35x43;
 extern const Icon I_SDError_43x35;
-extern const Icon I_BadUsb_9x8;
-extern const Icon I_PlaceholderR_30x13;
-extern const Icon I_Background_128x8;
-extern const Icon I_Lock_8x8;
 extern const Icon I_Battery_26x8;
 extern const Icon I_PlaceholderL_11x13;
-extern const Icon I_Battery_19x8;
-extern const Icon I_SDcardMounted_11x8;
-extern const Icon I_SDcardFail_11x8;
-extern const Icon I_USBConnected_15x8;
 extern const Icon I_Bluetooth_5x8;
+extern const Icon I_BadUsb_9x8;
+extern const Icon I_PlaceholderR_30x13;
+extern const Icon I_USBConnected_15x8;
+extern const Icon I_Battery_19x8;
+extern const Icon I_Lock_8x8;
 extern const Icon I_Background_128x11;
+extern const Icon I_Background_128x8;
+extern const Icon I_SDcardFail_11x8;
+extern const Icon I_SDcardMounted_11x8;
+extern const Icon I_iButtonDolphinVerySuccess_108x52;
 extern const Icon I_DolphinMafia_115x62;
-extern const Icon I_DolphinExcited_64x63;
 extern const Icon I_iButtonDolphinSuccess_109x60;
-extern const Icon I_iButtonDolphinVerySuccess_108x52;
-extern const Icon I_iButtonKey_49x44;
+extern const Icon I_DolphinExcited_64x63;
 extern const Icon I_DolphinNice_96x59;
+extern const Icon I_iButtonKey_49x44;
 extern const Icon I_DolphinWait_61x59;

BIN
assets/icons/NFC/Detailed_chip_17x13.png


BIN
assets/icons/NFC/EMV_Chip_14x11.png


+ 148 - 0
assets/resources/nfc/emv/aid.nfc

@@ -0,0 +1,148 @@
+A00000000305076010 VISA ELO Credit
+A0000000031010 VISA Debit/Credit (Classic)
+A000000003101001 VISA Credit
+A000000003101002 VISA Debit
+A0000000032010 VISA Electron
+A0000000032020 VISA
+A0000000033010 VISA Interlink
+A0000000034010 VISA Specific
+A0000000035010 VISA Specific
+A0000000036010 Domestic Visa Cash
+A0000000036020 International Visa Cash
+A0000000038002 VISA Auth EMV-CAP (DPA)
+A0000000038010 VISA Plus
+A0000000039010 VISA Loyalty
+A000000003999910 VISA Proprietary ATM
+A00000000401 MasterCard PayPass
+A0000000041010 MasterCard Global
+A00000000410101213 MasterCard Credit
+A00000000410101215 MasterCard Credit
+A0000000042010 MasterCard Specific
+A0000000043010 MasterCard Specific
+A0000000043060 Maestro (Debit)
+A000000004306001 Maestro (Debit)
+A0000000044010 MasterCard Specific
+A0000000045010 MasterCard Specific
+A0000000046000 Cirrus
+A0000000048002 SecureCode EMV-CAP
+A0000000049999 MasterCard PayPass
+A0000000050001 Maestro UK
+A0000000050002 Solo
+A00000002401 Self Service
+A000000025 American Express
+A0000000250000 American Express
+A00000002501 American Express
+A000000025010402 American Express
+A000000025010701 ExpressPay
+A000000025010801 American Express
+A0000000291010 Link / American Express
+A0000000421010 Cartes Bancaire EMV Card
+A0000000426010 Apple Pay
+A00000006510 JCB
+A0000000651010 JCB J Smart Credit
+A00000006900 Moneo
+A000000077010000021000000000003B Visa AEPN
+A000000098 Debit Card
+A0000000980848 Debit Card
+A0000001211010 Dankort VISA GEM Vision
+A0000001410001 PagoBANCOMAT
+A0000001523010 Discover, Pulse D Pas
+A0000001524010 Discover
+A0000001544442 Banricompras Debito
+A000000172950001 BAROC Taiwan
+A0000002281010 SPAN (M/Chip)
+A0000002282010 SPAN (VIS)
+A0000002771010 INTERAC
+A00000031510100528 Currence PuC
+A0000003156020 Chipknip
+A0000003591010028001 Girocard EAPS
+A0000003710001 InterSwitch Verve Card
+A0000004540010 Etranzact Genesis Card
+A0000004540011 Etranzact Genesis Card 2
+A0000004766C GOOGLE_PAYMENT
+A0000005241010 RuPay
+A0000006723010 TROY chip credit card
+A0000006723020 TROY chip debit card
+A0000007705850 XTRAPOWER
+B012345678 Maestro TEST
+D27600002545500100 Girocard
+D5780000021010 Bankaxept
+F0000000030001 BRADESCO
+A000000003000000 (VISA) Card Manager
+A000000003534441 Schlumberger SD
+A0000000035350 Security Domain
+A000000003535041 Security Domain
+A0000000040000 MasterCard Card Manager
+A000000018434D Gemplus card manager
+A000000018434D00 Gemplus Security Domain
+A0000000960200 Proton WISD
+A0000001510000 Global Platform SD
+A00000015153504341534400 CASD_AID
+A000000476A010 GSD_MANAGER_AID
+A000000476A110 GSD_MANAGER_AID
+315041592E5359532E4444463031 Visa PSE 
+325041592E5359532E4444463031 Visa PPSE
+A0000000042203 MasterCard Specific
+A0000000045555 APDULogger
+A0000000090001FF44FF1289 Orange
+A0000000101030 Maestro-CH
+A00000001800 Gemplus
+A0000000181001 gemplus util packages
+A000000025010104 American Express
+A00000002949034010100001 HSBC
+A00000002949282010100000 Barclay
+A00000005945430100 Girocard Electronic Cash
+A0000000980840 Visa Common Debit
+A0000001570010 AMEX
+A0000001570020 MasterCard
+A0000001570021 Maestro
+A0000001570022 Maestro
+A0000001570023 CASH
+A0000001570030 VISA
+A0000001570031 VISA
+A0000001570040 JCB
+A0000001570050 Postcard
+A0000001570051 Postcard
+A0000001570100 MCard
+A0000001570104 MyOne
+A000000157010C WIRCard
+A000000157010D Power Card
+A0000001574443 DINERS CLUB
+A0000001574444 Supercard Plus
+A00000022820101010 SPAN
+A000000308000010000100 ID-ONE PIV BIO
+A0000003241010 Discover Zip
+A000000333010101 UnionPay Debit
+A000000333010102 UnionPay Credit
+A000000333010103 UnionPay Quasi Credit
+A000000333010106 UnionPay Electronic Cash
+A000000333010108 U.S. UnionPay Common Debit
+A000000337102000 Classic
+A000000337101001 Prepaye Online
+A000000337102001 Prepaye Possibile Offiline
+A000000337601001 Porte Monnaie Electronique
+A0000006581010 MIR Credit
+A0000006581011 MIR Credit
+A0000006582010 MIR Debit
+D040000001000002 Paylife Quick IEP
+D040000002000002 RFU
+D040000003000002 POS
+D040000004000002 ATM
+D04000000B000002 Retail
+D04000000C000002 Bank_Data
+D04000000D000002 Shopping
+D040000013000001 DF_UNI_Kepler1
+D040000013000001 DF_Schüler1
+D040000013000002 DF_UNI_Kepler2
+D040000013000002 DF_Schüler2
+D040000014000001 DF_Mensa
+D040000015000001 DF_UNI_Ausweis
+D040000015000001 DF_Ausweis
+D0400000190001 EMV ATM Maestro
+D0400000190002 EMV POS Maestro
+D0400000190003 EMV ATM MasterCard
+D0400000190004 EMV POS MasterCard
+D276000025 Girocard
+D27600002547410100 Girocard ATM
+D7560000010101 Reka Card
+D7560000300101 M Budget

+ 249 - 0
assets/resources/nfc/emv/country_code.nfc

@@ -0,0 +1,249 @@
+0004 AFG
+0008 ALB
+0010 ATA
+0012 DZA
+0016 ASM
+0020 AND
+0024 AGO
+0028 ATG
+0031 AZE
+0032 ARG
+0036 AUS
+0040 AUT
+0044 BHS
+0048 BHR
+0050 BGD
+0051 ARM
+0052 BRB
+0056 BEL
+0060 BMU
+0064 BTN
+0068 BOL
+0070 BIH
+0072 BWA
+0074 BVT
+0076 BRA
+0084 BLZ
+0086 IOT
+0090 SLB
+0092 VGB
+0096 BRN
+0100 BGR
+0104 MMR
+0108 BDI
+0112 BLR
+0116 KHM
+0120 CMR
+0124 CAN
+0132 CPV
+0136 CYM
+0140 CAF
+0144 LKA
+0148 TCD
+0152 CHL
+0156 CHN
+0158 TWN
+0162 CXR
+0166 CCK
+0170 COL
+0174 COM
+0175 MYT
+0178 COG
+0180 COD
+0184 COK
+0188 CRI
+0191 HRV
+0192 CUB
+0196 CYP
+0203 CZE
+0204 BEN
+0208 DNK
+0212 DMA
+0214 DOM
+0218 ECU
+0222 SLV
+0226 GNQ
+0231 ETH
+0232 ERI
+0233 EST
+0234 FRO
+0238 FLK
+0239 SGS
+0242 FJI
+0246 FIN
+0248 ALA
+0250 FRA
+0254 GUF
+0258 PYF
+0260 ATF
+0262 DJI
+0266 GAB
+0268 GEO
+0270 GMB
+0275 PSE
+0276 DEU
+0288 GHA
+0292 GIB
+0296 KIR
+0300 GRC
+0304 GRL
+0308 GRD
+0312 GLP
+0316 GUM
+0320 GTM
+0324 GIN
+0328 GUY
+0332 HTI
+0334 HMD
+0336 VAT
+0340 HND
+0344 HKG
+0348 HUN
+0352 ISL
+0356 IND
+0360 IDN
+0364 IRN
+0368 IRQ
+0372 IRL
+0376 ISR
+0380 ITA
+0384 CIV
+0388 JAM
+0392 JPN
+0398 KAZ
+0400 JOR
+0404 KEN
+0408 PRK
+0410 KOR
+0414 KWT
+0417 KGZ
+0418 LAO
+0422 LBN
+0426 LSO
+0428 LVA
+0430 LBR
+0434 LBY
+0438 LIE
+0440 LTU
+0442 LUX
+0446 MAC
+0450 MDG
+0454 MWI
+0458 MYS
+0462 MDV
+0466 MLI
+0470 MLT
+0474 MTQ
+0478 MRT
+0480 MUS
+0484 MEX
+0492 MCO
+0496 MNG
+0498 MDA
+0499 MNE
+0500 MSR
+0504 MAR
+0508 MOZ
+0512 OMN
+0516 NAM
+0520 NRU
+0524 NPL
+0528 NLD
+0531 CUW
+0533 ABW
+0534 SXM
+0535 BES
+0540 NCL
+0548 VUT
+0554 NZL
+0558 NIC
+0562 NER
+0566 NGA
+0570 NIU
+0574 NFK
+0578 NOR
+0580 MNP
+0581 UMI
+0583 FSM
+0584 MHL
+0585 PLW
+0586 PAK
+0591 PAN
+0598 PNG
+0600 PRY
+0604 PER
+0608 PHL
+0612 PCN
+0616 POL
+0620 PRT
+0624 GNB
+0626 TLS
+0630 PRI
+0634 QAT
+0638 REU
+0642 ROU
+0643 RUS
+0646 RWA
+0652 BLM
+0654 SHN
+0659 KNA
+0660 AIA
+0662 LCA
+0663 MAF
+0666 SPM
+0670 VCT
+0674 SMR
+0678 STP
+0682 SAU
+0686 SEN
+0688 SRB
+0690 SYC
+0694 SLE
+0702 SGP
+0703 SVK
+0704 VNM
+0705 SVN
+0706 SOM
+0710 ZAF
+0716 ZWE
+0724 ESP
+0728 SSD
+0729 SDN
+0732 ESH
+0740 SUR
+0744 SJM
+0748 SWZ
+0752 SWE
+0756 CHE
+0760 SYR
+0762 TJK
+0764 THA
+0768 TGO
+0772 TKL
+0776 TON
+0780 TTO
+0784 ARE
+0788 TUN
+0792 TUR
+0795 TKM
+0796 TCA
+0798 TUV
+0800 UGA
+0804 UKR
+0807 MKD
+0818 EGY
+0826 GBR
+0831 GGY
+0832 JEY
+0833 IMN
+0834 TZA
+0840 USA
+0850 VIR
+0854 BFA
+0858 URY
+0860 UZB
+0862 VEN
+0876 WLF
+0882 WSM
+0887 YEM
+0894 ZMB

+ 168 - 0
assets/resources/nfc/emv/currency_code.nfc

@@ -0,0 +1,168 @@
+0997 USN
+0994 XSU
+0990 CLF
+0986 BRL
+0985 PLN
+0984 BOV
+0981 GEL
+0980 UAH
+0979 MXV
+0978 EUR
+0977 BAM
+0976 CDF
+0975 BGN
+0973 AOA
+0972 TJS
+0971 AFN
+0970 COU
+0969 MGA
+0968 SRD
+0967 ZMW
+0965 XUA
+0960 XDR
+0953 XPF
+0952 XOF
+0951 XCD
+0950 XAF
+0949 TRY
+0948 CHW
+0947 CHE
+0946 RON
+0944 AZN
+0943 MZN
+0941 RSD
+0940 UYI
+0938 SDG
+0937 VEF
+0936 GHS
+0934 TMT
+0933 BYN
+0932 ZWL
+0931 CUC
+0930 STN
+0929 MRU
+0901 TWD
+0886 YER
+0882 WST
+0860 UZS
+0858 UYU
+0840 USD
+0834 TZS
+0826 GBP
+0818 EGP
+0807 MKD
+0800 UGX
+0788 TND
+0784 AED
+0780 TTD
+0776 TOP
+0764 THB
+0760 SYP
+0756 CHF
+0752 SEK
+0748 SZL
+0728 SSP
+0710 ZAR
+0706 SOS
+0704 VND
+0702 SGD
+0694 SLL
+0690 SCR
+0682 SAR
+0654 SHP
+0646 RWF
+0643 RUB
+0634 QAR
+0608 PHP
+0604 PEN
+0600 PYG
+0598 PGK
+0590 PAB
+0586 PKR
+0578 NOK
+0566 NGN
+0558 NIO
+0554 NZD
+0548 VUV
+0533 AWG
+0532 ANG
+0524 NPR
+0516 NAD
+0512 OMR
+0504 MAD
+0498 MDL
+0496 MNT
+0484 MXN
+0480 MUR
+0462 MVR
+0458 MYR
+0454 MWK
+0446 MOP
+0434 LYD
+0430 LRD
+0426 LSL
+0422 LBP
+0418 LAK
+0417 KGS
+0414 KWD
+0410 KRW
+0408 KPW
+0404 KES
+0400 JOD
+0398 KZT
+0392 JPY
+0388 JMD
+0376 ILS
+0368 IQD
+0364 IRR
+0360 IDR
+0356 INR
+0352 ISK
+0348 HUF
+0344 HKD
+0340 HNL
+0332 HTG
+0328 GYD
+0324 GNF
+0320 GTQ
+0292 GIP
+0270 GMD
+0262 DJF
+0242 FJD
+0238 FKP
+0232 ERN
+0230 ETB
+0222 SVC
+0214 DOP
+0208 DKK
+0203 CZK
+0192 CUP
+0191 HRK
+0188 CRC
+0174 KMF
+0170 COP
+0156 CNY
+0152 CLP
+0144 LKR
+0136 KYD
+0132 CVE
+0124 CAD
+0116 KHR
+0108 BIF
+0104 MMK
+0096 BND
+0090 SBD
+0084 BZD
+0072 BWP
+0068 BOB
+0064 BTN
+0060 BMD
+0052 BBD
+0051 AMD
+0050 BDT
+0048 BHD
+0044 BSD
+0036 AUD
+0032 ARS
+0012 DZD
+0008 ALL

+ 3 - 1
lib/ST25RFAL002/source/rfal_nfc.c

@@ -575,7 +575,9 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_
             *rvdLen = (uint16_t*)&gNfcDev.rxLen;
             *rxData = (uint8_t*)(  (gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) ? gNfcDev.rxBuf.isoDepBuf.apdu : 
                                   ((gNfcDev.activeDev->rfInterface == RFAL_NFC_INTERFACE_NFCDEP) ? gNfcDev.rxBuf.nfcDepBuf.pdu  : gNfcDev.rxBuf.rfBuf));
-            gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
+            if(gNfcDev.disc.activate_after_sak) {
+                gNfcDev.state = RFAL_NFC_STATE_DATAEXCHANGE_DONE;
+            }
             return ERR_NONE;
         }
         

+ 4 - 0
lib/app-scened-template/file-worker-cpp.cpp

@@ -71,6 +71,10 @@ bool FileWorkerCpp::read_until_buffered(string_t str_result, char* file_buf, siz
     return file_worker_read_until_buffered(file_worker, str_result, file_buf, file_buf_cnt, max_length, separator);
 }
 
+bool FileWorkerCpp::get_value_from_key(string_t key, char delimiter, string_t value) {
+    return file_worker_get_value_from_key(file_worker, key, delimiter, value);
+}
+
 bool FileWorkerCpp::is_file_exist(const char* filename, bool* exist) {
     return file_worker_is_file_exist(file_worker, filename, exist);
 }

+ 11 - 0
lib/app-scened-template/file-worker-cpp.h

@@ -143,6 +143,17 @@ public:
      */
     bool read_until_buffered(string_t str_result, char* file_buf, size_t* file_buf_cnt, size_t max_length, char separator = '\n');
 
+    /**
+     * @brief Gets value from key
+     *
+     * @param file_worker FileWorker instance
+     * @param key key
+     * @param delimeter key-value delimeter
+     * @param value value for given key
+     * @return true on success
+     */
+    bool get_value_from_key(string_t key, char delimiter, string_t value);
+
     /**
      * @brief Check whether file exist or not
      *

+ 28 - 0
lib/app-scened-template/file-worker.c

@@ -355,6 +355,34 @@ bool file_worker_read_until_buffered(
     return string_size(str_result) || *file_buf_cnt;
 }
 
+bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value) {
+    bool found = false;
+    string_t next_line;
+    string_t next_key;
+    string_init(next_line);
+    string_init(next_key);
+    size_t delim_pos = 0;
+
+    while(file_worker_read_until(file_worker, next_line, '\n')) {
+        delim_pos = string_search_char(next_line, delimiter);
+        if(delim_pos == STRING_FAILURE) {
+            break;
+        }
+        string_set_n(next_key, next_line, 0, delim_pos);
+        if(string_equal_p(next_key, key)) {
+            string_right(next_line, delim_pos);
+            string_strim(next_line);
+            string_set(value, next_line);
+            found = true;
+            break;
+        }
+    }
+
+    string_clear(next_line);
+    string_clear(next_key);
+    return found;
+}
+
 bool file_worker_rename(FileWorker* file_worker, const char* old_path, const char* new_path) {
     FS_Error fs_result = storage_common_rename(file_worker->api, old_path, new_path);
 

+ 11 - 0
lib/app-scened-template/file-worker.h

@@ -185,6 +185,17 @@ bool file_worker_read_until_buffered(
     size_t max_length,
     char separator);
 
+/**
+ * @brief Gets value from key
+ *
+ * @param file_worker FileWorker instance
+ * @param key key
+ * @param delimeter key-value delimeter
+ * @param value value for given key
+ * @return true on success
+ */
+bool file_worker_get_value_from_key(FileWorker* file_worker, string_t key, char delimiter, string_t value);
+
 /**
  * @brief Check whether file exist or not
  *

+ 15 - 2
lib/nfc_protocols/emv_decoder.c

@@ -63,6 +63,14 @@ static uint16_t emv_parse_TLV(uint8_t* dest, uint8_t* src, uint16_t* idx) {
     return len;
 }
 
+static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* idx) {
+    if((buff[*idx] << 8 | buff[*idx + 1]) == tag) {
+        *idx = *idx + 3;
+        return true;
+    }
+    return false;
+}
+
 uint16_t emv_prepare_select_ppse(uint8_t* dest) {
     const uint8_t emv_select_ppse[] = {
         0x00, 0xA4, // SELECT ppse
@@ -219,10 +227,15 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app
         if(buff[i] == EMV_TAG_PAN) {
             memcpy(app->card_number, &buff[i + 2], 8);
             pan_parsed = true;
-        } else if((buff[i] << 8 | buff[i + 1]) == EMV_TAG_EXP_DATE) {
-            i += 3;
+        } else if(emv_decode_search_tag_u16_r(EMV_TAG_EXP_DATE, buff, &i)) {
             app->exp_year = buff[i++];
             app->exp_month = buff[i++];
+        } else if(emv_decode_search_tag_u16_r(EMV_TAG_CURRENCY_CODE, buff, &i)) {
+            app->currency_code = (buff[i] << 8) | buff[i + 1];
+            i += 2;
+        } else if(emv_decode_search_tag_u16_r(EMV_TAG_COUNTRY_CODE, buff, &i)) {
+            app->country_code = (buff[i] << 8) | buff[i + 1];
+            i += 2;
         }
     }
     return pan_parsed;

+ 4 - 1
lib/nfc_protocols/emv_decoder.h

@@ -17,6 +17,8 @@
 #define EMV_TAG_PAN 0x5A
 #define EMV_TAG_AFL 0x94
 #define EMV_TAG_EXP_DATE 0x5F24
+#define EMV_TAG_COUNTRY_CODE 0x5F28
+#define EMV_TAG_CURRENCY_CODE 0x9F42
 #define EMV_TAG_CARDHOLDER_NAME 0x5F20
 
 typedef struct {
@@ -39,7 +41,8 @@ typedef struct {
     uint8_t card_number[8];
     uint8_t exp_month;
     uint8_t exp_year;
-    char crdholder_name[32];
+    uint16_t country_code;
+    uint16_t currency_code;
     APDU pdol;
     APDU afl;
 } EmvApplication;

+ 8 - 0
scripts/ReadMe.md

@@ -53,3 +53,11 @@ Setting option bytes:
 ```bash
 ob.py set
 ```
+
+# Assets delivery
+
+Run in the root folder of the repo:
+
+```bash
+python scripts/storage.py -p <flipper_cli_port> send assets/resources /ext
+```

Некоторые файлы не были показаны из-за большого количества измененных файлов