فهرست منبع

Better parsing of SNCF train stations on Navigo

DocSystem 1 سال پیش
والد
کامیت
f9df843341
5فایلهای تغییر یافته به همراه185 افزوده شده و 165 حذف شده
  1. 46 34
      api/calypso/transit/navigo.c
  2. 5 1
      api/calypso/transit/navigo.h
  3. 2 0
      api/calypso/transit/navigo_i.h
  4. 129 130
      api/calypso/transit/navigo_lists.h
  5. 3 0
      scenes/metroflip_scene_calypso.c

+ 46 - 34
api/calypso/transit/navigo.c

@@ -211,21 +211,40 @@ int get_intercode_subversion(int version) {
     return version & 0x07;
     return version & 0x07;
 }
 }
 
 
-const char* get_navigo_station(int station_group_id, int station_id, int service_provider) {
+char* get_navigo_station(
+    int station_group_id,
+    int station_id,
+    int station_sub_id,
+    int service_provider) {
     switch(service_provider) {
     switch(service_provider) {
     case NAVIGO_PROVIDER_SNCF: {
     case NAVIGO_PROVIDER_SNCF: {
         if(station_group_id < 77 && station_id < 19) {
         if(station_group_id < 77 && station_id < 19) {
-            const char* station_name = NAVIGO_SNCF_LOCATION_LIST[station_group_id][station_id];
-            if(station_name) {
-                return station_name;
+            const char* station_group_name =
+                NAVIGO_SNCF_LOCATION_LIST[station_group_id][station_id];
+            if(station_group_name) {
+                // split station_name by '|' and return the station_sub_id - 1 element
+                char* station_name = strdup(station_group_name);
+                if(!station_name) {
+                    return "Unknown";
+                }
+                char* token = strtok(station_name, "|");
+                for(int i = 0; i < station_sub_id - 1; i++) {
+                    token = strtok(NULL, "|");
+                    if(!token) {
+                        break;
+                    }
+                }
+                if(token) {
+                    return token;
+                }
             }
             }
         }
         }
-        // cast station_group_id-station_id to a string
+        // cast station_group_id-station_id-station_sub_id to a string
         char* station = malloc(12 * sizeof(char));
         char* station = malloc(12 * sizeof(char));
         if(!station) {
         if(!station) {
             return "Unknown";
             return "Unknown";
         }
         }
-        snprintf(station, 10, "%d-%d", station_group_id, station_id);
+        snprintf(station, 10, "%d-%d-%d", station_group_id, station_id, station_sub_id);
         return station;
         return station;
     }
     }
     case NAVIGO_PROVIDER_RATP:
     case NAVIGO_PROVIDER_RATP:
@@ -233,7 +252,7 @@ const char* get_navigo_station(int station_group_id, int station_id, int service
         if(station_group_id < 32 && station_id < 16) {
         if(station_group_id < 32 && station_id < 16) {
             const char* station_name = NAVIGO_RATP_LOCATION_LIST[station_group_id][station_id];
             const char* station_name = NAVIGO_RATP_LOCATION_LIST[station_group_id][station_id];
             if(station_name) {
             if(station_name) {
-                return station_name;
+                return strdup(station_name);
             }
             }
         }
         }
         // cast station_group_id-station_id to a string
         // cast station_group_id-station_id to a string
@@ -288,6 +307,10 @@ void show_navigo_event_info(
         furi_string_cat_printf(parsed_data, "No event data\n");
         furi_string_cat_printf(parsed_data, "No event data\n");
         return;
         return;
     }
     }
+    char* station = get_navigo_station(
+        event->station_group_id, event->station_id, event->station_sub_id, event->service_provider);
+    char* sector = get_navigo_station(event->station_group_id, 0, 0, event->service_provider);
+
     if(event->transport_type == URBAN_BUS || event->transport_type == INTERURBAN_BUS ||
     if(event->transport_type == URBAN_BUS || event->transport_type == INTERURBAN_BUS ||
        event->transport_type == METRO || event->transport_type == TRAM) {
        event->transport_type == METRO || event->transport_type == TRAM) {
         if(event->route_number_available) {
         if(event->route_number_available) {
@@ -323,11 +346,7 @@ void show_navigo_event_info(
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data,
-            "Station: %s\nSector: %s\n",
-            get_navigo_station(event->station_group_id, event->station_id, event->service_provider),
-            get_navigo_station(event->station_group_id, 0, event->service_provider));
+        furi_string_cat_printf(parsed_data, "Station: %s\nSector: %s\n", station, sector);
         if(event->location_gate_available) {
         if(event->location_gate_available) {
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
         }
         }
@@ -373,14 +392,7 @@ void show_navigo_event_info(
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data,
-            "Station: %s\n",
-            get_navigo_station(
-                event->station_group_id, event->station_id, event->service_provider));
-        /* if(event->route_number_available) {
-            furi_string_cat_printf(parsed_data, "Route: %d\n", event->route_number);
-        } */
+        furi_string_cat_printf(parsed_data, "Station: %s\n", station);
         if(event->location_gate_available) {
         if(event->location_gate_available) {
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
         }
         }
@@ -416,8 +428,7 @@ void show_navigo_event_info(
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data, "Station ID: %d-%d\n", event->station_group_id, event->station_id);
+        furi_string_cat_printf(parsed_data, "Station: %s\n", station);
         if(event->location_gate_available) {
         if(event->location_gate_available) {
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
             furi_string_cat_printf(parsed_data, "Gate: %d\n", event->location_gate);
         }
         }
@@ -440,9 +451,16 @@ void show_navigo_event_info(
         locale_format_datetime_cat(parsed_data, &event->date, true);
         locale_format_datetime_cat(parsed_data, &event->date, true);
         furi_string_cat_printf(parsed_data, "\n");
         furi_string_cat_printf(parsed_data, "\n");
     }
     }
+
+    free(station);
+    free(sector);
 }
 }
 
 
 void show_navigo_special_event_info(NavigoCardSpecialEvent* event, FuriString* parsed_data) {
 void show_navigo_special_event_info(NavigoCardSpecialEvent* event, FuriString* parsed_data) {
+    char* station = get_navigo_station(
+        event->station_group_id, event->station_id, event->station_sub_id, event->service_provider);
+    char* sector = get_navigo_station(event->station_group_id, 0, 0, event->service_provider);
+
     if(event->transport_type == URBAN_BUS || event->transport_type == INTERURBAN_BUS ||
     if(event->transport_type == URBAN_BUS || event->transport_type == INTERURBAN_BUS ||
        event->transport_type == METRO || event->transport_type == TRAM) {
        event->transport_type == METRO || event->transport_type == TRAM) {
         if(event->route_number_available) {
         if(event->route_number_available) {
@@ -480,11 +498,7 @@ void show_navigo_special_event_info(NavigoCardSpecialEvent* event, FuriString* p
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data,
-            "Station: %s\nSector: %s\n",
-            get_navigo_station(event->station_group_id, event->station_id, event->service_provider),
-            get_navigo_station(event->station_group_id, 0, event->service_provider));
+        furi_string_cat_printf(parsed_data, "Station: %s\nSector: %s\n", station, sector);
         if(event->device_available) {
         if(event->device_available) {
             furi_string_cat_printf(parsed_data, "Device: %d\n", event->device);
             furi_string_cat_printf(parsed_data, "Device: %d\n", event->device);
         }
         }
@@ -511,11 +525,7 @@ void show_navigo_special_event_info(NavigoCardSpecialEvent* event, FuriString* p
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data,
-            "Station: %s\n",
-            get_navigo_station(
-                event->station_group_id, event->station_id, event->service_provider));
+        furi_string_cat_printf(parsed_data, "Station: %s\n", station);
         if(event->device_available) {
         if(event->device_available) {
             if(event->service_provider == NAVIGO_PROVIDER_SNCF) {
             if(event->service_provider == NAVIGO_PROVIDER_SNCF) {
                 furi_string_cat_printf(parsed_data, "Device: %d\n", event->device & 0xFF);
                 furi_string_cat_printf(parsed_data, "Device: %d\n", event->device & 0xFF);
@@ -537,14 +547,16 @@ void show_navigo_special_event_info(NavigoCardSpecialEvent* event, FuriString* p
             parsed_data,
             parsed_data,
             "Transporter: %s\n",
             "Transporter: %s\n",
             get_navigo_service_provider(event->service_provider));
             get_navigo_service_provider(event->service_provider));
-        furi_string_cat_printf(
-            parsed_data, "Station ID: %d-%d\n", event->station_group_id, event->station_id);
+        furi_string_cat_printf(parsed_data, "Station: %s\n", station);
         if(event->device_available) {
         if(event->device_available) {
             furi_string_cat_printf(parsed_data, "Device: %d\n", event->device);
             furi_string_cat_printf(parsed_data, "Device: %d\n", event->device);
         }
         }
         locale_format_datetime_cat(parsed_data, &event->date, true);
         locale_format_datetime_cat(parsed_data, &event->date, true);
         furi_string_cat_printf(parsed_data, "\n");
         furi_string_cat_printf(parsed_data, "\n");
     }
     }
+
+    free(station);
+    free(sector);
 }
 }
 
 
 void show_navigo_contract_info(NavigoCardContract* contract, FuriString* parsed_data) {
 void show_navigo_contract_info(NavigoCardContract* contract, FuriString* parsed_data) {

+ 5 - 1
api/calypso/transit/navigo.h

@@ -10,7 +10,11 @@
 
 
 const char* get_navigo_type(int type);
 const char* get_navigo_type(int type);
 
 
-const char* get_navigo_station(int station_group_id, int station_id, int service_provider);
+char* get_navigo_station(
+    int station_group_id,
+    int station_id,
+    int station_sub_id,
+    int service_provider);
 
 
 const char* get_navigo_sncf_train_line(int station_group_id);
 const char* get_navigo_sncf_train_line(int station_group_id);
 
 

+ 2 - 0
api/calypso/transit/navigo_i.h

@@ -10,6 +10,7 @@ typedef struct {
     int service_provider;
     int service_provider;
     int station_group_id;
     int station_group_id;
     int station_id;
     int station_id;
+    int station_sub_id;
     int location_gate;
     int location_gate;
     bool location_gate_available;
     bool location_gate_available;
     int device;
     int device;
@@ -34,6 +35,7 @@ typedef struct {
     int service_provider;
     int service_provider;
     int station_group_id;
     int station_group_id;
     int station_id;
     int station_id;
+    int station_sub_id;
     int device;
     int device;
     bool device_available;
     bool device_available;
     int route_number;
     int route_number;

+ 129 - 130
api/calypso/transit/navigo_lists.h

@@ -388,225 +388,224 @@ static const char* NAVIGO_SNCF_TRAIN_LINES_LIST[77] = {
     [73] = "Transilien J", [75] = "RER C",        [76] = "RER C"};
     [73] = "Transilien J", [75] = "RER C",        [76] = "RER C"};
 
 
 static const char* NAVIGO_SNCF_LOCATION_LIST[77][19] = {
 static const char* NAVIGO_SNCF_LOCATION_LIST[77][19] = {
-    [1] = {[0] = "Châtelet-Les Halles", [1] = "Châtelet-Les Halles", [7] = "Luxembourg"},
+    [1] = {[0] = "Chatelet-Les Halles", [1] = "Chatelet-Les Halles", [7] = "Luxembourg"},
     [3] = {[0] = "Saint-Michel Notre-Dame"},
     [3] = {[0] = "Saint-Michel Notre-Dame"},
     [6] = {[0] = "Auber", [6] = "Auber"},
     [6] = {[0] = "Auber", [6] = "Auber"},
     [14] = {[4] = "Cite Universitaire"},
     [14] = {[4] = "Cite Universitaire"},
     [15] = {[12] = "Port Royal"},
     [15] = {[12] = "Port Royal"},
     [16] =
     [16] =
         {[1] = "Nation",
         {[1] = "Nation",
-         [2] = "Fontenay-sous-Bois | Vincennes",
-         [3] = "Joinville-le-Pont | Nogent-sur-Marne",
+         [2] = "Fontenay-sous-Bois|Vincennes",
+         [3] = "Joinville-le-Pont|Nogent-sur-Marne",
          [4] = "Saint-Maur Creteil",
          [4] = "Saint-Maur Creteil",
          [5] = "Le Parc de Saint-Maur",
          [5] = "Le Parc de Saint-Maur",
          [6] = "Champigny",
          [6] = "Champigny",
          [7] = "La Varenne-Chennevieres",
          [7] = "La Varenne-Chennevieres",
-         [8] = "Boissy-Saint-Leger | Sucy Bonneuil"},
+         [8] = "Boissy-Saint-Leger|Sucy Bonneuil"},
     [17] =
     [17] =
         {[1] = "Charles de Gaulle-Etoile",
         {[1] = "Charles de Gaulle-Etoile",
          [4] = "La Defense (Grande Arche)",
          [4] = "La Defense (Grande Arche)",
          [5] = "Nanterre-Ville",
          [5] = "Nanterre-Ville",
          [6] = "Rueil-Malmaison",
          [6] = "Rueil-Malmaison",
          [8] = "Chatou-Croissy",
          [8] = "Chatou-Croissy",
-         [9] = "Le Vesinet-Centre | Le Vesinet-Le Pecq | Saint-Germain-en-Laye"},
+         [9] = "Le Vesinet-Centre|Le Vesinet-Le Pecq|Saint-Germain-en-Laye"},
     [18] =
     [18] =
         {[0] = "Denfert-Rochereau",
         {[0] = "Denfert-Rochereau",
          [1] = "Gentilly",
          [1] = "Gentilly",
-         [2] = "Arcueil-Cachan | Laplace",
-         [3] = "Bagneux | Bourg-la-Reine",
-         [4] = "La Croix-de-Berny | Parc de Sceaux",
-         [5] = "Antony | Fontaine-Michalon | Les Baconnets",
-         [6] = "Massy-Palaiseau | Massy-Verrieres",
-         [7] = "Palaiseau Villebon | Palaiseau",
+         [2] = "Arcueil-Cachan|Laplace",
+         [3] = "Bagneux|Bourg-la-Reine",
+         [4] = "La Croix-de-Berny|Parc de Sceaux",
+         [5] = "Antony|Fontaine-Michalon|Les Baconnets",
+         [6] = "Massy-Palaiseau|Massy-Verrieres",
+         [7] = "Palaiseau Villebon|Palaiseau",
          [8] = "Lozere",
          [8] = "Lozere",
-         [9] = "Le Guichet | Orsay-Ville",
+         [9] = "Le Guichet|Orsay-Ville",
          [10] =
          [10] =
-             "Bures-sur-Yvette | Courcelle-sur-Yvette | Gif-sur-Yvette | La Hacquiniere | Saint-Remy-les-Chevreuse"},
+             "Bures-sur-Yvette|Courcelle-sur-Yvette|Gif-sur-Yvette|La Hacquiniere|Saint-Remy-les-Chevreuse"},
     [20] =
     [20] =
         {[1] = "Gare de l'Est",
         {[1] = "Gare de l'Est",
          [4] = "Pantin",
          [4] = "Pantin",
          [5] = "Noisy-le-Sec",
          [5] = "Noisy-le-Sec",
          [6] = "Bondy",
          [6] = "Bondy",
-         [7] = "Gagny | Le Raincy Villemomble Montfermeil",
-         [9] = "Chelles Gournay | Le Chenay Gagny",
+         [7] = "Gagny|Le Raincy Villemomble Montfermeil",
+         [9] = "Chelles Gournay|Le Chenay Gagny",
          [10] = "Vaires Torcy",
          [10] = "Vaires Torcy",
          [11] = "Lagny-Thorigny",
          [11] = "Lagny-Thorigny",
          [13] = "Esbly",
          [13] = "Esbly",
          [14] = "Meaux",
          [14] = "Meaux",
-         [15] = "Changis-Saint-Jean | Isles-Armentieres Congis | Lizy-sur-Ourcq | Trilport",
-         [16] = "Crouy-sur-Ourcq | La Ferte-sous-Jouarre | Nanteuil Saacy"},
+         [15] = "Changis-Saint-Jean|Isles-Armentieres Congis|Lizy-sur-Ourcq|Trilport",
+         [16] = "Crouy-sur-Ourcq|La Ferte-sous-Jouarre|Nanteuil Saacy"},
     [21] =
     [21] =
-        {[5] = "Rosny-Bois-Perrier | Rosny-sous-Bois | Val de Fontenay",
+        {[5] = "Rosny-Bois-Perrier|Rosny-sous-Bois|Val de Fontenay",
          [6] = "Nogent Le-Perreux",
          [6] = "Nogent Le-Perreux",
          [7] = "Les Boullereaux Champigny",
          [7] = "Les Boullereaux Champigny",
          [8] = "Villiers-sur-Marne Plessis-Trevise",
          [8] = "Villiers-sur-Marne Plessis-Trevise",
          [9] = "Les Yvris Noisy-le-Grand",
          [9] = "Les Yvris Noisy-le-Grand",
-         [10] = "Emerainville Pontault-Combault | Roissy-en-Brie",
+         [10] = "Emerainville Pontault-Combault|Roissy-en-Brie",
          [11] = "Ozoir-la-Ferriere",
          [11] = "Ozoir-la-Ferriere",
-         [12] = "Gretz-Armainvilliers | Tournan",
+         [12] = "Gretz-Armainvilliers|Tournan",
          [15] =
          [15] =
-             "Courquetaine | Faremoutiers Pommeuse | Guerard La-Celle-sur-Morin | Liverdy en Brie | Marles-en-Brie | Mormant | Mortcerf | Mouroux | Ozouer le voulgis | Verneuil-l'Etang | Villepatour - Presles | Yebles - Guignes | Yebles",
+             "Courquetaine|Faremoutiers Pommeuse|Guerard La-Celle-sur-Morin|Liverdy en Brie|Marles-en-Brie|Mormant|Mortcerf|Mouroux|Ozouer le voulgis|Verneuil-l'Etang|Villepatour - Presles|Yebles - Guignes|Yebles",
          [16] =
          [16] =
-             "Chailly Boissy-le-Châtel | Chauffry | Coulommiers | Jouy-sur-Morin Le-Marais | Nangis | Saint-Remy-la-Vanne | Saint-Simeon",
+             "Chailly Boissy-le-Châtel|Chauffry|Coulommiers|Jouy-sur-Morin Le-Marais|Nangis|Saint-Remy-la-Vanne|Saint-Simeon",
          [17] =
          [17] =
-             "Champbenoist-Poigny | La Ferte-Gaucher | Longueville | Provins | Sainte-Colombe-Septveilles",
-         [18] = "Flamboin | Meilleray | Villiers St Georges"},
+             "Champbenoist-Poigny|La Ferte-Gaucher|Longueville|Provins|Sainte-Colombe-Septveilles",
+         [18] = "Flamboin|Meilleray|Villiers St Georges"},
     [22] =
     [22] =
         {[7] =
         {[7] =
-             "Allee de la Tour-Rendez-Vous | La Remise-a-Jorelle | Les Coquetiers | Les Pavillons-sous-Bois",
+             "Allee de la Tour-Rendez-Vous|La Remise-a-Jorelle|Les Coquetiers|Les Pavillons-sous-Bois",
          [8] = "Gargan",
          [8] = "Gargan",
-         [9] = "Freinville Sevran | L'Abbaye"},
+         [9] = "Freinville Sevran|L'Abbaye"},
     [23] =
     [23] =
-        {[13] = "Couilly Saint-Germain Quincy | Les Champs-Forts | Montry Conde",
-         [14] = "Crecy-en-Brie La Chapelle | Villiers-Montbarbin"},
+        {[13] = "Couilly Saint-Germain Quincy|Les Champs-Forts|Montry Conde",
+         [14] = "Crecy-en-Brie La Chapelle|Villiers-Montbarbin"},
     [26] =
     [26] =
         {[5] = "Val de Fontenay",
         {[5] = "Val de Fontenay",
-         [6] = "Bry-sur-Marne | Neuilly-Plaisance",
+         [6] = "Bry-sur-Marne|Neuilly-Plaisance",
          [7] = "Noisy-le-Grand (Mont d'Est)",
          [7] = "Noisy-le-Grand (Mont d'Est)",
          [8] = "Noisy-Champs",
          [8] = "Noisy-Champs",
-         [10] = "Lognes | Noisiel | Torcy",
+         [10] = "Lognes|Noisiel|Torcy",
          [11] = "Bussy-Saint-Georges",
          [11] = "Bussy-Saint-Georges",
          [12] = "Val d'europe",
          [12] = "Val d'europe",
          [13] = "Marne-la-Vallee Chessy"},
          [13] = "Marne-la-Vallee Chessy"},
-    [28] = {[4] = "Fontenay-aux-Roses | Robinson | Sceaux"},
+    [28] = {[4] = "Fontenay-aux-Roses|Robinson|Sceaux"},
     [30] =
     [30] =
         {[1] = "Gare Saint-Lazare",
         {[1] = "Gare Saint-Lazare",
          [3] = "Pont Cardinet",
          [3] = "Pont Cardinet",
-         [4] =
-             "Asnieres | Becon-les-Bruyeres | Clichy Levallois | Courbevoie | La Defense (Grande Arche)",
-         [5] = "Puteaux | Suresnes Mont-Valerien",
-         [7] = "Garches Marne-la-Coquette | Le Val d'Or | Saint-Cloud",
+         [4] = "Asnieres|Becon-les-Bruyeres|Clichy Levallois|Courbevoie|La Defense (Grande Arche)",
+         [5] = "Puteaux|Suresnes Mont-Valerien",
+         [7] = "Garches Marne-la-Coquette|Le Val d'Or|Saint-Cloud",
          [8] = "Vaucresson",
          [8] = "Vaucresson",
-         [9] = "Bougival | La Celle-Saint-Cloud | Louveciennes | Marly-le-Roi",
-         [10] = "L'Etang-la-Ville | Saint-Nom-la-Breteche Foret de Marly"},
+         [9] = "Bougival|La Celle-Saint-Cloud|Louveciennes|Marly-le-Roi",
+         [10] = "L'Etang-la-Ville|Saint-Nom-la-Breteche Foret de Marly"},
     [31] =
     [31] =
-        {[7] = "Chaville-Rive Droite | Sevres Ville-d'Avray | Viroflay-Rive Droite",
-         [8] = "Montreuil | Versailles-Rive Droite"},
+        {[7] = "Chaville-Rive Droite|Sevres Ville-d'Avray|Viroflay-Rive Droite",
+         [8] = "Montreuil|Versailles-Rive Droite"},
     [32] =
     [32] =
-        {[5] = "La Garenne-Colombes | Les Vallees | Nanterre-Universite",
-         [7] = "Houilles Carrieres-sur-Seine | Sartrouville",
+        {[5] = "La Garenne-Colombes|Les Vallees|Nanterre-Universite",
+         [7] = "Houilles Carrieres-sur-Seine|Sartrouville",
          [9] = "Maisons-Laffitte",
          [9] = "Maisons-Laffitte",
          [10] = "Poissy",
          [10] = "Poissy",
          [11] = "Villennes-sur-Seine",
          [11] = "Villennes-sur-Seine",
-         [12] = "Les Clairieres de Verneuil | Vernouillet Verneuil",
-         [13] = "Aubergenville-Elisabethville | Les Mureaux",
+         [12] = "Les Clairieres de Verneuil|Vernouillet Verneuil",
+         [13] = "Aubergenville-Elisabethville|Les Mureaux",
          [14] = "Epone Mezieres",
          [14] = "Epone Mezieres",
-         [16] = "Bonnieres | Mantes-Station | Mantes-la-Jolie | Port-Villez | Rosny-sur-Seine"},
+         [16] = "Bonnieres|Mantes-Station|Mantes-la-Jolie|Port-Villez|Rosny-sur-Seine"},
     [33] =
     [33] =
-        {[10] = "Acheres-Grand-Cormier | Acheres-Ville",
-         [11] = "Cergy-Prefecture | Neuville-Universite",
-         [12] = "Cergy-Saint-Christophe | Cergy-le-Haut"},
+        {[10] = "Acheres-Grand-Cormier|Acheres-Ville",
+         [11] = "Cergy-Prefecture|Neuville-Universite",
+         [12] = "Cergy-Saint-Christophe|Cergy-le-Haut"},
     [35] =
     [35] =
         {[4] = "Bois-Colombes",
         {[4] = "Bois-Colombes",
-         [5] = "Colombes | Le Stade",
-         [6] = "Argenteuil | Argenteuil",
-         [8] = "Cormeilles-en-Parisis | Val d'Argenteuil | Val d'Argenteuil",
-         [9] = "Herblay | La Frette Montigny",
-         [10] = "Conflans-Fin d'Oise | Conflans-Sainte-Honorine",
-         [11] = "Andresy | Chanteloup-les-Vignes | Maurecourt",
-         [12] = "Triel-sur-Seine | Vaux-sur-Seine",
-         [13] = "Meulan Hadricourt | Thun-le-Paradis",
-         [14] = "Gargenville | Juziers",
-         [15] = "Issou Porcheville | Limay",
-         [16] = "Breval | Menerville"},
+         [5] = "Colombes|Le Stade",
+         [6] = "Argenteuil|Argenteuil",
+         [8] = "Cormeilles-en-Parisis|Val d'Argenteuil|Val d'Argenteuil",
+         [9] = "Herblay|La Frette Montigny",
+         [10] = "Conflans-Fin d'Oise|Conflans-Sainte-Honorine",
+         [11] = "Andresy|Chanteloup-les-Vignes|Maurecourt",
+         [12] = "Triel-sur-Seine|Vaux-sur-Seine",
+         [13] = "Meulan Hadricourt|Thun-le-Paradis",
+         [14] = "Gargenville|Juziers",
+         [15] = "Issou Porcheville|Limay",
+         [16] = "Breval|Menerville"},
     [40] =
     [40] =
         {[1] = "Gare de Lyon",
         {[1] = "Gare de Lyon",
-         [5] = "Le Vert de Maisons | Maisons-Alfort Alfortville",
+         [5] = "Le Vert de Maisons|Maisons-Alfort Alfortville",
          [6] = "Villeneuve-Prairie",
          [6] = "Villeneuve-Prairie",
          [7] = "Villeneuve-Triage",
          [7] = "Villeneuve-Triage",
          [8] = "Villeneuve-Saint-Georges",
          [8] = "Villeneuve-Saint-Georges",
-         [9] = "Juvisy | Vigneux-sur-Seine",
-         [10] = "Ris-Orangis | Viry-Châtillon",
-         [11] = "Evry Val de Seine | Grand-Bourg",
-         [12] = "Corbeil-Essonnes | Mennecy | Moulin-Galant",
-         [13] = "Ballancourt | Fontenay le Vicomte",
+         [9] = "Juvisy|Vigneux-sur-Seine",
+         [10] = "Ris-Orangis|Viry-Châtillon",
+         [11] = "Evry Val de Seine|Grand-Bourg",
+         [12] = "Corbeil-Essonnes|Mennecy|Moulin-Galant",
+         [13] = "Ballancourt|Fontenay le Vicomte",
          [14] = "La Ferte-Alais",
          [14] = "La Ferte-Alais",
-         [16] = "Boutigny | Maisse",
-         [17] = "Boigneville | Buno-Gironville"},
+         [16] = "Boutigny|Maisse",
+         [17] = "Boigneville|Buno-Gironville"},
     [41] =
     [41] =
-        {[0] = "Musee d'Orsay | Saint-Michel Notre-Dame",
+        {[0] = "Musee d'Orsay|Saint-Michel Notre-Dame",
          [1] = "Gare d'Austerlitz",
          [1] = "Gare d'Austerlitz",
          [2] = "Bibliotheque-Francois Mitterrand",
          [2] = "Bibliotheque-Francois Mitterrand",
-         [4] = "Ivry-sur-Seine | Vitry-sur-Seine",
-         [5] = "Choisy-le-Roi | Les Ardoines",
+         [4] = "Ivry-sur-Seine|Vitry-sur-Seine",
+         [5] = "Choisy-le-Roi|Les Ardoines",
          [7] = "Villeneuve-le-Roi",
          [7] = "Villeneuve-le-Roi",
          [8] = "Ablon",
          [8] = "Ablon",
          [9] = "Athis-Mons"},
          [9] = "Athis-Mons"},
     [42] =
     [42] =
-        {[9] = "Epinay-sur-Orge | Savigny-sur-Orge",
+        {[9] = "Epinay-sur-Orge|Savigny-sur-Orge",
          [10] = "Sainte-Genevieve-des-Bois",
          [10] = "Sainte-Genevieve-des-Bois",
          [11] = "Saint-Michel-sur-Orge",
          [11] = "Saint-Michel-sur-Orge",
-         [12] = "Bretigny-sur-Orge | Marolles-en-Hurepoix",
-         [13] = "Bouray | Lardy",
-         [14] = "Chamarande | Etampes | Etrechy",
+         [12] = "Bretigny-sur-Orge|Marolles-en-Hurepoix",
+         [13] = "Bouray|Lardy",
+         [14] = "Chamarande|Etampes|Etrechy",
          [16] = "Saint-Martin d'Etampes",
          [16] = "Saint-Martin d'Etampes",
          [17] = "Guillerval"},
          [17] = "Guillerval"},
     [43] =
     [43] =
-        {[9] = "Montgeron Crosne | Yerres",
+        {[9] = "Montgeron Crosne|Yerres",
          [10] = "Brunoy",
          [10] = "Brunoy",
-         [11] = "Boussy-Saint-Antoine | Combs-la-Ville Quincy",
+         [11] = "Boussy-Saint-Antoine|Combs-la-Ville Quincy",
          [12] = "Lieusaint Moissy",
          [12] = "Lieusaint Moissy",
-         [13] = "Cesson | Savigny-le-Temple Nandy",
-         [15] = "Le Mee | Melun",
-         [16] = "Chartrettes | Fontaine-le-Port | Livry-sur-Seine",
+         [13] = "Cesson|Savigny-le-Temple Nandy",
+         [15] = "Le Mee|Melun",
+         [16] = "Chartrettes|Fontaine-le-Port|Livry-sur-Seine",
          [17] =
          [17] =
-             "Champagne-sur-Seine | Hericy | La Grande Paroisse | Vernou-sur-Seine | Vulaines-sur-Seine Samoreau"},
+             "Champagne-sur-Seine|Hericy|La Grande Paroisse|Vernou-sur-Seine|Vulaines-sur-Seine Samoreau"},
     [44] =
     [44] =
-        {[12] = "Essonnes-Robinson | Villabe",
-         [13] = "Coudray-Montceaux | Le Plessis-Chenet-IBM | Saint-Fargeau",
-         [14] = "Boissise-le-Roi | Ponthierry Pringy",
+        {[12] = "Essonnes-Robinson|Villabe",
+         [13] = "Coudray-Montceaux|Le Plessis-Chenet-IBM|Saint-Fargeau",
+         [14] = "Boissise-le-Roi|Ponthierry Pringy",
          [15] = "Vosves",
          [15] = "Vosves",
          [16] = "Bois-le-Roi",
          [16] = "Bois-le-Roi",
          [17] =
          [17] =
-             "Bagneaux-sur-Loing | Bourron-Marlotte Grez | Fontainebleau-Avon | Montereau | Montigny-sur-Loing | Moret Veneux-les-Sablons | Nemours Saint-Pierre | Saint-Mammes | Souppes | Thomery"},
+             "Bagneaux-sur-Loing|Bourron-Marlotte Grez|Fontainebleau-Avon|Montereau|Montigny-sur-Loing|Moret Veneux-les-Sablons|Nemours Saint-Pierre|Saint-Mammes|Souppes|Thomery"},
     [45] =
     [45] =
         {[10] = "Grigny-Centre",
         {[10] = "Grigny-Centre",
-         [11] = "Evry Courcouronnes | Orangis Bois de l'Epine",
+         [11] = "Evry Courcouronnes|Orangis Bois de l'Epine",
          [12] = "Le Bras-de-Fer - Evry Genopole"},
          [12] = "Le Bras-de-Fer - Evry Genopole"},
     [50] =
     [50] =
         {[0] = "Haussmann-Saint-Lazare",
         {[0] = "Haussmann-Saint-Lazare",
-         [1] = "Gare du Nord | Magenta | Paris-Nord",
-         [5] = "Epinay-Villetaneuse | Saint-Denis | Sevres-Rive Gauche",
+         [1] = "Gare du Nord|Magenta|Paris-Nord",
+         [5] = "Epinay-Villetaneuse|Saint-Denis|Sevres-Rive Gauche",
          [6] = "La Barre-Ormesson",
          [6] = "La Barre-Ormesson",
-         [7] = "Champ de Courses d'Enghien | Enghien-les-Bains",
-         [8] = "Ermont-Eaubonne | Ermont-Halte | Gros-Noyer Saint-Prix",
-         [9] = "Saint-Leu-La-Foret | Taverny | Vaucelles",
-         [10] = "Bessancourt | Frepillon | Mery",
-         [11] = "Meriel | Valmondois",
-         [12] = "Bruyeres-sur-Oise | Champagne-sur-Oise | L'Isle-Adam Parmain | Persan Beaumont"},
+         [7] = "Champ de Courses d'Enghien|Enghien-les-Bains",
+         [8] = "Ermont-Eaubonne|Ermont-Halte|Gros-Noyer Saint-Prix",
+         [9] = "Saint-Leu-La-Foret|Taverny|Vaucelles",
+         [10] = "Bessancourt|Frepillon|Mery",
+         [11] = "Meriel|Valmondois",
+         [12] = "Bruyeres-sur-Oise|Champagne-sur-Oise|L'Isle-Adam Parmain|Persan Beaumont"},
     [51] =
     [51] =
-        {[4] = "La Courneuve-Aubervilliers | La Plaine-Stade de France",
+        {[4] = "La Courneuve-Aubervilliers|La Plaine-Stade de France",
          [5] = "Le Bourget",
          [5] = "Le Bourget",
-         [7] = "Blanc-Mesnil | Drancy",
+         [7] = "Blanc-Mesnil|Drancy",
          [8] = "Aulnay-sous-Bois",
          [8] = "Aulnay-sous-Bois",
-         [9] = "Sevran Livry | Vert-Galant",
+         [9] = "Sevran Livry|Vert-Galant",
          [10] = "Villeparisis",
          [10] = "Villeparisis",
-         [11] = "Compans | Mitry-Claye",
-         [12] = "Dammartin Juilly Saint-Mard | Thieux Nantouillet"},
+         [11] = "Compans|Mitry-Claye",
+         [12] = "Dammartin Juilly Saint-Mard|Thieux Nantouillet"},
     [52] =
     [52] =
         {[5] = "Stade de France-Saint-Denis",
         {[5] = "Stade de France-Saint-Denis",
          [6] = "Pierrefitte Stains",
          [6] = "Pierrefitte Stains",
          [7] = "Garges-Sarcelles",
          [7] = "Garges-Sarcelles",
          [8] = "Villiers-le-Bel (Gonesse - Arnouville)",
          [8] = "Villiers-le-Bel (Gonesse - Arnouville)",
-         [10] = "Goussainville | Les Noues | Louvres",
-         [11] = "La Borne-Blanche | Survilliers-Fosses"},
+         [10] = "Goussainville|Les Noues|Louvres",
+         [11] = "La Borne-Blanche|Survilliers-Fosses"},
     [53] =
     [53] =
         {[6] = "Deuil Montmagny",
         {[6] = "Deuil Montmagny",
          [7] = "Groslay",
          [7] = "Groslay",
          [8] = "Sarcelles Saint-Brice",
          [8] = "Sarcelles Saint-Brice",
-         [9] = "Domont | Ecouen Ezanville",
-         [10] = "Bouffemont Moisselles | Montsoult Maffliers",
-         [11] = "Belloy-Saint-Martin | Luzarches | Seugy | Viarmes | Villaines"},
+         [9] = "Domont|Ecouen Ezanville",
+         [10] = "Bouffemont Moisselles|Montsoult Maffliers",
+         [11] = "Belloy-Saint-Martin|Luzarches|Seugy|Viarmes|Villaines"},
     [54] =
     [54] =
         {[8] = "Cernay",
         {[8] = "Cernay",
-         [9] = "Franconville Plessis-Bouchard | Montigny-Beauchamp",
+         [9] = "Franconville Plessis-Bouchard|Montigny-Beauchamp",
          [10] = "Pierrelaye",
          [10] = "Pierrelaye",
-         [11] = "Pontoise | Saint-Ouen-l'Aumone-Liesse",
-         [12] = "Boissy-l'Aillerie | Osny",
-         [15] = "Chars | Montgeroult Courcelles | Santeuil Le Perchay | Us"},
+         [11] = "Pontoise|Saint-Ouen-l'Aumone-Liesse",
+         [12] = "Boissy-l'Aillerie|Osny",
+         [15] = "Chars|Montgeroult Courcelles|Santeuil Le Perchay|Us"},
     [55] =
     [55] =
         {[0] =
         {[0] =
-             "Avenue Foch | Avenue Henri-Martin | Boulainvilliers | Kennedy Radio-France | Neuilly-Porte Maillot (Palais des congres)",
+             "Avenue Foch|Avenue Henri-Martin|Boulainvilliers|Kennedy Radio-France|Neuilly-Porte Maillot (Palais des congres)",
          [1] = "Pereire-Levallois",
          [1] = "Pereire-Levallois",
          [2] = "Porte de Clichy",
          [2] = "Porte de Clichy",
          [3] = "Saint-Ouen",
          [3] = "Saint-Ouen",
@@ -614,58 +613,58 @@ static const char* NAVIGO_SNCF_LOCATION_LIST[77][19] = {
          [5] = "Gennevilliers",
          [5] = "Gennevilliers",
          [6] = "Epinay-sur-Seine",
          [6] = "Epinay-sur-Seine",
          [7] = "Saint-Gratien"},
          [7] = "Saint-Gratien"},
-    [56] = {[11] = "Auvers-sur-Oise | Chaponval | Epluches | Pont Petit"},
+    [56] = {[11] = "Auvers-sur-Oise|Chaponval|Epluches|Pont Petit"},
     [57] = {[11] = "Presles Courcelles", [12] = "Nointel Mours"},
     [57] = {[11] = "Presles Courcelles", [12] = "Nointel Mours"},
     [60] =
     [60] =
         {[1] = "Gare Montparnasse",
         {[1] = "Gare Montparnasse",
-         [4] = "Clamart | Vanves Malakoff",
-         [5] = "Bellevue | Bievres | Meudon",
-         [6] = "Chaville-Rive Gauche | Chaville-Velizy | Viroflay-Rive Gauche",
+         [4] = "Clamart|Vanves Malakoff",
+         [5] = "Bellevue|Bievres|Meudon",
+         [6] = "Chaville-Rive Gauche|Chaville-Velizy|Viroflay-Rive Gauche",
          [7] = "Versailles-Chantiers",
          [7] = "Versailles-Chantiers",
          [10] = "Saint-Cyr",
          [10] = "Saint-Cyr",
-         [11] = "Saint-Quentin-en-Yvelines - Montigny le Bretonneux | Trappes",
-         [12] = "Coignieres | La Verriere",
+         [11] = "Saint-Quentin-en-Yvelines - Montigny le Bretonneux|Trappes",
+         [12] = "Coignieres|La Verriere",
          [13] = "Les Essarts-le-Roi",
          [13] = "Les Essarts-le-Roi",
-         [14] = "Le Perray | Rambouillet",
+         [14] = "Le Perray|Rambouillet",
          [15] = "Gazeran"},
          [15] = "Gazeran"},
     [61] =
     [61] =
         {[10] = "Fontenay-le-Fleury",
         {[10] = "Fontenay-le-Fleury",
          [11] = "Villepreux Les-Clayes",
          [11] = "Villepreux Les-Clayes",
-         [12] = "Plaisir Grignon | Plaisir Les-Clayes",
-         [13] = "Beynes | Mareil-sur-Mauldre | Maule | Nezel Aulnay",
+         [12] = "Plaisir Grignon|Plaisir Les-Clayes",
+         [13] = "Beynes|Mareil-sur-Mauldre|Maule|Nezel Aulnay",
          [15] =
          [15] =
-             "Garancieres La-Queue | Montfort-l'Amaury Mere | Orgerus Behoust | Tacoigneres Richebourg | Villiers Neauphle Pontchartrain",
+             "Garancieres La-Queue|Montfort-l'Amaury Mere|Orgerus Behoust|Tacoigneres Richebourg|Villiers Neauphle Pontchartrain",
          [16] = "Houdan"},
          [16] = "Houdan"},
-    [63] = {[7] = "Porchefontaine | Versailles-Rive Gauche"},
+    [63] = {[7] = "Porchefontaine|Versailles-Rive Gauche"},
     [64] =
     [64] =
-        {[0] = "Invalides | Pont de l'alma",
+        {[0] = "Invalides|Pont de l'alma",
          [1] = "Champ de Mars-Tour Eiffel",
          [1] = "Champ de Mars-Tour Eiffel",
          [2] = "Javel",
          [2] = "Javel",
-         [3] = "Boulevard Victor - Pont du Garigliano | Issy-Val de Seine | Issy",
+         [3] = "Boulevard Victor - Pont du Garigliano|Issy-Val de Seine|Issy",
          [5] = "Meudon-Val-Fleury"},
          [5] = "Meudon-Val-Fleury"},
     [65] =
     [65] =
-        {[8] = "Jouy-en-Josas | Petit-Jouy-les-Loges",
+        {[8] = "Jouy-en-Josas|Petit-Jouy-les-Loges",
          [9] = "Vauboyen",
          [9] = "Vauboyen",
          [10] = "Igny",
          [10] = "Igny",
          [11] = "Massy-Palaiseau",
          [11] = "Massy-Palaiseau",
          [12] = "Longjumeau",
          [12] = "Longjumeau",
          [13] = "Chilly-Mazarin",
          [13] = "Chilly-Mazarin",
-         [14] = "Gravigny-Balizy | Petit-Vaux"},
+         [14] = "Gravigny-Balizy|Petit-Vaux"},
     [70] =
     [70] =
-        {[9] = "Parc des Expositions | Sevran-Beaudottes | Villepinte",
+        {[9] = "Parc des Expositions|Sevran-Beaudottes|Villepinte",
          [10] = "Aeroport Charles de Gaulle"},
          [10] = "Aeroport Charles de Gaulle"},
     [72] = {[7] = "Sannois"},
     [72] = {[7] = "Sannois"},
-    [73] = {[11] = "Eragny Neuville | Saint-Ouen-l'Aumone (Eglise)"},
+    [73] = {[11] = "Eragny Neuville|Saint-Ouen-l'Aumone (Eglise)"},
     [75] =
     [75] =
-        {[7] = "Les Saules | Orly-Ville",
-         [9] = "Pont de Rungis Aeroport d'Orly | Rungis-La Fraternelle",
+        {[7] = "Les Saules|Orly-Ville",
+         [9] = "Pont de Rungis Aeroport d'Orly|Rungis-La Fraternelle",
          [10] = "Chemin d'Antony",
          [10] = "Chemin d'Antony",
-         [12] = "Massy-Verrieres | Arpajon"},
+         [12] = "Massy-Verrieres|Arpajon"},
     [76] =
     [76] =
-        {[12] = "Egly | La Norville Saint-Germain-les-Arpajon",
-         [13] = "Breuillet Bruyeres-le-Châtel | Breuillet-Village | Saint-Cheron",
+        {[12] = "Egly|La Norville Saint-Germain-les-Arpajon",
+         [13] = "Breuillet Bruyeres-le-Châtel|Breuillet-Village|Saint-Cheron",
          [14] = "Sermaise",
          [14] = "Sermaise",
-         [15] = "Dourdan | Dourdan-la-Foret"},
+         [15] = "Dourdan|Dourdan-la-Foret"},
 };
 };
 
 
 #endif
 #endif

+ 3 - 0
scenes/metroflip_scene_calypso.c

@@ -927,6 +927,7 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
                                 bit_slice_to_dec(event_bit_representation, start, end);
                                 bit_slice_to_dec(event_bit_representation, start, end);
                             card->navigo->events[i - 1].station_group_id = decimal_value >> 9;
                             card->navigo->events[i - 1].station_group_id = decimal_value >> 9;
                             card->navigo->events[i - 1].station_id = (decimal_value >> 4) & 31;
                             card->navigo->events[i - 1].station_id = (decimal_value >> 4) & 31;
+                            card->navigo->events[i - 1].station_sub_id = decimal_value & 15;
                         }
                         }
 
 
                         // 9. EventLocationGate
                         // 9. EventLocationGate
@@ -1153,6 +1154,8 @@ static NfcCommand metroflip_scene_navigo_poller_callback(NfcGenericEvent event,
                                                                                    9;
                                                                                    9;
                             card->navigo->special_events[i - 1].station_id = (decimal_value >> 4) &
                             card->navigo->special_events[i - 1].station_id = (decimal_value >> 4) &
                                                                              31;
                                                                              31;
+                            card->navigo->special_events[i - 1].station_sub_id = decimal_value &
+                                                                                 15;
                         }
                         }
 
 
                         // 10. EventDevice
                         // 10. EventDevice