Преглед изворни кода

Fix read errors on some Navigo cards + add logs + more tariffs + parse contract status

DocSystem пре 1 година
родитељ
комит
30d79de2cc
1 измењених фајлова са 59 додато и 11 уклоњено
  1. 59 11
      scenes/metroflip_scene_navigo.c

+ 59 - 11
scenes/metroflip_scene_navigo.c

@@ -22,6 +22,17 @@ int select_new_app(
 
     bit_buffer_reset(tx_buffer);
     bit_buffer_append_bytes(tx_buffer, select_app, sizeof(select_app));
+    FURI_LOG_D(
+        TAG,
+        "SEND %02x %02x %02x %02x %02x %02x %02x %02x",
+        select_app[0],
+        select_app[1],
+        select_app[2],
+        select_app[3],
+        select_app[4],
+        select_app[5],
+        select_app[6],
+        select_app[7]);
     int error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
     if(error != Iso14443_4bErrorNone) {
         FURI_LOG_I(TAG, "Select File: iso14443_4b_poller_send_block error %d", error);
@@ -42,6 +53,14 @@ int read_new_file(
     read_file[2] = new_file;
     bit_buffer_reset(tx_buffer);
     bit_buffer_append_bytes(tx_buffer, read_file, sizeof(read_file));
+    FURI_LOG_D(
+        TAG,
+        "SEND %02x %02x %02x %02x %02x",
+        read_file[0],
+        read_file[1],
+        read_file[2],
+        read_file[3],
+        read_file[4]);
     Iso14443_4bError error =
         iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
     if(error != Iso14443_4bErrorNone) {
@@ -61,11 +80,14 @@ int check_response(
     *response_length = bit_buffer_get_size_bytes(rx_buffer);
     if(bit_buffer_get_byte(rx_buffer, *response_length - 2) != apdu_success[0] ||
        bit_buffer_get_byte(rx_buffer, *response_length - 1) != apdu_success[1]) {
-        FURI_LOG_I(
-            TAG,
-            "Select profile app/file failed: %02x%02x",
-            bit_buffer_get_byte(rx_buffer, *response_length - 2),
-            bit_buffer_get_byte(rx_buffer, *response_length - 1));
+        int error_code_1 = bit_buffer_get_byte(rx_buffer, *response_length - 2);
+        int error_code_2 = bit_buffer_get_byte(rx_buffer, *response_length - 1);
+        FURI_LOG_E(TAG, "Select profile app/file failed: %02x%02x", error_code_1, error_code_2);
+        if(error_code_1 == 0x6a && error_code_2 == 0x82) {
+            FURI_LOG_E(TAG, "Wrong parameter(s) P1-P2 - File not found");
+        } else if(error_code_1 == 0x69 && error_code_2 == 0x82) {
+            FURI_LOG_E(TAG, "Command not allowed - Security status not satisfied");
+        }
         *stage = MetroflipPollerEventTypeFail;
         view_dispatcher_send_custom_event(
             app->view_dispatcher, MetroflipCustomEventPollerFileNotFound);
@@ -203,13 +225,13 @@ const char* get_navigo_type(int type) {
 const char* get_tariff(int tariff) {
     switch(tariff) {
     case 0x0000:
-        return "Navigo Mois"; // Theoric
+        return "Navigo Mois";
     case 0x0001:
-        return "Navigo Semaine"; // Theoric
+        return "Navigo Semaine";
     case 0x0002:
         return "Navigo Annuel";
     case 0x0003:
-        return "Navigo Jour"; // Theoric
+        return "Navigo Jour";
     case 0x0004:
         return "Imagine R Junior";
     case 0x0005:
@@ -220,6 +242,10 @@ const char* get_tariff(int tariff) {
         return "Paris-Visite"; // Theoric
     case 0x1000:
         return "Navigo Liberte+";
+    case 0x4000:
+        return "Navigo Mois 75%%";
+    case 0x4001:
+        return "Navigo Semaine 75%%";
     case 0x4015:
         return "Paris-Visite (Enfant)"; // Theoric
     case 0x5000:
@@ -242,6 +268,8 @@ const char* get_tariff(int tariff) {
         return "Metro-Train-RER (Reduit)"; // Theoric
     case 0x501b:
         return "Paris <> Aeroports (Reduit)"; // Theoric
+    case 0x8003:
+        return "Navigo Solidarite Gratuit";
     default: {
         char* tariff_str = malloc(6 * sizeof(char));
         snprintf(tariff_str, 6, "%d", tariff);
@@ -582,7 +610,11 @@ void show_contract_info(NavigoCardContract* contract, FuriString* parsed_data) {
     furi_string_cat_printf(
         parsed_data, "Sales Agent: %s\n", get_service_provider(contract->sale_agent));
     furi_string_cat_printf(parsed_data, "Sales Terminal: %d\n", contract->sale_device);
-    furi_string_cat_printf(parsed_data, "Status: %d\n", contract->status);
+    if(contract->status == 1) {
+        furi_string_cat_printf(parsed_data, "Status: OK\n");
+    } else {
+        furi_string_cat_printf(parsed_data, "Status: Unknown (%d)\n", contract->status);
+    }
     furi_string_cat_printf(parsed_data, "Authenticity Code: %d\n", contract->authenticator);
 }
 
@@ -832,20 +864,34 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
                 }
                 icc_bit_representation[response_length * 8] = '\0';
 
-                FURI_LOG_I(TAG, "ICC bit representation: %s", icc_bit_representation);
-
                 int start = 128, end = 159;
                 card->card_number = bit_slice_to_dec(icc_bit_representation, start, end);
 
+                // Select app for ticketing
+                error = select_new_app(
+                    0x20, 0x00, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
+                if(error != 0) {
+                    FURI_LOG_E(TAG, "Failed to select app for ticketing");
+                    break;
+                }
+
+                // Check the response after selecting app
+                if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
+                    FURI_LOG_E(TAG, "Failed to check response after selecting app for ticketing");
+                    break;
+                }
+
                 // Select app for contracts
                 error = select_new_app(
                     0x20, 0x20, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
                 if(error != 0) {
+                    FURI_LOG_E(TAG, "Failed to select app for contracts");
                     break;
                 }
 
                 // Check the response after selecting app
                 if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
+                    FURI_LOG_E(TAG, "Failed to check response after selecting app for contracts");
                     break;
                 }
 
@@ -861,11 +907,13 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
                     error =
                         read_new_file(i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
                     if(error != 0) {
+                        FURI_LOG_E(TAG, "Failed to read contract %d", i);
                         break;
                     }
 
                     // Check the response after reading the file
                     if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
+                        FURI_LOG_E(TAG, "Failed to check response after reading contract %d", i);
                         break;
                     }