Skip to content

Commit ca55a11

Browse files
authored
Merge pull request #58 from mikeller/add_garmin_descent_mk3_support
Merging this - there is demand for this fix, so now is a good time to get it tested: https://groups.google.com/g/subsurface-divelog/c/7Uo7A9YTGhg/m/BlhlZ2NNBQAJ
2 parents 62a29ee + bb502c6 commit ca55a11

File tree

3 files changed

+66
-22
lines changed

3 files changed

+66
-22
lines changed

src/descriptor.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,10 +471,11 @@ static const dc_descriptor_t g_descriptors[] = {
471471

472472
// Not merged upstream yet
473473
/* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */
474-
/* for the Mk1 we are using the model of the global model - the APAC model is 2991 */
475-
/* for the Mk2 we are using the model of the global model - the APAC model is 3702 */
474+
/* for the Mk1 we are using the model of the global model */
475+
/* for the Mk2/Mk3 we are using the model of the Mk2 global model */
476+
/* see garmin_parser.c for a more comprehensive list of models */
476477
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
477-
{"Garmin", "Descent Mk2/Mk2i", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
478+
{"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
478479
{"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL },
479480
};
480481

src/garmin.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *ios
101101
// in order to have only one entry for the Mk2, we don't use the Mk2/APAC model number in our code
102102
device->use_mtp = (model == (0x0FFF & DESCENT_MK2));
103103
device->mtp_device = NULL;
104-
DEBUG(context, "Found Garmin with model 0x%x which is a %s\n", model, (device->use_mtp ? "Mk2/Mk2i" : "Mk1"));
105104
#endif
106105

107106
*out = (dc_device_t *) device;
@@ -331,12 +330,16 @@ mtp_get_file_list(dc_device_t *abstract, struct file_list *files)
331330
for (i = 0; i < numrawdevices; i++) {
332331
LIBMTP_devicestorage_t *storage;
333332
// we only want to read from a Garmin Descent Mk2 device at this point
334-
if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR ||
335-
(rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC)) {
333+
if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR) {
336334
DEBUG(abstract->context, "Garmin/mtp: skipping raw device %04x/%04x",
337335
rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id);
338336
continue;
339337
}
338+
if (rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC) {
339+
DEBUG(abstract->context, "Garmin/mtp: skipping Garmin raw device %04x/%04x, as it is not a dive computer / does not support MTP",
340+
rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id);
341+
continue;
342+
}
340343
device->mtp_device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]);
341344
if (device->mtp_device == NULL) {
342345
DEBUG(abstract->context, "Garmin/mtp: unable to open raw device %d", i);

src/garmin_parser.c

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ typedef struct garmin_parser_t {
129129
unsigned int setpoint_low_cbar, setpoint_high_cbar;
130130
unsigned int setpoint_low_switch_depth_mm, setpoint_high_switch_depth_mm;
131131
unsigned int setpoint_low_switch_mode, setpoint_high_switch_mode;
132-
dc_gasmix_t *current_gasmix;
132+
dc_usage_t current_gasmix_usage;
133133
} dive;
134134

135135
// I count nine (!) different GPS fields Hmm.
@@ -239,11 +239,11 @@ static void garmin_event(struct garmin_parser_t *garmin,
239239
sample.gasmix = data;
240240
garmin->callback(DC_SAMPLE_GASMIX, &sample, garmin->userdata);
241241

242-
dc_gasmix_t *gasmix = &garmin->cache.GASMIX[data];
243-
if (!garmin->dive.current_gasmix || gasmix->usage != garmin->dive.current_gasmix->usage) {
242+
dc_usage_t gasmix_usage = garmin->cache.GASMIX[data].usage;
243+
if (gasmix_usage != garmin->dive.current_gasmix_usage) {
244244
dc_sample_value_t sample2 = {0};
245245
sample2.event.type = SAMPLE_EVENT_STRING;
246-
if (gasmix->usage == DC_USAGE_DILUENT) {
246+
if (gasmix_usage == DC_USAGE_DILUENT) {
247247
sample2.event.name = "Switched to closed circuit";
248248
} else {
249249
sample2.event.name = "Switched to open circuit bailout";
@@ -252,7 +252,7 @@ static void garmin_event(struct garmin_parser_t *garmin,
252252

253253
garmin->callback(DC_SAMPLE_EVENT, &sample2, garmin->userdata);
254254

255-
garmin->dive.current_gasmix = gasmix;
255+
garmin->dive.current_gasmix_usage = gasmix_usage;
256256
}
257257

258258
return;
@@ -486,19 +486,22 @@ DECLARE_FIELD(ANY, timestamp, UINT32)
486486
{
487487
garmin->record_data.timestamp = data;
488488
if (garmin->callback) {
489-
dc_sample_value_t sample = {0};
490-
491489
// Turn the timestamp relative to the beginning of the dive
492-
if (data < garmin->dive.time)
490+
if (data < garmin->dive.time) {
491+
DEBUG(garmin->base.context, "Timestamp before dive start: %d (dive start: %d)", data, garmin->dive.time);
492+
493493
return;
494-
data -= garmin->dive.time;
494+
}
495+
data -= garmin->dive.time - 1;
495496

496497
// Did we already do this?
497-
if (data < garmin->record_data.time)
498+
if (data == garmin->record_data.time)
498499
return;
499500

501+
garmin->record_data.time = data;
502+
500503
// Now we're ready to actually update the sample times
501-
garmin->record_data.time = data+1;
504+
dc_sample_value_t sample = {0};
502505
sample.time = data * 1000;
503506
garmin->callback(DC_SAMPLE_TIME, &sample, garmin->userdata);
504507
}
@@ -656,14 +659,18 @@ DECLARE_FIELD(ACTIVITY, event_group, UINT8) { }
656659
// SPORT
657660
DECLARE_FIELD(SPORT, sub_sport, ENUM) {
658661
garmin->dive.sub_sport = (ENUM) data;
662+
garmin->dive.current_gasmix_usage = DC_USAGE_OPEN_CIRCUIT;
659663
dc_divemode_t val;
660664
switch (data) {
661665
case 55: val = DC_DIVEMODE_GAUGE;
662666
break;
663667
case 56:
664668
case 57: val = DC_DIVEMODE_FREEDIVE;
665669
break;
666-
case 63: val = DC_DIVEMODE_CCR;
670+
case 63:
671+
val = DC_DIVEMODE_CCR;
672+
garmin->dive.current_gasmix_usage = DC_USAGE_DILUENT;
673+
667674
break;
668675
default: val = DC_DIVEMODE_OC;
669676
}
@@ -797,7 +804,7 @@ DECLARE_FIELD(SENSOR_PROFILE, enabled, ENUM)
797804
{
798805
current_sensor(garmin)->sensor_enabled = data;
799806
}
800-
DECLARE_FIELD(SENSOR_PROFILE, sensor_type, UINT8)
807+
DECLARE_FIELD(SENSOR_PROFILE, sensor_type, ENUM)
801808
{
802809
// 28 is tank pod
803810
// start filling in next sensor after this record
@@ -1090,7 +1097,7 @@ DECLARE_MESG(SENSOR_PROFILE) = {
10901097
SET_FIELD(SENSOR_PROFILE, 0, ant_channel_id, UINT32Z), // derived from the number engraved on the side
10911098
SET_FIELD(SENSOR_PROFILE, 2, name, STRING),
10921099
SET_FIELD(SENSOR_PROFILE, 3, enabled, ENUM),
1093-
SET_FIELD(SENSOR_PROFILE, 52, sensor_type, UINT8), // 28 is tank pod
1100+
SET_FIELD(SENSOR_PROFILE, 52, sensor_type, ENUM), // 28 is tank pod
10941101
SET_FIELD(SENSOR_PROFILE, 74, pressure_units, ENUM), // 0 is PSI, 1 is KPA (unused), 2 is Bar
10951102
SET_FIELD(SENSOR_PROFILE, 75, rated_pressure, UINT16),
10961103
SET_FIELD(SENSOR_PROFILE, 76, reserve_pressure, UINT16),
@@ -1337,7 +1344,10 @@ static int traverse_regular(struct garmin_parser_t *garmin,
13371344
}
13381345

13391346
if (field_desc) {
1340-
field_desc->parse(garmin, base_type, data);
1347+
if (field_nr == 253 && !msg_desc->maxfield)
1348+
DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message.");
1349+
else
1350+
field_desc->parse(garmin, base_type, data);
13411351
} else {
13421352
unknown_field(garmin, data, msg_name, field_nr, base_type, len);
13431353
}
@@ -1521,7 +1531,12 @@ traverse_data(struct garmin_parser_t *garmin)
15211531
// Compressed records are like normal records
15221532
// with that added relative timestamp
15231533
DEBUG(garmin->base.context, "Compressed record for type %d", type);
1524-
parse_ANY_timestamp(garmin, time);
1534+
1535+
if (!(garmin->type_desc + type)->msg_desc->maxfield)
1536+
DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message.");
1537+
else
1538+
parse_ANY_timestamp(garmin, time);
1539+
15251540
len = traverse_regular(garmin, data, datasize, type, &time);
15261541
} else if (record & 0x40) { // Definition record?
15271542
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
16151630
static dc_status_t
16161631
garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsigned int size)
16171632
{
1633+
// This list is empirical and somewhat speculative
1634+
// will have to be confirmed with Garmin
1635+
static const struct {
1636+
int id;
1637+
const char *name;
1638+
} models[] = {
1639+
{ 2859, "Descent Mk1" },
1640+
{ 2991, "Descent Mk1 APAC" },
1641+
{ 3258, "Descent Mk2(i)" },
1642+
{ 3542, "Descent Mk2s" },
1643+
{ 3702, "Descent Mk2 APAC" },
1644+
{ 4223, "Descent Mk3" },
1645+
};
1646+
16181647
/* Walk the data once without a callback to set up the core fields */
16191648
garmin->callback = NULL;
16201649
garmin->userdata = NULL;
@@ -1630,6 +1659,17 @@ garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsi
16301659
if (garmin->dive.firmware)
16311660
dc_field_add_string_fmt(&garmin->cache, "Firmware", "%u.%02u",
16321661
garmin->dive.firmware / 100, garmin->dive.firmware % 100);
1662+
if (garmin->dive.product) {
1663+
int i = 0;
1664+
for (i = 0; i < C_ARRAY_SIZE(models); i++)
1665+
if (models[i].id == garmin->dive.product)
1666+
break;
1667+
1668+
if (i < C_ARRAY_SIZE(models))
1669+
dc_field_add_string_fmt(&garmin->cache, "Model", "%s", models[i].name);
1670+
else
1671+
dc_field_add_string_fmt(&garmin->cache, "Model", "Unknown model ID: %u", garmin->dive.product);
1672+
}
16331673

16341674
// These seem to be the "real" GPS dive coordinates
16351675
add_gps_string(garmin, "GPS1", &garmin->gps.SESSION.entry);

0 commit comments

Comments
 (0)