From 0ebd5d3879854206cd1cf0272e6c357004b33727 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 29 Sep 2020 16:54:48 -0700 Subject: [PATCH] Garmin Descent: clear dive data in between dives This actually got broken long ago (and before the new "Subsurface-DS9" branch: when I converted the Garmin parser to use the generic field cache, I missed the fact that the parser now cleared _only_ that generic part of the per-dive cache in between different dives. The GPS information, and the general dive information would be left alone in between dives, and could leak from one dive to the next. Most of the time you don't notice, because dives tend to all have the same information, so the stale data would get overwritten when parsing the next dive. But that isn't _always_ true - particularly for the GPS information, not all the data necessarily always exists. So clear all the per-dive data when starting to parse a new dive. This puts the non-gps data all in one sub-structure, so that it's easy to clear that too in one go - even though that part of the data probably always does get opverwritten by the new dive data. Reported-by: @brysconsulting Signed-off-by: Linus Torvalds --- src/garmin_parser.c | 55 ++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/garmin_parser.c b/src/garmin_parser.c index 5ebbe6a..2e649b4 100644 --- a/src/garmin_parser.c +++ b/src/garmin_parser.c @@ -97,15 +97,16 @@ typedef struct garmin_parser_t { struct type_desc type_desc[MAXTYPE]; // Field cache - unsigned int initialized; - unsigned int sub_sport; - unsigned int serial; - unsigned int product; - unsigned int firmware; - unsigned int protocol; - unsigned int profile; - unsigned int time; - int utc_offset, time_offset; + struct { + unsigned int sub_sport; + unsigned int serial; + unsigned int product; + unsigned int firmware; + unsigned int protocol; + unsigned int profile; + unsigned int time; + int utc_offset, time_offset; + } dive; // I count nine (!) different GPS fields Hmm. // Reporting all of them just to try to figure @@ -214,9 +215,9 @@ static void flush_pending_record(struct garmin_parser_t *garmin) } } if (pending & RECORD_DEVICE_INFO && record->device_index == 0) { - garmin->firmware = record->firmware; - garmin->serial = record->serial; - garmin->product = record->product; + garmin->dive.firmware = record->firmware; + garmin->dive.serial = record->serial; + garmin->dive.product = record->product; } if (pending & RECORD_DECO_MODEL) dc_field_add_string_fmt(&garmin->cache, "Deco model", "Buhlmann ZHL-16C %u/%u", record->gf_low, record->gf_high); @@ -358,9 +359,9 @@ DECLARE_FIELD(ANY, timestamp, UINT32) dc_sample_value_t sample = {0}; // Turn the timestamp relative to the beginning of the dive - if (data < garmin->time) + if (data < garmin->dive.time) return; - data -= garmin->time; + data -= garmin->dive.time; // Did we already do this? if (data < garmin->record_data.time) @@ -385,7 +386,7 @@ DECLARE_FIELD(FILE, number, UINT16) { } DECLARE_FIELD(FILE, other_time, UINT32) { } // SESSION msg -DECLARE_FIELD(SESSION, start_time, UINT32) { garmin->time = data; } +DECLARE_FIELD(SESSION, start_time, UINT32) { garmin->dive.time = data; } DECLARE_FIELD(SESSION, start_pos_lat, SINT32) { garmin->gps.SESSION.entry.lat = data; } DECLARE_FIELD(SESSION, start_pos_long, SINT32) { garmin->gps.SESSION.entry.lon = data; } DECLARE_FIELD(SESSION, nec_pos_lat, SINT32) { garmin->gps.SESSION.NE.lat = data; } @@ -474,8 +475,8 @@ DECLARE_FIELD(RECORD, cns_load, UINT8) DECLARE_FIELD(RECORD, n2_load, UINT16) { } // percent // DEVICE_SETTINGS -DECLARE_FIELD(DEVICE_SETTINGS, utc_offset, UINT32) { garmin->utc_offset = (SINT32) data; } // wrong type in FIT -DECLARE_FIELD(DEVICE_SETTINGS, time_offset, UINT32) { garmin->time_offset = (SINT32) data; } // wrong type in FIT +DECLARE_FIELD(DEVICE_SETTINGS, utc_offset, UINT32) { garmin->dive.utc_offset = (SINT32) data; } // wrong type in FIT +DECLARE_FIELD(DEVICE_SETTINGS, time_offset, UINT32) { garmin->dive.time_offset = (SINT32) data; } // wrong type in FIT // DEVICE_INFO // collect the data and then use the record if it is for device_index 0 @@ -501,7 +502,7 @@ DECLARE_FIELD(DEVICE_INFO, firmware, UINT16) } // SPORT -DECLARE_FIELD(SPORT, sub_sport, ENUM) { garmin->sub_sport = (ENUM) data; } +DECLARE_FIELD(SPORT, sub_sport, ENUM) { garmin->dive.sub_sport = (ENUM) data; } // DIVE_GAS - uses msg index DECLARE_FIELD(DIVE_GAS, helium, UINT8) @@ -1102,8 +1103,8 @@ traverse_data(struct garmin_parser_t *garmin) if (hdrsize < 12 || datasize > len || datasize + hdrsize + 2 > len) return DC_STATUS_IO; - garmin->protocol = protocol; - garmin->profile = profile; + garmin->dive.protocol = protocol; + garmin->dive.profile = profile; data += hdrsize; time = 0; @@ -1188,11 +1189,11 @@ garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigne garmin_parser_t *garmin = (garmin_parser_t *) abstract; if (devinfo_p) { - devinfo_p->firmware = garmin->firmware; - devinfo_p->serial = garmin->serial; - devinfo_p->model = garmin->product; + devinfo_p->firmware = garmin->dive.firmware; + devinfo_p->serial = garmin->dive.serial; + devinfo_p->model = garmin->dive.product; } - switch (garmin->sub_sport) { + switch (garmin->dive.sub_sport) { case 53: // Single-gas case 54: // Multi-gas case 55: // Gauge @@ -1218,6 +1219,8 @@ garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsign /* Walk the data once without a callback to set up the core fields */ garmin->callback = NULL; garmin->userdata = NULL; + memset(&garmin->gps, 0, sizeof(garmin->gps)); + memset(&garmin->dive, 0, sizeof(garmin->dive)); memset(&garmin->cache, 0, sizeof(garmin->cache)); traverse_data(garmin); @@ -1243,10 +1246,10 @@ static dc_status_t garmin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { garmin_parser_t *garmin = (garmin_parser_t *) abstract; - dc_ticks_t time = 631065600 + (dc_ticks_t) garmin->time; + dc_ticks_t time = 631065600 + (dc_ticks_t) garmin->dive.time; // Show local time (time_offset) - dc_datetime_gmtime(datetime, time + garmin->time_offset); + dc_datetime_gmtime(datetime, time + garmin->dive.time_offset); datetime->timezone = DC_TIMEZONE_NONE; return DC_STATUS_SUCCESS;