From: Linus Torvalds torvalds@linux-foundation.org Date: Wed, 22 Oct 2014 11:23:09 -0700 Subject: parser: add DC_FIELD_DEVINFO field type for parse-time device information
This can be used to extend and override the device open-time DEVINFO callback information at dive parse time. If you leave the pointers NULL, nothing happens, but you can choose to individually fill in the fields as needed (or not).
NOTE: The caller is supposed to clear the structure so that the divecomputer backends don't need to care about fields they don't support. So it's valid for a backend to just return DC_STATUS_SUCCESS and not do anything else as a reply to DC_FIELD_DEVINFO, although obviously that means that you won't be returning any new information either.
Signed-off-by: Linus Torvalds torvalds@linux-foundation.org ---
This is actually "PATCH 6/7" in my current series to support the new Suunto EON Steel dive computer, but it stands on its own as preparatory infrastructure, and I thought I should send it out as such.
This simply implements the "DC_FIELD_DEVINFO" field, which allows a dive computer backend to - at parse time - give what amounts to a sanitized and extended version of the DC_EVENT_DEVINFO device event.
In particular, it differs from DEVINFO in that:
- it contains all strings (expected to be utf8, because we're not barbarians any more, but for Windows people you could just say "ASCII" to not confuse the poor souls)
- it is expected to be called for each dive at parse time, and also thus allows a "dive id" string to be filled in.
- if the dive computer backend doesn't have anything to add to the original DC_EVENT_DEVINFO, then the backend can just ignore this.
The basic premise is simply that (a) strings are good and (b) we may have more information at parse-time than at the original DC_EVENT time..
This is trivially usable by subsurface - or any other user of libdivecomputer - in *addition* to the old interface, and I'll post another patch to show how subsurface does it. It doesn't replace or remove the old DC_EVENT_DEVINFO interface, it really just is a seamless extension of it with a better interface.
As you can see, the patch itself is also really really trivial and small. So not only is this flexible and simple to use, the implementation really is trivial too.
Comments? Btw, I'm in no way married to the particular fields. They are not at all everything that the EON Steel returns, but they seem to be fairly generic and useful in general.
Side note: the "vendor/model" thing migth be too much repetition and I don't really use it for the EON Steel at all, but I added those because I think it might be useful for the case where the user doesn't specify the device very precisely, and one backend can handle many different models.
In other words, this might be a good way to allow the back-end to give more precise information, without having the user having to care (ie if the backend can download from both a "Mares Icon" and a "Mares Icon HD", and the user doesn't need to specify *which* one it is, this would allow the dive log app to get the exact model name even if the user just said "Mares Icon".
Comments?
include/libdivecomputer/parser.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 65b18c9bb2fe..741803f4e256 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -53,9 +53,13 @@ typedef enum dc_field_type_t { DC_FIELD_GASMIX_COUNT, DC_FIELD_GASMIX, DC_FIELD_SALINITY, - DC_FIELD_ATMOSPHERIC + DC_FIELD_ATMOSPHERIC, + DC_FIELD_DEVINFO, } dc_field_type_t;
+// Make it easy to test support compile-time with "#ifdef DC_FIELD_DEVINFO" +#define DC_FIELD_DEVINFO DC_FIELD_DEVINFO + typedef enum parser_sample_event_t { SAMPLE_EVENT_NONE, SAMPLE_EVENT_DECOSTOP, @@ -128,6 +132,17 @@ typedef struct dc_gasmix_t { double nitrogen; } dc_gasmix_t;
+// You don't have to fill all of these in, you can leave them NULL +// but if you do fill them in, they override the device devinfo +typedef struct dc_field_devinfo_t { + const char *vendor; + const char *model; + const char *serial; + const char *hw_version; + const char *fw_version; + const char *dive_id; +} dc_field_devinfo_t; + typedef union dc_sample_value_t { unsigned int time; double depth;
From: Linus Torvalds torvalds@linux-foundation.org Date: Wed, 22 Oct 2014 12:11:12 -0700 Subject: [PATCH] Use the new DC_FIELD_DEVINFO callback if it exists
This gets dive ID and divecomputer device information in a sane string format.
Signed-off-by: Linus Torvalds torvalds@linux-foundation.org ---
Jef and the libdivecomputer mailing list cc'd, because this whole patch to subsurface only makes sense if the libdivecomputer part of it gets applied.
So I'm sending this out not to be applied by Dirk, but to show how simple the new DC_FIELD_DEVINFO model is to use, and how subsurface can trivially use it.
With this patch, my Suunto EON Steel backend to liobdivecomputer "just works". Even without this patch it worked for getting dives and profiles, but this is the part that is needed to actually get dive computer serial numbers etc.
Also notice how this can actually work *together* with the old DC_EVENT_DEVINFO interface. In particular, say that you have an old backend that used the DC_EVENT_DEVINFO interface, but wants to give a *real* serial number, not the broken numeric-only one that DC_EVENT_DEVINFO supports.
Such a backend could just add the new DC_FIELD_DEVINFO support, and subsurface will continue to use the old "deviceid" that was generated by DC_EVENT_DEVINFO - so that device ID's don't change in your logbook - but can automatically now pick up properly formatted serial numbers (of hardware versions etc). And it would "just work".
The point being that this doesn't break the old interface, and it's actually designed to work in conjunction with it. It's also designed so that applications that haven't been changed (including versions of subsurface that do not have this patch) to use the new DC_FIELD_DEVINFO interface won't even notice.
They'll get all the old information, and they aren't broken by any of this. They can't take advantage of the new info, and they won't get EON Steel serial numbers etc, but they'll work fine.
libdivecomputer.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/libdivecomputer.c b/libdivecomputer.c index ff8d0eb93bda..5da49577ba2c 100644 --- a/libdivecomputer.c +++ b/libdivecomputer.c @@ -397,6 +397,28 @@ static uint32_t calculate_diveid(const unsigned char *fingerprint, unsigned int return csum[0]; }
+static uint32_t calculate_string_hash(const char *str) +{ + return calculate_diveid(str, strlen(str)); +} + +static void parse_devinfo(struct dive *dive, dc_field_devinfo_t *info) +{ + // Our dive ID is the string hash of the dive_id string + if (info->dive_id && !dive->dc.diveid) + dive->dc.diveid = calculate_string_hash(info->dive_id); + + // Our "device ID" is the string hash of the serial number + if (info->serial && !dive->dc.deviceid) + dive->dc.deviceid = calculate_string_hash(info->serial); + + // If we have a deviceid either from the above or from the + // original DC_EVENT_DEVINFO, and we now have serial numbers + // or fw/hw versions, fill that into the device node + if (dive->dc.deviceid && (info->serial || info->fw_version)) + create_device_node(dive->dc.model, dive->dc.deviceid, info->serial, info->fw_version, ""); +} + /* returns true if we want libdivecomputer's dc_device_foreach() to continue, * false otherwise */ static int dive_cb(const unsigned char *data, unsigned int size, @@ -494,6 +516,14 @@ static int dive_cb(const unsigned char *data, unsigned int size, dive->dc.surface_pressure.mbar = rint(surface_pressure * 1000.0); #endif
+#ifdef DC_FIELD_DEVINFO + // The dive parsing may give us more device information + dc_field_devinfo_t devinfo = { NULL }; + rc = dc_parser_get_field(parser, DC_FIELD_DEVINFO, 0, &devinfo); + if (rc == DC_STATUS_SUCCESS) + parse_devinfo(dive, &devinfo); +#endif + rc = parse_gasmixes(devdata, dive, parser, ngases, data); if (rc != DC_STATUS_SUCCESS) { dev_info(devdata, translate("gettextFromC", "Error parsing the gas mix"));
On Wed, Oct 22, 2014 at 12:40 PM, Linus Torvalds torvalds@linux-foundation.org wrote:
So I'm sending this out not to be applied by Dirk, but to show how simple the new DC_FIELD_DEVINFO model is to use, and how subsurface can trivially use it.
Oh, and I realized that I need to add another
#ifdef DC_FIELD_DEVINFO .. #endif
around the whole parse_devinfo() function too, since otherwise the compile will fail with any libdivecomputer version that doesn't define the 'dc_field_devinfo_t' type.
But other than that, I'm actually using this all now, and the EON Steel profiles are now part of the dive logs I maintain..
I will have to add some event parsing (and turn the ceiling and tts data into events too, for that matter), but the basics all work. Supporting things like synchronizing the time or even changing the configurable screens is a whole different matter. That's going to take a lot more effort.
Linus