diff --git a/src/descriptor.c b/src/descriptor.c index 7a824dc..6a83f28 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -471,10 +471,11 @@ static const dc_descriptor_t g_descriptors[] = { // Not merged upstream yet /* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */ - /* for the Mk1 we are using the model of the global model - the APAC model is 2991 */ - /* for the Mk2 we are using the model of the global model - the APAC model is 3702 */ + /* for the Mk1 we are using the model of the global model */ + /* for the Mk2/Mk3 we are using the model of the Mk2 global model */ + /* see garmin_parser.c for a more comprehensive list of models */ {"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin}, - {"Garmin", "Descent Mk2/Mk2i", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin}, + {"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin}, {"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL }, }; diff --git a/src/garmin.c b/src/garmin.c index f51e19a..16c7464 100644 --- a/src/garmin.c +++ b/src/garmin.c @@ -101,7 +101,6 @@ garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *ios // in order to have only one entry for the Mk2, we don't use the Mk2/APAC model number in our code device->use_mtp = (model == (0x0FFF & DESCENT_MK2)); device->mtp_device = NULL; - DEBUG(context, "Found Garmin with model 0x%x which is a %s\n", model, (device->use_mtp ? "Mk2/Mk2i" : "Mk1")); #endif *out = (dc_device_t *) device; @@ -331,12 +330,16 @@ mtp_get_file_list(dc_device_t *abstract, struct file_list *files) for (i = 0; i < numrawdevices; i++) { LIBMTP_devicestorage_t *storage; // we only want to read from a Garmin Descent Mk2 device at this point - if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR || - (rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC)) { + if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR) { DEBUG(abstract->context, "Garmin/mtp: skipping raw device %04x/%04x", rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id); continue; } + if (rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC) { + DEBUG(abstract->context, "Garmin/mtp: skipping Garmin raw device %04x/%04x, as it is not a dive computer / does not support MTP", + rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id); + continue; + } device->mtp_device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]); if (device->mtp_device == NULL) { DEBUG(abstract->context, "Garmin/mtp: unable to open raw device %d", i); diff --git a/src/garmin_parser.c b/src/garmin_parser.c index c2be625..543346b 100644 --- a/src/garmin_parser.c +++ b/src/garmin_parser.c @@ -129,7 +129,7 @@ typedef struct garmin_parser_t { unsigned int setpoint_low_cbar, setpoint_high_cbar; unsigned int setpoint_low_switch_depth_mm, setpoint_high_switch_depth_mm; unsigned int setpoint_low_switch_mode, setpoint_high_switch_mode; - dc_gasmix_t *current_gasmix; + dc_usage_t current_gasmix_usage; } dive; // I count nine (!) different GPS fields Hmm. @@ -239,11 +239,11 @@ static void garmin_event(struct garmin_parser_t *garmin, sample.gasmix = data; garmin->callback(DC_SAMPLE_GASMIX, &sample, garmin->userdata); - dc_gasmix_t *gasmix = &garmin->cache.GASMIX[data]; - if (!garmin->dive.current_gasmix || gasmix->usage != garmin->dive.current_gasmix->usage) { + dc_usage_t gasmix_usage = garmin->cache.GASMIX[data].usage; + if (gasmix_usage != garmin->dive.current_gasmix_usage) { dc_sample_value_t sample2 = {0}; sample2.event.type = SAMPLE_EVENT_STRING; - if (gasmix->usage == DC_USAGE_DILUENT) { + if (gasmix_usage == DC_USAGE_DILUENT) { sample2.event.name = "Switched to closed circuit"; } else { sample2.event.name = "Switched to open circuit bailout"; @@ -252,7 +252,7 @@ static void garmin_event(struct garmin_parser_t *garmin, garmin->callback(DC_SAMPLE_EVENT, &sample2, garmin->userdata); - garmin->dive.current_gasmix = gasmix; + garmin->dive.current_gasmix_usage = gasmix_usage; } return; @@ -486,19 +486,22 @@ DECLARE_FIELD(ANY, timestamp, UINT32) { garmin->record_data.timestamp = data; if (garmin->callback) { - dc_sample_value_t sample = {0}; - // Turn the timestamp relative to the beginning of the dive - if (data < garmin->dive.time) + if (data < garmin->dive.time) { + DEBUG(garmin->base.context, "Timestamp before dive start: %d (dive start: %d)", data, garmin->dive.time); + return; - data -= garmin->dive.time; + } + data -= garmin->dive.time - 1; // Did we already do this? - if (data < garmin->record_data.time) + if (data == garmin->record_data.time) return; + garmin->record_data.time = data; + // Now we're ready to actually update the sample times - garmin->record_data.time = data+1; + dc_sample_value_t sample = {0}; sample.time = data * 1000; garmin->callback(DC_SAMPLE_TIME, &sample, garmin->userdata); } @@ -656,6 +659,7 @@ DECLARE_FIELD(ACTIVITY, event_group, UINT8) { } // SPORT DECLARE_FIELD(SPORT, sub_sport, ENUM) { garmin->dive.sub_sport = (ENUM) data; + garmin->dive.current_gasmix_usage = DC_USAGE_OPEN_CIRCUIT; dc_divemode_t val; switch (data) { case 55: val = DC_DIVEMODE_GAUGE; @@ -663,7 +667,10 @@ DECLARE_FIELD(SPORT, sub_sport, ENUM) { case 56: case 57: val = DC_DIVEMODE_FREEDIVE; break; - case 63: val = DC_DIVEMODE_CCR; + case 63: + val = DC_DIVEMODE_CCR; + garmin->dive.current_gasmix_usage = DC_USAGE_DILUENT; + break; default: val = DC_DIVEMODE_OC; } @@ -797,7 +804,7 @@ DECLARE_FIELD(SENSOR_PROFILE, enabled, ENUM) { current_sensor(garmin)->sensor_enabled = data; } -DECLARE_FIELD(SENSOR_PROFILE, sensor_type, UINT8) +DECLARE_FIELD(SENSOR_PROFILE, sensor_type, ENUM) { // 28 is tank pod // start filling in next sensor after this record @@ -1090,7 +1097,7 @@ DECLARE_MESG(SENSOR_PROFILE) = { SET_FIELD(SENSOR_PROFILE, 0, ant_channel_id, UINT32Z), // derived from the number engraved on the side SET_FIELD(SENSOR_PROFILE, 2, name, STRING), SET_FIELD(SENSOR_PROFILE, 3, enabled, ENUM), - SET_FIELD(SENSOR_PROFILE, 52, sensor_type, UINT8), // 28 is tank pod + SET_FIELD(SENSOR_PROFILE, 52, sensor_type, ENUM), // 28 is tank pod SET_FIELD(SENSOR_PROFILE, 74, pressure_units, ENUM), // 0 is PSI, 1 is KPA (unused), 2 is Bar SET_FIELD(SENSOR_PROFILE, 75, rated_pressure, UINT16), SET_FIELD(SENSOR_PROFILE, 76, reserve_pressure, UINT16), @@ -1337,7 +1344,10 @@ static int traverse_regular(struct garmin_parser_t *garmin, } if (field_desc) { - field_desc->parse(garmin, base_type, data); + if (field_nr == 253 && !msg_desc->maxfield) + DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message."); + else + field_desc->parse(garmin, base_type, data); } else { unknown_field(garmin, data, msg_name, field_nr, base_type, len); } @@ -1521,7 +1531,12 @@ traverse_data(struct garmin_parser_t *garmin) // Compressed records are like normal records // with that added relative timestamp DEBUG(garmin->base.context, "Compressed record for type %d", type); - parse_ANY_timestamp(garmin, time); + + if (!(garmin->type_desc + type)->msg_desc->maxfield) + DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message."); + else + parse_ANY_timestamp(garmin, time); + len = traverse_regular(garmin, data, datasize, type, &time); } else if (record & 0x40) { // Definition record? len = traverse_definition(garmin, data, datasize, record); @@ -1615,6 +1630,20 @@ static void add_sensor_string(garmin_parser_t *garmin, const char *desc, const s static dc_status_t garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsigned int size) { + // This list is empirical and somewhat speculative + // will have to be confirmed with Garmin + static const struct { + int id; + const char *name; + } models[] = { + { 2859, "Descent Mk1" }, + { 2991, "Descent Mk1 APAC" }, + { 3258, "Descent Mk2(i)" }, + { 3542, "Descent Mk2s" }, + { 3702, "Descent Mk2 APAC" }, + { 4223, "Descent Mk3" }, + }; + /* Walk the data once without a callback to set up the core fields */ garmin->callback = NULL; garmin->userdata = NULL; @@ -1630,6 +1659,17 @@ garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsi if (garmin->dive.firmware) dc_field_add_string_fmt(&garmin->cache, "Firmware", "%u.%02u", garmin->dive.firmware / 100, garmin->dive.firmware % 100); + if (garmin->dive.product) { + int i = 0; + for (i = 0; i < C_ARRAY_SIZE(models); i++) + if (models[i].id == garmin->dive.product) + break; + + if (i < C_ARRAY_SIZE(models)) + dc_field_add_string_fmt(&garmin->cache, "Model", "%s", models[i].name); + else + dc_field_add_string_fmt(&garmin->cache, "Model", "Unknown model ID: %u", garmin->dive.product); + } // These seem to be the "real" GPS dive coordinates add_gps_string(garmin, "GPS1", &garmin->gps.SESSION.entry);