Skip to content

Commit

Permalink
garmin_parser: add support for developer fields
Browse files Browse the repository at this point in the history
This was the _actual_ reason why the Suunto FIT file import fell flat on
its face: it adds records with developer fields in them, and I just had
no idea how to parse them.

It turns out that they aren't all *that* horrible to parse: they are
kind of like a special case of the regular FIT event fields.

And no, this does not really parse them: it only parses the layout, and
using that it can then skip the developer fields without causing the
decoder to go all wonky and lose stream synchronization.

At least it works for the specific case of the Suunto FIT files, and the
code makes some amount of sense.  The FIT format may be odd, but at the
same time it's most definitely designed for pretty simplistic devices,
so it's not some kind of crazy XML thing.

This gets us parsing those Suunto FIT files at least partially.

That said, it is all very rough indeed, since you have to lie and claim
you're downloading from a Garmin, and have to set up the whole magic
'Garmin/Activity/' directory structure and limit the file size to the 24
characters that Garmin uses.

So this is by no means the real solution.

Considering that Jef doesn't want the Garmin parser in libdivecomputer
anyway, the proper solution might be to move this all to subsurface, and
make it be a "FIT file import" thing instead.  Annoying, but on the
other hand it has also been a bit awkward to have it in libdivecomputer.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
torvalds committed Jul 13, 2023
1 parent 147d3df commit 929ce47
Showing 1 changed file with 55 additions and 7 deletions.
62 changes: 55 additions & 7 deletions src/garmin_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct msg_desc;
struct type_desc {
const char *msg_name;
const struct msg_desc *msg_desc;
unsigned char nrfields;
unsigned char nrfields, devfields;
unsigned char fields[MAXFIELDS][3];
};

Expand Down Expand Up @@ -1281,6 +1281,31 @@ static int traverse_regular(struct garmin_parser_t *garmin,
size -= len;
}

for (int i = 0; i < desc->devfields; i++) {
int desc_idx = i + desc->nrfields;
const unsigned char *field = desc->fields[desc_idx];
unsigned int field_nr = field[0];
unsigned int len = field[1];
unsigned int type = field[2];

DEBUG(garmin->base.context, "Developer field %d %02x type %02x", i, field_nr, type);

if (!len) {
ERROR(garmin->base.context, " developer field with zero length\n");
return -1;
}

if (size < len) {
ERROR(garmin->base.context, " developer field bigger than remaining data (%d vs %d)\n", len, size);
return -1;
}

HEXDUMP(garmin->base.context, DC_LOGLEVEL_DEBUG, "data", data, len);
data += len;
total_len += len;
size -= len;
}

return total_len;
}

Expand Down Expand Up @@ -1328,19 +1353,42 @@ static int traverse_definition(struct garmin_parser_t *garmin,
desc->nrfields = fields;
len = 5 + fields*3;
devfields = 0;
if (record & 0x20) {
devfields = data[len];
len += 1 + devfields*3;
ERROR(garmin->base.context, "NO support for developer fields yet\n");
return -1;
}

for (int i = 0; i < fields; i++) {
unsigned char *field = desc->fields[i];
memcpy(field, data + (5+i*3), 3);
DEBUG(garmin->base.context, " %d: %02x %02x %02x", i, field[0], field[1], field[2]);
}

data += len;

/* Developer fields after the regular ones */
if (record & 0x20) {
devfields = data[0];
DEBUG(garmin->base.context, "Developer field (rec=%02x len=%d, devfields=%d)",
record, len, devfields);
HEXDUMP (garmin->base.context, DC_LOGLEVEL_DEBUG, "data", data, 40);

/*
* one byte of dev field numbers, each three bytes in size
* (number/size/index)
*/
len += 1 + 3*devfields;

for (int i = 0; i < devfields; i++) {
int idx = fields + i;
unsigned char *field = desc->fields[idx];
if (idx > MAXFIELDS) {
ERROR(garmin->base.context, "Too many dev fields in description: %d+%d (max %d)\n", fields, i, MAXFIELDS);
return -1;
}
memcpy(field, data + (1+i*3), 3);
DEBUG(garmin->base.context, " %d: %02x %02x %02x", i, field[0], field[1], field[2]);
}
}

desc->devfields = devfields;

return len;
}

Expand Down

0 comments on commit 929ce47

Please sign in to comment.