From bdf8b4b3bdf948cf2330658e4e406d092f90a253 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 22 Oct 2014 11:23:09 -0700 Subject: [PATCH 01/33] parser: add DC_FIELD_STRING field type for parse-time information This can be used to return almost arbitrary information to the dive log application at dive parse time, by returning a number of strings (with a descriptor) for dive state. NOTE! The strings are supposed to be human-readable, so that the dive log application can just show them unedited - and without understanding them - to the user, together with the description. So if your dive computer supports returning a battery voltage, for example, you can return it as a { "Voltage", "4.449V" } descriptor/value string pair, and the application could then put these string pairs together and show (somewhere) an informational line like "Voltage: 4.449V" along with the other information you return. Some dive log applications migth recognize particular descriptor strings and use them specially to fill in other information (ie serial numbers, weight and suit information etc), but in general the interface is very much meant to be informational free-form for a human user. So do *not* use this interface to encode things that are not human- readable. Serial numbers or version information that is meaningful to humans are fine. But random encoded data structures are not. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- include/libdivecomputer/parser.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 774e5e3..dbd9d2d 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -59,9 +59,13 @@ typedef enum dc_field_type_t { DC_FIELD_TEMPERATURE_MAXIMUM, DC_FIELD_TANK_COUNT, DC_FIELD_TANK, - DC_FIELD_DIVEMODE + DC_FIELD_DIVEMODE, + DC_FIELD_STRING, } dc_field_type_t; +// Make it easy to test support compile-time with "#ifdef DC_FIELD_STRING" +#define DC_FIELD_STRING DC_FIELD_STRING + typedef enum parser_sample_event_t { SAMPLE_EVENT_NONE, SAMPLE_EVENT_DECOSTOP, @@ -181,6 +185,11 @@ typedef struct dc_tank_t { double endpressure; /* End pressure (bar) */ } dc_tank_t; +typedef struct dc_field_string_t { + const char *desc; + const char *value; +} dc_field_string_t; + typedef union dc_sample_value_t { unsigned int time; double depth; From 4377bf7f2d77ae0c9216104fe37a0e9ad5e50eb6 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 8 Nov 2014 17:10:14 -0800 Subject: [PATCH 02/33] Add DC_FIELD_STRING support to Atomics Aquatics Cobalt parser Just support a few of the most useful values. There are several more we could and should add. Signed-off-by: Dirk Hohndel --- src/atomics_cobalt_parser.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c index 83bcfc7..ab6ec6a 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -20,6 +20,12 @@ */ #include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif #include #include @@ -139,6 +145,9 @@ atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *dateti } +#define BUFLEN 16 + + static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { @@ -153,6 +162,9 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un dc_tank_t *tank = (dc_tank_t *) value; double atmospheric = 0.0; + char buf[BUFLEN]; + dc_field_string_t *string = (dc_field_string_t *) value; + if (parser->atmospheric) atmospheric = parser->atmospheric; else @@ -218,6 +230,29 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un return DC_STATUS_DATAFORMAT; } break; + case DC_FIELD_STRING: + switch(flags) { + case 0: // Serialnr + string->desc = "Serial"; + snprintf(buf, BUFLEN, "%c%c%c%c-%c%c%c%c", p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]); + break; + case 1: // Program Version + string->desc = "Program Version"; + snprintf(buf, BUFLEN, "%.2f", array_uint16_le(p + 30) / 100.0); + break; + case 2: // Boot Version + string->desc = "Boot Version"; + snprintf(buf, BUFLEN, "%.2f", array_uint16_le(p + 32) / 100.0); + break; + case 3: // Nofly + string->desc = "NoFly Time"; + snprintf(buf, BUFLEN, "%0u:%02u", p[0x52], p[0x53]); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } From feb1d9d3915ce737cb3528765e3594a24a8827f3 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 8 Nov 2014 18:08:25 -0800 Subject: [PATCH 03/33] Add DC_FIELD_STRING support to Shearwater Petrel parser Just support a few of the most useful values. There are several more we could and should add. Signed-off-by: Dirk Hohndel --- src/shearwater_predator_parser.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 3d9d26d..e7ca143 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -20,6 +20,12 @@ */ #include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif #include #include @@ -173,6 +179,8 @@ shearwater_predator_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *d } +#define BUFLEN 16 + static dc_status_t shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) { @@ -239,7 +247,9 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; unsigned int density = 0; + char buf[BUFLEN]; if (value) { switch (type) { @@ -271,6 +281,16 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ case DC_FIELD_ATMOSPHERIC: *((double *) value) = array_uint16_be (data + 47) / 1000.0; break; + case DC_FIELD_STRING: + switch(flags) { + case 0: // Battery + string->desc = "Battery at end"; + snprintf(buf, BUFLEN, "%.1f", data[9] / 10.0); + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } From 54957047a185a3bfd679943b6c29db7514ac0156 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 8 Nov 2014 18:08:58 -0800 Subject: [PATCH 04/33] Add DC_FIELD_STRING support to OSTC parser Just support a few of the most useful values. There are several more we could and should add. Signed-off-by: Dirk Hohndel --- src/hw_ostc_parser.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index a0e9002..437301b 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -20,6 +20,12 @@ */ #include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif #include #include "libdivecomputer/units.h" @@ -57,6 +63,10 @@ #define OSTC3_GAUGE 2 #define OSTC3_APNEA 3 +#define UNSUPPORTED 0xFFFFFFFF + +typedef struct hw_ostc_parser_t hw_ostc_parser_t; + typedef struct hw_ostc_sample_info_t { unsigned int type; unsigned int divisor; @@ -72,6 +82,8 @@ typedef struct hw_ostc_layout_t { unsigned int salinity; unsigned int duration; unsigned int temperature; + unsigned int battery; + unsigned int desat; } hw_ostc_layout_t; typedef struct hw_ostc_gasmix_t { @@ -117,6 +129,8 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 43, /* salinity */ 47, /* duration */ 13, /* temperature */ + 34, /* battery volt after dive */ + 17, /* desat */ }; static const hw_ostc_layout_t hw_ostc_layout_frog = { @@ -128,6 +142,8 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 43, /* salinity */ 47, /* duration */ 19, /* temperature */ + UNSUPPORTED, /* battery volt after dive */ + UNSUPPORTED, /* desat */ }; static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { @@ -139,6 +155,8 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 70, /* salinity */ 75, /* duration */ 22, /* temperature */ + 50, /* battery volt after dive */ + 26, /* desat */ }; static unsigned int @@ -380,6 +398,8 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) return DC_STATUS_SUCCESS; } +#define BUFLEN 16 + static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { @@ -404,9 +424,12 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; + unsigned int salinity = data[layout->salinity]; if (version == 0x23) salinity += 100; + char buf[BUFLEN]; if (value) { switch (type) { @@ -497,6 +520,22 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned return DC_STATUS_UNSUPPORTED; } break; + case DC_FIELD_STRING: + switch(flags) { + case 0: /* battery */ + string->desc = "Battery at end"; + snprintf(buf, BUFLEN, "%.2f", array_uint16_le (data + layout->battery) / 1000.0); + break; + case 1: /* desat */ + string->desc = "Desat time"; + snprintf(buf, BUFLEN, "%0u:%02u", array_uint16_le (data + layout->desat) / 60, + array_uint16_le (data + layout->desat) % 60); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } From 5f4d8e09b49c1365aba6154bed00696ffb7323e9 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Thu, 20 Nov 2014 18:17:47 -0800 Subject: [PATCH 05/33] Support FW Version on OSTC devices And add battery voltage and desat for the Frog. Signed-off-by: Dirk Hohndel --- src/hw_ostc_parser.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 437301b..a7b6dbd 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -84,6 +84,7 @@ typedef struct hw_ostc_layout_t { unsigned int temperature; unsigned int battery; unsigned int desat; + unsigned int fw_version; } hw_ostc_layout_t; typedef struct hw_ostc_gasmix_t { @@ -131,6 +132,7 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 13, /* temperature */ 34, /* battery volt after dive */ 17, /* desat */ + 32, /* fw_version */ }; static const hw_ostc_layout_t hw_ostc_layout_frog = { @@ -142,8 +144,9 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 43, /* salinity */ 47, /* duration */ 19, /* temperature */ - UNSUPPORTED, /* battery volt after dive */ - UNSUPPORTED, /* desat */ + 34, /* battery volt after dive */ + 23, /* desat */ + 32, /* fw_version */ }; static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { @@ -157,6 +160,7 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 22, /* temperature */ 50, /* battery volt after dive */ 26, /* desat */ + 48, /* fw_version */ }; static unsigned int @@ -531,6 +535,10 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned snprintf(buf, BUFLEN, "%0u:%02u", array_uint16_le (data + layout->desat) / 60, array_uint16_le (data + layout->desat) % 60); break; + case 2: /* fw_version */ + string->desc = "FW Version"; + snprintf(buf, BUFLEN, "%0u.%0u", data[layout->fw_version], data[layout->fw_version + 1]); + break; default: return DC_STATUS_UNSUPPORTED; } From 3ae06d85e91079892ebe4b4150ee9437d2448691 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 21 Nov 2014 12:55:11 -0800 Subject: [PATCH 06/33] Pass the serial number from the devinfo to the OSTC parsers This way we can analyze the data in the parser and return it to the application. Signed-off-by: Dirk Hohndel --- include/libdivecomputer/hw_ostc.h | 2 +- src/hw_ostc_parser.c | 4 +++- src/parser.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/libdivecomputer/hw_ostc.h b/include/libdivecomputer/hw_ostc.h index 4dfb523..91fe714 100644 --- a/include/libdivecomputer/hw_ostc.h +++ b/include/libdivecomputer/hw_ostc.h @@ -65,7 +65,7 @@ dc_status_t hw_ostc_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata); dc_status_t -hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int frog); +hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int frog); dc_status_t hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename); diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index a7b6dbd..3bf9bde 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -95,6 +95,7 @@ typedef struct hw_ostc_gasmix_t { typedef struct hw_ostc_parser_t { dc_parser_t base; unsigned int frog; + unsigned int serial; // Cached fields. unsigned int cached; unsigned int version; @@ -282,7 +283,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } dc_status_t -hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int frog) +hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int frog) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -310,6 +311,7 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int fr parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; } + parser->serial = serial; *out = (dc_parser_t *) parser; diff --git a/src/parser.c b/src/parser.c index 4d0d97e..d8a137a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -111,11 +111,11 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = mares_iconhd_parser_create (&parser, context, device->devinfo.model); break; case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, 0); + rc = hw_ostc_parser_create (&parser, context, device->devinfo.serial, 0); break; case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_OSTC3: - rc = hw_ostc_parser_create (&parser, context, 1); + rc = hw_ostc_parser_create (&parser, context, device->devinfo.serial, 1); break; case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_ZEAGLE_N2ITION3: From d9b40eaa52361e4ae5fde8d03bbc05591caa5f7e Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 21 Nov 2014 13:00:12 -0800 Subject: [PATCH 07/33] Add support to return serial number to OSTC devices This data isn't per dive, but it makes sense to return it here as a string (we already return it as unsigned int in the devinfo event after opening the device). Signed-off-by: Dirk Hohndel --- src/hw_ostc_parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 3bf9bde..6917530 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -541,6 +541,10 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned string->desc = "FW Version"; snprintf(buf, BUFLEN, "%0u.%0u", data[layout->fw_version], data[layout->fw_version + 1]); break; + case 3: /* serial */ + string->desc = "Serial"; + snprintf(buf, BUFLEN, "%u", parser->serial); + break; default: return DC_STATUS_UNSUPPORTED; } From bb283bc5e1e6f82f84f804060656b825ae320103 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 21 Nov 2014 13:24:34 -0800 Subject: [PATCH 08/33] Support serial number as DC_FIELD_STRING on atom2 backend This has been verified with a few of the models, it needs much more testing to make sure this is generally correct. Signed-off-by: Dirk Hohndel --- include/libdivecomputer/oceanic_atom2.h | 2 +- src/oceanic_atom2_parser.c | 20 +++++++++++++++++++- src/parser.c | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/libdivecomputer/oceanic_atom2.h b/include/libdivecomputer/oceanic_atom2.h index 4cae707..194c84b 100644 --- a/include/libdivecomputer/oceanic_atom2.h +++ b/include/libdivecomputer/oceanic_atom2.h @@ -43,7 +43,7 @@ dc_status_t oceanic_atom2_device_keepalive (dc_device_t *device); dc_status_t -oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model); +oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial); #ifdef __cplusplus } diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index b13a9f8..4b03bbe 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -20,6 +20,8 @@ */ #include +#include +#include #include #include @@ -86,6 +88,7 @@ struct oceanic_atom2_parser_t { unsigned int model; unsigned int headersize; unsigned int footersize; + unsigned int serial; // Cached fields. unsigned int cached; unsigned int divetime; @@ -109,7 +112,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { dc_status_t -oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) +oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -151,6 +154,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned parser->headersize = 5 * PAGESIZE; } + parser->serial = serial; parser->cached = 0; parser->divetime = 0; parser->maxdepth = 0.0; @@ -318,6 +322,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim return DC_STATUS_SUCCESS; } +#define BUF_LEN 16 static dc_status_t oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) @@ -366,9 +371,11 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; unsigned int oxygen = 0; unsigned int helium = 0; + char buf[BUF_LEN]; if (value) { switch (type) { @@ -452,6 +459,17 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns return DC_STATUS_DATAFORMAT; } break; + case DC_FIELD_STRING: + switch(flags) { + case 0: /* Serial */ + string->desc = "Serial"; + snprintf(buf, BUF_LEN, "%06u", parser->serial); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } diff --git a/src/parser.c b/src/parser.c index d8a137a..16f626a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -98,7 +98,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) if (device->devinfo.model == REACTPROWHITE) rc = oceanic_veo250_parser_create (&parser, context, device->devinfo.model); else - rc = oceanic_atom2_parser_create (&parser, context, device->devinfo.model); + rc = oceanic_atom2_parser_create (&parser, context, device->devinfo.model, device->devinfo.serial); break; case DC_FAMILY_MARES_NEMO: case DC_FAMILY_MARES_PUCK: From fbe702ea7bc66370787d08d5615637e99871bd9a Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 21 Nov 2014 13:56:43 -0800 Subject: [PATCH 09/33] Support firmware and serial number for Shearwater Petrel This should work with the Predator as well. Signed-off-by: Dirk Hohndel --- include/libdivecomputer/shearwater_petrel.h | 2 +- include/libdivecomputer/shearwater_predator.h | 2 +- src/parser.c | 4 ++-- src/shearwater_predator_parser.c | 21 ++++++++++++++----- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/libdivecomputer/shearwater_petrel.h b/include/libdivecomputer/shearwater_petrel.h index 5092127..18a4bce 100644 --- a/include/libdivecomputer/shearwater_petrel.h +++ b/include/libdivecomputer/shearwater_petrel.h @@ -34,7 +34,7 @@ dc_status_t shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, const char *name); dc_status_t -shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context); +shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial); #ifdef __cplusplus } diff --git a/include/libdivecomputer/shearwater_predator.h b/include/libdivecomputer/shearwater_predator.h index 40c7ae2..28163e2 100644 --- a/include/libdivecomputer/shearwater_predator.h +++ b/include/libdivecomputer/shearwater_predator.h @@ -37,7 +37,7 @@ dc_status_t shearwater_predator_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata); dc_status_t -shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context); +shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial); #ifdef __cplusplus } diff --git a/src/parser.c b/src/parser.c index 16f626a..6471e3f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -128,10 +128,10 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = atomics_cobalt_parser_create (&parser, context); break; case DC_FAMILY_SHEARWATER_PREDATOR: - rc = shearwater_predator_parser_create (&parser, context); + rc = shearwater_predator_parser_create (&parser, context, device->devinfo.serial); break; case DC_FAMILY_SHEARWATER_PETREL: - rc = shearwater_petrel_parser_create (&parser, context); + rc = shearwater_petrel_parser_create (&parser, context, device->devinfo.serial); break; case DC_FAMILY_DIVERITE_NITEKQ: rc = diverite_nitekq_parser_create (&parser, context); diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index e7ca143..c7a529c 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -58,6 +58,7 @@ struct shearwater_predator_parser_t { unsigned int ngasmixes; unsigned int oxygen[NGASMIXES]; unsigned int helium[NGASMIXES]; + unsigned int serial; }; static dc_status_t shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); @@ -86,7 +87,7 @@ static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { dc_status_t -shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int petrel) +shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int petrel) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -100,6 +101,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig // Initialize the base class. parser->petrel = petrel; + parser->serial = serial; if (petrel) { parser_init (&parser->base, context, &shearwater_petrel_parser_vtable); } else { @@ -121,16 +123,16 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig dc_status_t -shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context) +shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial) { - return shearwater_common_parser_create (out, context, 0); + return shearwater_common_parser_create (out, context, serial, 0); } dc_status_t -shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context) +shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial) { - return shearwater_common_parser_create (out, context, 1); + return shearwater_common_parser_create (out, context, serial, 1); } @@ -286,6 +288,15 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ case 0: // Battery string->desc = "Battery at end"; snprintf(buf, BUFLEN, "%.1f", data[9] / 10.0); + break; + case 1: // Serial + string->desc = "Serial"; + snprintf(buf, BUFLEN, "%08x", parser->serial); + break; + case 2: // FW Version + string->desc = "FW Version"; + snprintf(buf, BUFLEN, "%2x", data[19]); + break; default: return DC_STATUS_UNSUPPORTED; } From c28aa775e61c25366aa88461cf4f0704bd82fc9d Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 21 Nov 2014 14:29:53 -0800 Subject: [PATCH 10/33] Support serial number for Suuntu Vyper2 family of devices We have the correct firmware in the devinfo, but that's the firmware the dive computer is on NOW, not necessarily the firmware it was using when recording the dive. Signed-off-by: Dirk Hohndel --- include/libdivecomputer/suunto_d9.h | 2 +- src/parser.c | 2 +- src/suunto_d9_parser.c | 24 ++++++++++++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/libdivecomputer/suunto_d9.h b/include/libdivecomputer/suunto_d9.h index d177c6c..1fb1824 100644 --- a/include/libdivecomputer/suunto_d9.h +++ b/include/libdivecomputer/suunto_d9.h @@ -42,7 +42,7 @@ dc_status_t suunto_d9_device_reset_maxdepth (dc_device_t *device); dc_status_t -suunto_d9_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model); +suunto_d9_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial); #ifdef __cplusplus } diff --git a/src/parser.c b/src/parser.c index 6471e3f..66bb80a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -66,7 +66,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) break; case DC_FAMILY_SUUNTO_VYPER2: case DC_FAMILY_SUUNTO_D9: - rc = suunto_d9_parser_create (&parser, context, device->devinfo.model); + rc = suunto_d9_parser_create (&parser, context, device->devinfo.model, device->devinfo.serial); break; case DC_FAMILY_SUUNTO_EONSTEEL: rc = suunto_eonsteel_parser_create(&parser, context, device->devinfo.model); diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index e71a60f..ba4d551 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -20,7 +20,8 @@ */ #include -#include // memcmp +#include // memcmp, strdup +#include // snprintf #include @@ -62,6 +63,7 @@ typedef struct suunto_d9_parser_t suunto_d9_parser_t; struct suunto_d9_parser_t { dc_parser_t base; unsigned int model; + unsigned int serial; // Cached fields. unsigned int cached; unsigned int mode; @@ -186,7 +188,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) } dc_status_t -suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) +suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -203,6 +205,7 @@ suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int // Set the default values. parser->model = model; + parser->serial = serial; parser->cached = 0; parser->mode = AIR; parser->ngasmixes = 0; @@ -287,6 +290,7 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) return DC_STATUS_SUCCESS; } +#define BUFLEN 16 static dc_status_t suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) @@ -302,6 +306,9 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne return rc; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; + + char buf[BUFLEN]; if (value) { switch (type) { @@ -347,6 +354,19 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne return DC_STATUS_DATAFORMAT; } break; + case DC_FIELD_STRING: + switch (flags) { + case 0: /* serial */ + string->desc = "Serial"; + snprintf(buf, BUFLEN, "%02d%02d%02d%02d", (parser->serial >> 24) & 0xff, + (parser->serial >> 16) & 0xff, (parser->serial >> 8) & 0xff, + parser->serial & 0xff); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } From c0b79f46bf24a5154f445ef0fc0a7858e3c0912e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 24 Nov 2014 11:08:59 -0800 Subject: [PATCH 11/33] Fix suunto serial numbers libdivecomputer has already done the "byte to decimal" conversion. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- src/suunto_d9_parser.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index ba4d551..d4ae8aa 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -358,9 +358,7 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne switch (flags) { case 0: /* serial */ string->desc = "Serial"; - snprintf(buf, BUFLEN, "%02d%02d%02d%02d", (parser->serial >> 24) & 0xff, - (parser->serial >> 16) & 0xff, (parser->serial >> 8) & 0xff, - parser->serial & 0xff); + snprintf(buf, BUFLEN, "%08u", parser->serial); break; default: return DC_STATUS_UNSUPPORTED; From c13f4da702d84fb07e9a43ca9abb560ea35f6be1 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 12 Dec 2014 11:47:52 -0800 Subject: [PATCH 12/33] Mark a library built from our branch as such This way it will be obvious when people report their libdivecomputer version that they are not using upstream master. Signed-off-by: Dirk Hohndel --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 047b3f0..3cb11f7 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ m4_define([dc_version_major],[0]) m4_define([dc_version_minor],[5]) m4_define([dc_version_micro],[0]) -m4_define([dc_version_suffix],[devel]) +m4_define([dc_version_suffix],[devel-Subsurface-testing]) m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix])) # Libtool versioning. From 8d6417f16a23e450d08c8cce280635103de6f034 Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Wed, 21 Jan 2015 08:42:00 +0100 Subject: [PATCH 13/33] Add deco model info strings to hw parser Signed-off-by: Anton Lundin Signed-off-by: Dirk Hohndel --- src/hw_ostc_parser.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 6917530..76a3fc7 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -63,6 +63,9 @@ #define OSTC3_GAUGE 2 #define OSTC3_APNEA 3 +#define OSTC3_ZHL16 0 +#define OSTC3_ZHL16_GF 1 + #define UNSUPPORTED 0xFFFFFFFF typedef struct hw_ostc_parser_t hw_ostc_parser_t; @@ -85,6 +88,9 @@ typedef struct hw_ostc_layout_t { unsigned int battery; unsigned int desat; unsigned int fw_version; + unsigned int deco_info1; + unsigned int deco_info2; + unsigned int decomode; } hw_ostc_layout_t; typedef struct hw_ostc_gasmix_t { @@ -134,6 +140,9 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 34, /* battery volt after dive */ 17, /* desat */ 32, /* fw_version */ + 49, /* deco_info1 */ + 50, /* deco_info1 */ + 51, /* decomode */ }; static const hw_ostc_layout_t hw_ostc_layout_frog = { @@ -148,6 +157,9 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 34, /* battery volt after dive */ 23, /* desat */ 32, /* fw_version */ + 49, /* deco_info1 */ + 50, /* deco_info2 */ + 51, /* decomode */ }; static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { @@ -162,6 +174,9 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 50, /* battery volt after dive */ 26, /* desat */ 48, /* fw_version */ + 77, /* deco_info1 */ + 78, /* deco_info2 */ + 79, /* decomode */ }; static unsigned int @@ -545,6 +560,32 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned string->desc = "Serial"; snprintf(buf, BUFLEN, "%u", parser->serial); break; + case 4: /* Deco model */ + string->desc = "Deco model"; + if ((version == 0x23 && data[layout->decomode] == OSTC3_ZHL16) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC))) + strncpy(buf, "ZH-L16", BUFLEN); + if ((version == 0x23 && data[layout->decomode] == OSTC3_ZHL16_GF) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF))) + strncpy(buf, "ZH-L16-GF", BUFLEN); + else + return DC_STATUS_DATAFORMAT; + break; + case 5: /* Deco model info */ + string->desc = "Deco model info"; + if ((version == 0x23 && data[layout->decomode] == OSTC3_ZHL16) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC))) + snprintf(buf, BUFLEN, "Saturation %u, Desaturation %u", layout->deco_info1, layout->deco_info2); + if ((version == 0x23 && data[layout->decomode] == OSTC3_ZHL16_GF) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF))) + snprintf(buf, BUFLEN, "GF %u/%u", data[layout->deco_info1], data[layout->deco_info2]); + else + return DC_STATUS_DATAFORMAT; + break; default: return DC_STATUS_UNSUPPORTED; } From f1f2fa2c123e3945704639b0d4acf19ac5d2cfc0 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 2 Feb 2015 07:31:33 -0800 Subject: [PATCH 14/33] Don't report errors if we can't set serial mode That's just silly and breaks using the simulator. Signed-off-by: Dirk Hohndel --- src/serial_posix.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/serial_posix.c b/src/serial_posix.c index 2b0c3fa..e0e609a 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -418,8 +418,10 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int // Apply the new settings. if (tcsetattr (device->fd, TCSANOW, &tty) != 0) { +#if 0 // who cares SYSERROR (device->context, errno); return -1; +#endif } // Configure a custom baudrate if necessary. From 427466c3495bffcbe3a58baa6400735b4a0df7cc Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 6 Feb 2015 09:56:21 -0800 Subject: [PATCH 15/33] Predator: don't report PPO2 unless in CC mode Sending this in OC mode is redundant and might confuse applications that assume they only get PPO2 data in CC mode. Signed-off-by: Dirk Hohndel --- src/shearwater_predator_parser.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index c7a529c..ce71771 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -375,9 +375,11 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal sample.temperature = temperature; if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - // PPO2 - sample.ppo2 = data[offset + 6] / 100.0; - if (callback) callback (DC_SAMPLE_PPO2, sample, userdata); + // PPO2 -- only return PPO2 if we are in closed circuit mode + if (data[offset + 11] & 0x10 == 0) { + sample.ppo2 = data[offset + 6] / 100.0; + if (callback) callback (DC_SAMPLE_PPO2, sample, userdata); + } // CNS if (parser->petrel) { From ac56b20192392896177bacebcb0f572b306330cc Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Tue, 10 Feb 2015 07:39:56 +0100 Subject: [PATCH 16/33] Correct firmware version string from OSTC's The format string was incorrect, producing firmware numbers as 3.2 instead of 3.02 as is the current OSTC firmware version. This was reported via hw's forum: http://forum.heinrichsweikamp.com/read.php?2,14550,14552 Signed-off-by: Anton Lundin Signed-off-by: Dirk Hohndel --- src/hw_ostc_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 76a3fc7..451c71b 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -554,7 +554,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned break; case 2: /* fw_version */ string->desc = "FW Version"; - snprintf(buf, BUFLEN, "%0u.%0u", data[layout->fw_version], data[layout->fw_version + 1]); + snprintf(buf, BUFLEN, "%0u.%02u", data[layout->fw_version], data[layout->fw_version + 1]); break; case 3: /* serial */ string->desc = "Serial"; From b9e731e6414261cec8921310030de6b37e38fdac Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sat, 27 Jun 2015 15:11:15 +0300 Subject: [PATCH 17/33] Extend the transport enum descriptor for serial communication Add a new transport type which can be used to identify Bluetooth serial communication. Signed-off-by Claudiu Oleanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/descriptor.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/descriptor.h b/include/libdivecomputer/descriptor.h index 6f9735d..f1c815d 100644 --- a/include/libdivecomputer/descriptor.h +++ b/include/libdivecomputer/descriptor.h @@ -33,7 +33,8 @@ typedef enum dc_transport_t { DC_TRANSPORT_NONE, DC_TRANSPORT_SERIAL, DC_TRANSPORT_USB, - DC_TRANSPORT_IRDA + DC_TRANSPORT_IRDA, + DC_TRANSPORT_BLUETOOTH } dc_transport_t; typedef struct dc_descriptor_t dc_descriptor_t; From 619b9de06e3d62ddfc26511f0f7d1d8bb2b01e41 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sat, 27 Jun 2015 15:14:16 +0300 Subject: [PATCH 18/33] Create a generic way to represent any type of serial communication Add a structure which holds references to basic operations on a serial communication. This can be used to pass a set of function pointer callbacks in order to create a custom implementation for serial communication. Add a generic structure to represent the needed information for a serial communication. Implement the initialization method where the user can pass a set of function pointer callbacks and set some custom data for the serial device. Create open method for the native serial implementation. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/Makefile.am | 3 +- include/libdivecomputer/custom_serial.h | 63 ++++++++++++++++++++ src/Makefile.am | 3 +- src/custom_serial.c | 79 +++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 include/libdivecomputer/custom_serial.h create mode 100644 src/custom_serial.c diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am index 71887d5..a0ed196 100644 --- a/include/libdivecomputer/Makefile.am +++ b/include/libdivecomputer/Makefile.am @@ -53,4 +53,5 @@ libdivecomputer_HEADERS = \ citizen.h \ citizen_aqualand.h \ divesystem.h \ - divesystem_idive.h + divesystem_idive.h \ + custom_serial.h diff --git a/include/libdivecomputer/custom_serial.h b/include/libdivecomputer/custom_serial.h new file mode 100644 index 0000000..a52d49b --- /dev/null +++ b/include/libdivecomputer/custom_serial.h @@ -0,0 +1,63 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Claudiu Olteanu + * base on code that is Copyright (C) 2008 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef CUSTOM_SERIAL_H +#define CUSTOM_SERIAL_H + +#include +#include + +#include "context.h" +#include "descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct serial_t serial_t; + +typedef struct dc_serial_operations_t +{ + int (*open) (serial_t **device, dc_context_t *context, const char *name); + int (*close) (serial_t *device); + int (*read) (serial_t *device, void* data, unsigned int size); + int (*write) (serial_t *device, const void* data, unsigned int size); + int (*flush) (serial_t *device, int queue); + int (*get_received) (serial_t *device); + int (*get_transmitted) (serial_t *device); +} dc_serial_operations_t; + +typedef struct dc_serial_t { + serial_t *port; //serial device port + dc_transport_t type; //the type of the transport (USB, SERIAL, IRDA, BLUETOOTH) + void *data; //specific data for serial device + const dc_serial_operations_t *ops; //reference to a custom set of operations +} dc_serial_t; + +void dc_serial_init(dc_serial_t *device, void *data, const dc_serial_operations_t *ops); + +dc_status_t dc_serial_native_open(dc_serial_t **serial, dc_context_t *context, const char *devname); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CUSTOM_SERIAL_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 71a4770..5172227 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,7 +60,8 @@ libdivecomputer_la_SOURCES = \ ringbuffer.h ringbuffer.c \ checksum.h checksum.c \ array.h array.c \ - buffer.c + buffer.c \ + custom_serial.c if OS_WIN32 libdivecomputer_la_SOURCES += serial.h serial_win32.c diff --git a/src/custom_serial.c b/src/custom_serial.c new file mode 100644 index 0000000..6e024b2 --- /dev/null +++ b/src/custom_serial.c @@ -0,0 +1,79 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Claudiu Olteanu + * base on code that is Copyright (C) 2008 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include + +#include "context-private.h" + +const dc_serial_operations_t native_serial_ops = { + .open = serial_open, + .close = serial_close, + .read = serial_read, + .write = serial_write, + .flush = serial_flush, + .get_received = serial_get_received, + .get_transmitted = serial_get_transmitted +}; + + +void +dc_serial_init(dc_serial_t *device, void *data, const dc_serial_operations_t *ops) +{ + memset(device, 0, sizeof (*device)); + device->data = data; + device->ops = ops; +} + + +dc_status_t +dc_serial_native_open(dc_serial_t **out, dc_context_t *context, const char *devname) +{ + if (out == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + dc_serial_t *serial_device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); + + if (serial_device == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Initialize data and function pointers + dc_serial_init(serial_device, NULL, &native_serial_ops); + + // Open the serial device. + int rc = serial_open (&serial_device->port, context, devname); + if (rc == -1) { + ERROR (context, "Failed to open the serial port."); + free (serial_device); + return DC_STATUS_IO; + } + + // Set the type of the device + serial_device->type = DC_TRANSPORT_SERIAL; + + *out = serial_device; + + return DC_STATUS_SUCCESS; +} From 42bc3f1303ae20768810a85139586829fe01440a Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sat, 27 Jun 2015 15:18:01 +0300 Subject: [PATCH 19/33] Use the dc_serial_t structure in HW OSTC family 3 Open a native serial device and use it in the HW OSTC3 implementation. This patch replaces the old serial structure with the new one, which can be used for custom serial implementations. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/hw_ostc3.h | 2 ++ src/hw_ostc3.c | 41 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index c60dc63..454d45c 100644 --- a/include/libdivecomputer/hw_ostc3.h +++ b/include/libdivecomputer/hw_ostc3.h @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2013 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ #include "device.h" #include "parser.h" #include "buffer.h" +#include "custom_serial.h" #ifdef __cplusplus extern "C" { diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a221fb2..a55c5cc 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Jef Driesen * Copyright (C) 2014 Anton Lundin + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -88,7 +89,7 @@ typedef enum hw_ostc3_state_t { typedef struct hw_ostc3_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *serial; unsigned char fingerprint[5]; hw_ostc3_state_t state; } hw_ostc3_device_t; @@ -163,7 +164,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Send the command. unsigned char command[1] = {cmd}; - int n = serial_write (device->port, command, sizeof (command)); + int n = device->serial->ops->write (device->serial->port, command, sizeof (command)); if (n != sizeof (command)) { ERROR (abstract->context, "Failed to send the command."); return EXITCODE (n); @@ -171,7 +172,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Read the echo. unsigned char echo[1] = {0}; - n = serial_read (device->port, echo, sizeof (echo)); + n = device->serial->ops->read (device->serial->port, echo, sizeof (echo)); if (n != sizeof (echo)) { ERROR (abstract->context, "Failed to receive the echo."); return EXITCODE (n); @@ -190,7 +191,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, if (input) { // Send the input data packet. - n = serial_write (device->port, input, isize); + n = device->serial->ops->write (device->serial->port, input, isize); if (n != isize) { ERROR (abstract->context, "Failed to send the data packet."); return EXITCODE (n); @@ -204,7 +205,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, unsigned int len = 1024; // Increase the packet size if more data is immediately available. - int available = serial_get_received (device->port); + int available = device->serial->ops->get_received (device->serial->port); if (available > len) len = available; @@ -213,7 +214,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, len = osize - nbytes; // Read the packet. - n = serial_read (device->port, output + nbytes, len); + n = device->serial->ops->read (device->serial->port, output + nbytes, len); if (n != len) { ERROR (abstract->context, "Failed to receive the answer."); return EXITCODE (n); @@ -232,7 +233,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, if (cmd != EXIT) { // Read the ready byte. unsigned char answer[1] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); + n = device->serial->ops->read (device->serial->port, answer, sizeof (answer)); if (n != sizeof (answer)) { ERROR (abstract->context, "Failed to receive the ready byte."); return EXITCODE (n); @@ -266,11 +267,11 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name device_init (&device->base, context, &hw_ostc3_device_vtable); // Set the default values. - device->port = NULL; + device->serial = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); + int rc = dc_serial_native_open (&device->serial, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); free (device); @@ -278,25 +279,25 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); + device->serial->ops->close (device->serial->port); free (device); return DC_STATUS_IO; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + if (serial_set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); + device->serial->ops->close (device->serial->port); free (device); return DC_STATUS_IO; } // Make sure everything is in a sane state. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + serial_sleep (device->serial->port, 300); + device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); device->state = OPEN; @@ -336,17 +337,17 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device) int n = 0; // We cant use hw_ostc3_transfer here, due to the different echos - n = serial_write (device->port, command, sizeof (command)); + n = device->serial->ops->write (device->serial->port, command, sizeof (command)); if (n != sizeof (command)) { ERROR (context, "Failed to send the command."); return EXITCODE (n); } // Give the device some time to enter service mode - serial_sleep (device->port, 100); + serial_sleep (device->serial->port, 100); // Read the response - n = serial_read (device->port, output, sizeof (output)); + n = device->serial->ops->read (device->serial->port, output, sizeof (output)); if (n != sizeof (output)) { ERROR (context, "Failed to receive the echo."); return EXITCODE (n); @@ -408,14 +409,14 @@ hw_ostc3_device_close (dc_device_t *abstract) rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - serial_close (device->port); + device->serial->ops->close (device->serial->port); free (device); return rc; } } // Close the device. - if (serial_close (device->port) == -1) { + if (device->serial->ops->close (device->serial->port) == -1) { free (device); return DC_STATUS_IO; } From 70d4fcb46d340025df9c8c52a9c6b39cf6ec404a Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sat, 27 Jun 2015 15:21:19 +0300 Subject: [PATCH 20/33] Implement custom open method for HW OSTC 3 family Create a custom open method for HW OSTC3 family. This method can be used to pass a reference to a dc_serial_t structure. In this way the applications can implement their own implementation for a serial communication and set their callbacks for the basic serial functions. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/hw_ostc3.h | 3 ++ src/hw_ostc3.c | 57 ++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index 454d45c..8463cb2 100644 --- a/include/libdivecomputer/hw_ostc3.h +++ b/include/libdivecomputer/hw_ostc3.h @@ -39,6 +39,9 @@ extern "C" { dc_status_t hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +hw_ostc3_device_custom_open (dc_device_t **device, dc_context_t *context, dc_serial_t *serial); + dc_status_t hw_ostc3_device_version (dc_device_t *device, unsigned char data[], unsigned int size); diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a55c5cc..2d975b7 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -272,10 +272,10 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name // Open the device. int rc = dc_serial_native_open (&device->serial, context, name); - if (rc == -1) { + if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); free (device); - return DC_STATUS_IO; + return rc; } // Set the serial communication protocol (115200 8N1). @@ -307,6 +307,59 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name } +dc_status_t +hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +{ + if (out == NULL || serial == NULL || serial->port == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + hw_ostc3_device_t *device = (hw_ostc3_device_t *) malloc (sizeof (hw_ostc3_device_t)); + if (device == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Initialize the base class. + device_init (&device->base, context, &hw_ostc3_device_vtable); + + // Set the default values. + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + // Set the serial reference + device->serial = serial; + + if (serial->type == DC_TRANSPORT_SERIAL) { + // Set the serial communication protocol (115200 8N1). + int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + if (rc == -1) { + ERROR (context, "Failed to set the terminal attributes."); + device->serial->ops->close (device->serial->port); + free (device); + return DC_STATUS_IO; + } + } + + // Set the timeout for receiving data (3000ms). + if (serial_set_timeout (device->serial->port, 3000) == -1) { + ERROR (context, "Failed to set the timeout."); + device->serial->ops->close (device->serial->port); + free (device); + return DC_STATUS_IO; + } + + // Make sure everything is in a sane state. + serial_sleep (device->serial->port, 300); + device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + + device->state = OPEN; + + *out = (dc_device_t *) device; + + return DC_STATUS_SUCCESS; +} + + static dc_status_t hw_ostc3_device_init_download (hw_ostc3_device_t *device) { From d38ea815cfb89478ee8310674c8655ddcf005049 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sat, 27 Jun 2015 15:22:04 +0300 Subject: [PATCH 21/33] Implement custom device open method This method can be used by external applications to open a device and to pass their custom implementation for the serial communication. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/device.h | 5 +++++ src/device.c | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/libdivecomputer/device.h b/include/libdivecomputer/device.h index 7ba4bd6..60590b5 100644 --- a/include/libdivecomputer/device.h +++ b/include/libdivecomputer/device.h @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2008 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,6 +28,7 @@ #include "descriptor.h" #include "buffer.h" #include "datetime.h" +#include "custom_serial.h" #ifdef __cplusplus extern "C" { @@ -72,6 +74,9 @@ typedef int (*dc_dive_callback_t) (const unsigned char *data, unsigned int size, dc_status_t dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descriptor, const char *name); +dc_status_t +dc_device_custom_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descriptor, dc_serial_t *serial); + dc_family_t dc_device_get_type (dc_device_t *device); diff --git a/src/device.c b/src/device.c index d95585d..257dc75 100644 --- a/src/device.c +++ b/src/device.c @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2008 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -174,6 +175,27 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr return rc; } +dc_status_t +dc_device_custom_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descriptor, dc_serial_t *serial) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + + if (out == NULL || descriptor == NULL || serial == NULL) + return DC_STATUS_INVALIDARGS; + + switch (dc_descriptor_get_type (descriptor)) { + case DC_FAMILY_HW_OSTC3: + rc = hw_ostc3_device_custom_open (&device, context, serial); + break; + default: + return DC_STATUS_INVALIDARGS; + } + + *out = device; + + return rc; +} int dc_device_isinstance (dc_device_t *device, const dc_device_vtable_t *vtable) From 0f6d480a1dd6ff868cfbd33a53b7426abb2932d6 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Sun, 28 Jun 2015 23:46:56 +0300 Subject: [PATCH 22/33] Use the dc_serial_t structure in SHEARWATER family Use the new structure in the SHEARWATER family implementation. This patch opens a native serial device and use it for the serial communication. Also the patch uses the set of callback functions saved in the dc_serial_t structure. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- src/shearwater_common.c | 29 +++++++++++++++-------------- src/shearwater_common.h | 4 +++- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/shearwater_common.c b/src/shearwater_common.c index b809a3c..a4e94de 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2013 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -41,30 +42,30 @@ dc_status_t shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name) { // Open the device. - int rc = serial_open (&device->port, context, name); + int rc = dc_serial_native_open (&device->serial, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - return DC_STATUS_IO; + return rc; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); + device->serial->ops->close (device->serial->port); return DC_STATUS_IO; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + if (serial_set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); + device->serial->ops->close (device->serial->port); return DC_STATUS_IO; } // Make sure everything is in a sane state. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + serial_sleep (device->serial->port, 300); + device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); return DC_STATUS_SUCCESS; } @@ -74,7 +75,7 @@ dc_status_t shearwater_common_close (shearwater_common_device_t *device) { // Close the device. - if (serial_close (device->port) == -1) { + if (device->serial->ops->close (device->serial->port) == -1) { return DC_STATUS_IO; } @@ -154,7 +155,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned #if 0 // Send an initial END character to flush out any data that may have // accumulated in the receiver due to line noise. - n = serial_write (device->port, end, sizeof (end)); + n = device->serial->ops->write (device->serial->port, end, sizeof (end)); if (n != sizeof (end)) { return EXITCODE(n); } @@ -183,7 +184,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned // Flush the buffer if necessary. if (nbytes + len + sizeof(end) > sizeof(buffer)) { - n = serial_write (device->port, buffer, nbytes); + n = device->serial->ops->write (device->serial->port, buffer, nbytes); if (n != nbytes) { return EXITCODE(n); } @@ -201,7 +202,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned nbytes += sizeof(end); // Flush the buffer. - n = serial_write (device->port, buffer, nbytes); + n = device->serial->ops->write (device->serial->port, buffer, nbytes); if (n != nbytes) { return EXITCODE(n); } @@ -224,7 +225,7 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d int n = 0; // Get a single character to process. - n = serial_read (device->port, &c, 1); + n = device->serial->ops->read (device->serial->port, &c, 1); if (n != 1) { return EXITCODE(n); } @@ -243,7 +244,7 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d case ESC: // If it's an ESC character, get another character and then // figure out what to store in the packet based on that. - n = serial_read (device->port, &c, 1); + n = device->serial->ops->read (device->serial->port, &c, 1); if (n != 1) { return EXITCODE(n); } diff --git a/src/shearwater_common.h b/src/shearwater_common.h index a07de14..b930fb9 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2013 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +25,7 @@ #include "device-private.h" #include "serial.h" +#include "libdivecomputer/custom_serial.h" #ifdef __cplusplus extern "C" { @@ -34,7 +36,7 @@ extern "C" { typedef struct shearwater_common_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *serial; } shearwater_common_device_t; dc_status_t From 2f9227a3e2164d5e0c4931b47654779c01794754 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Mon, 29 Jun 2015 00:08:20 +0300 Subject: [PATCH 23/33] Implement custom open device method for SHEARWATER family Create a custom open method for SHEARWATER family. This method can be used to pass a reference to a dc_serial_t structure. In this way the applications can implement their own implementation for a serial communication and set their callbacks for the basic serial functions. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/shearwater_petrel.h | 4 +++ include/libdivecomputer/shearwater_predator.h | 4 +++ src/device.c | 6 ++++ src/shearwater_common.c | 33 ++++++++++++++++- src/shearwater_common.h | 3 ++ src/shearwater_petrel.c | 35 +++++++++++++++++++ src/shearwater_predator.c | 35 +++++++++++++++++++ 7 files changed, 119 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/shearwater_petrel.h b/include/libdivecomputer/shearwater_petrel.h index 18a4bce..97a8dc2 100644 --- a/include/libdivecomputer/shearwater_petrel.h +++ b/include/libdivecomputer/shearwater_petrel.h @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2013 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,6 +34,9 @@ extern "C" { dc_status_t shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial); + dc_status_t shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial); diff --git a/include/libdivecomputer/shearwater_predator.h b/include/libdivecomputer/shearwater_predator.h index 28163e2..9a37bcf 100644 --- a/include/libdivecomputer/shearwater_predator.h +++ b/include/libdivecomputer/shearwater_predator.h @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2012 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,6 +34,9 @@ extern "C" { dc_status_t shearwater_predator_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +shearwater_predator_device_custom_open (dc_device_t **device, dc_context_t *context, dc_serial_t *serial); + dc_status_t shearwater_predator_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata); diff --git a/src/device.c b/src/device.c index 257dc75..fd6fe9b 100644 --- a/src/device.c +++ b/src/device.c @@ -188,6 +188,12 @@ dc_device_custom_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t case DC_FAMILY_HW_OSTC3: rc = hw_ostc3_device_custom_open (&device, context, serial); break; + case DC_FAMILY_SHEARWATER_PREDATOR: + rc = shearwater_predator_device_custom_open (&device, context, serial); + break; + case DC_FAMILY_SHEARWATER_PETREL: + rc = shearwater_petrel_device_custom_open (&device, context, serial); + break; default: return DC_STATUS_INVALIDARGS; } diff --git a/src/shearwater_common.c b/src/shearwater_common.c index a4e94de..b12bf9b 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -45,7 +45,7 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex int rc = dc_serial_native_open (&device->serial, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - return rc; + return DC_STATUS_IO; } // Set the serial communication protocol (115200 8N1). @@ -71,6 +71,37 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex } +dc_status_t +shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *serial) +{ + // Set the serial reference + device->serial = serial; + + if (serial->type == DC_TRANSPORT_SERIAL) { + // Set the serial communication protocol (115200 8N1). + int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + if (rc == -1) { + ERROR (context, "Failed to set the terminal attributes."); + device->serial->ops->close (device->serial->port); + return DC_STATUS_IO; + } + } + + // Set the timeout for receiving data (3000ms). + if (serial_set_timeout (device->serial->port, 3000) == -1) { + ERROR (context, "Failed to set the timeout."); + device->serial->ops->close (device->serial->port); + return DC_STATUS_IO; + } + + // Make sure everything is in a sane state. + serial_sleep (device->serial->port, 300); + device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + + return DC_STATUS_SUCCESS; +} + + dc_status_t shearwater_common_close (shearwater_common_device_t *device) { diff --git a/src/shearwater_common.h b/src/shearwater_common.h index b930fb9..8e4112f 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -42,6 +42,9 @@ typedef struct shearwater_common_device_t { dc_status_t shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name); +dc_status_t +shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *serial); + dc_status_t shearwater_common_close (shearwater_common_device_t *device); diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 3534a26..e33dc8f 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2013 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -110,6 +111,40 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const c } +dc_status_t +shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + if (out == NULL || serial == NULL || serial->port == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + shearwater_petrel_device_t *device = (shearwater_petrel_device_t *) malloc (sizeof (shearwater_petrel_device_t)); + if (device == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Initialize the base class. + device_init (&device->base.base, context, &shearwater_petrel_device_vtable); + + // Set the default values. + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + // Open the device. + rc = shearwater_common_custom_open (&device->base, context, serial); + if (rc != DC_STATUS_SUCCESS) { + free (device); + return rc; + } + + *out = (dc_device_t *) device; + + return DC_STATUS_SUCCESS; +} + + static dc_status_t shearwater_petrel_device_close (dc_device_t *abstract) { diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index e8a44ac..4901787 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -2,6 +2,7 @@ * libdivecomputer * * Copyright (C) 2012 Jef Driesen + * Copyright (C) 2015 Claudiu Olteanu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -96,6 +97,40 @@ shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const } +dc_status_t +shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + if (out == NULL || serial == NULL || serial->port == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + shearwater_predator_device_t *device = (shearwater_predator_device_t *) malloc (sizeof (shearwater_predator_device_t)); + if (device == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Initialize the base class. + device_init (&device->base.base, context, &shearwater_predator_device_vtable); + + // Set the default values. + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + // Open the device. + rc = shearwater_common_custom_open (&device->base, context, serial); + if (rc != DC_STATUS_SUCCESS) { + free (device); + return rc; + } + + *out = (dc_device_t *) device; + + return DC_STATUS_SUCCESS; +} + + static dc_status_t shearwater_predator_device_close (dc_device_t *abstract) { From d6335c4cf1f2b463784f9f81707858acc3c20ec6 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Tue, 7 Jul 2015 10:48:44 -0700 Subject: [PATCH 24/33] Make it easier to detect our branch of libdivecomputer Signed-off-by: Dirk Hohndel --- include/libdivecomputer/version.h.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/libdivecomputer/version.h.in b/include/libdivecomputer/version.h.in index 6ac63d4..4a29f26 100644 --- a/include/libdivecomputer/version.h.in +++ b/include/libdivecomputer/version.h.in @@ -26,6 +26,10 @@ extern "C" { #endif /* __cplusplus */ +/* use these defines to detect Subsurface specific features */ +#define SSRF_LIBDC_VERSION 1 +#define SSRF_CUSTOM_SERIAL 1 + #define DC_VERSION "@DC_VERSION@" #define DC_VERSION_MAJOR @DC_VERSION_MAJOR@ #define DC_VERSION_MINOR @DC_VERSION_MINOR@ From 68851cea177fdf22c70ce77ddccb2e771c173daa Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 27 Oct 2014 17:19:48 -0700 Subject: [PATCH 25/33] Suunto EON Steel: populate various string data The EON Steel saves the dive computer firmware versions etc per dive, which is really nice for upgrades: old dives done with older firmware still show the firmware at the time of the dive. That, in turn, is nice because we can use it for a reliable dive ID - dive time with serial number etc. This uses the new DC_FIELD_STRING model to feed the hw/sw information to the application, since we need the parser to access it. It also returns battery state and deco model information. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- src/suunto_eonsteel_parser.c | 49 +++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 10577b2..f8322a4 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -68,6 +68,7 @@ struct type_desc { #define MAXTYPE 512 #define MAXGASES 16 +#define MAXSTRINGS 16 typedef struct suunto_eonsteel_parser_t { dc_parser_t base; @@ -82,6 +83,7 @@ typedef struct suunto_eonsteel_parser_t { dc_gasmix_t gasmix[MAXGASES]; dc_salinity_t salinity; double surface_pressure; + dc_field_string_t strings[MAXSTRINGS]; } cache; } suunto_eonsteel_parser_t; @@ -868,6 +870,19 @@ suunto_eonsteel_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback return DC_STATUS_SUCCESS; } +static dc_status_t get_string_field(suunto_eonsteel_parser_t *eon, unsigned idx, dc_field_string_t *value) +{ + if (idx < MAXSTRINGS) { + dc_field_string_t *res = eon->cache.strings+idx; + if (res->desc && res->value) { + *value = *res; + return DC_STATUS_SUCCESS; + } + + } + return DC_STATUS_UNSUPPORTED; +} + // Ugly define thing makes the code much easier to read // I'd love to use __typeof__, but that's a gcc'ism #define field_value(p, set) \ @@ -905,6 +920,8 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi case DC_FIELD_ATMOSPHERIC: field_value(value, eon->cache.surface_pressure); break; + case DC_FIELD_STRING: + return get_string_field(eon, flags, (dc_field_string_t *)value); default: return DC_STATUS_UNSUPPORTED; } @@ -980,6 +997,22 @@ static int add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he) return 0; } +static int add_string(suunto_eonsteel_parser_t *eon, const char *desc, const char *value) +{ + int i; + + eon->cache.initialized |= 1 << DC_FIELD_STRING; + for (i = 0; i < MAXSTRINGS; i++) { + dc_field_string_t *str = eon->cache.strings+i; + if (str->desc) + continue; + str->desc = desc; + str->value = strdup(value); + break; + } + return 0; +} + static float get_le32_float(const unsigned char *src) { union { @@ -1003,7 +1036,16 @@ static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct ty const unsigned char *data, int len) { const char *name = desc->desc + strlen("sml.DeviceLog.Device."); - + if (!strcmp(name, "SerialNumber")) + return add_string(eon, "Serial", data); + if (!strcmp(name, "Info.HW")) + return add_string(eon, "HW Version", data); + if (!strcmp(name, "Info.SW")) + return add_string(eon, "FW Version", data); + if (!strcmp(name, "Info.BatteryAtStart")) + return add_string(eon, "Battery at start", data); + if (!strcmp(name, "Info.BatteryAtEnd")) + return add_string(eon, "Battery at end", data); return 0; } @@ -1070,6 +1112,9 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty return 0; } + if (!strcmp(name, "Algorithm")) + return add_string(eon, "Deco algorithm", data); + return 0; } @@ -1096,6 +1141,8 @@ static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const struct ty eon->cache.maxdepth = d; return 0; } + if (!strcmp(name, "DateTime")) + return add_string(eon, "Dive ID", data); return 0; } From bc983be48485b185abb958131606b9ea5fb7784a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Jan 2015 14:43:46 -0800 Subject: [PATCH 26/33] Add EON Steel dive mode and transmitter ID information This adds the divemode name (Nitrox, Trimix, Gauge, or whatever custon name) and the transmitter ID as extra string information when downloading from the EON Steel. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- src/suunto_eonsteel_parser.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index f8322a4..4d54652 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1105,6 +1105,9 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty if (!strcmp(name, "Gases.Gas.Helium")) return add_gas_he(eon, data[0]); + if (!strcmp(name, "Gases.Gas.TransmitterID")) + return add_string(eon, "Transmitter ID", data); + if (!strcmp(name, "SurfacePressure")) { unsigned int pressure = array_uint32_le(data); // in SI units - Pascal eon->cache.surface_pressure = pressure / 100000.0; // bar @@ -1115,6 +1118,9 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty if (!strcmp(name, "Algorithm")) return add_string(eon, "Deco algorithm", data); + if (!strcmp(name, "DiveMode")) + return add_string(eon, "Dive Mode", data); + return 0; } From f54ea6f4f516d45fffdffd0cd648075107c7cd98 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Jan 2015 17:07:38 -0800 Subject: [PATCH 27/33] Add EON Steel personal adjustment parsing Suunto calls it "Conservatism" in the dump, but "Personal adjustment" in at least some of the documentation. That's what we expose it as. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- src/suunto_eonsteel_parser.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 4d54652..afa99d6 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -21,8 +21,14 @@ #include #include +#include #include +/* Wow. MSC is truly crap */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + #include #include "context-private.h" @@ -1121,6 +1127,15 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty if (!strcmp(name, "DiveMode")) return add_string(eon, "Dive Mode", data); + /* Signed byte of conservatism (-2 .. +2) */ + if (!strcmp(name, "Conservatism")) { + char buffer[10]; + int val = *(signed char *)data; + + snprintf(buffer, sizeof(buffer), "P%d", val); + return add_string(eon, "Personal Adjustment", buffer); + } + return 0; } From 0cd8e0d695f2ab2d6738ce6ee01f6fb47a781da2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Jan 2015 17:09:45 -0800 Subject: [PATCH 28/33] EON Steel: expose the gas switch cylinder in the "flags" field This seems to be the simplest extension to the SAMPLE_EVENT_GASCHANGE2 format: the "value" remains the oddly encoded gas mix, but the "flags" value (if non-zero) now contains the actual cylinder number we switch to. This will need a trivial patch to subsurface to take advantage of the new data too. But then we can actually distinguish between cylinders that have the same gas mix. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- src/suunto_eonsteel_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index afa99d6..86a60c4 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -576,6 +576,7 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.value = o2 | (he << 16); + sample.event.flags = idx; if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); } From 328a599337d5ed85c6ec7c5171f92b1d30863c6e Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Thu, 9 Jul 2015 11:06:08 -0700 Subject: [PATCH 29/33] Revert "Avoid a run-time dependency on the libgcc dlls." This breaks builds with clang This reverts commit bd2b132d7f3c92aa434c4d799e8cc5358bc1baef. --- src/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5172227..0c60d02 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,6 @@ lib_LTLIBRARIES = libdivecomputer.la libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) libdivecomputer_la_LDFLAGS = \ -version-info $(DC_VERSION_LIBTOOL) \ - -Wc,-static-libgcc \ -no-undefined \ -export-symbols libdivecomputer.exp From dfe59b01883ea36dd508daf5c19a98b7f98693e0 Mon Sep 17 00:00:00 2001 From: Gaetan Bisson Date: Wed, 8 Jul 2015 07:14:50 -1000 Subject: [PATCH 30/33] Add new functions to list of exported symbols This is required in order to build those new public functions into the shared library. Signed-off-by: Gaetan Bisson Signed-off-by: Dirk Hohndel --- src/libdivecomputer.symbols | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 562099d..0cef199 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -82,6 +82,9 @@ dc_device_set_events dc_device_set_fingerprint dc_device_write +dc_serial_init +dc_device_custom_open + cressi_edy_device_open cressi_leonardo_device_open mares_nemo_device_open From 0541770a8c01e9835ea3d31d7ccaa6a69895b1b4 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Thu, 13 Aug 2015 01:38:03 +0300 Subject: [PATCH 31/33] Add set_timeout callback for serial custom implementation The new callback will be usefull when we will implement the support for Windows. The implementation of native serial set_timeout method uses a HANDLER on Windows and we will use the WinSock2 API which has a socket descriptor. Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- include/libdivecomputer/custom_serial.h | 1 + src/custom_serial.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/custom_serial.h b/include/libdivecomputer/custom_serial.h index a52d49b..a27d519 100644 --- a/include/libdivecomputer/custom_serial.h +++ b/include/libdivecomputer/custom_serial.h @@ -44,6 +44,7 @@ typedef struct dc_serial_operations_t int (*flush) (serial_t *device, int queue); int (*get_received) (serial_t *device); int (*get_transmitted) (serial_t *device); + int (*set_timeout) (serial_t *device, long timeout); } dc_serial_operations_t; typedef struct dc_serial_t { diff --git a/src/custom_serial.c b/src/custom_serial.c index 6e024b2..a6af432 100644 --- a/src/custom_serial.c +++ b/src/custom_serial.c @@ -32,7 +32,8 @@ const dc_serial_operations_t native_serial_ops = { .write = serial_write, .flush = serial_flush, .get_received = serial_get_received, - .get_transmitted = serial_get_transmitted + .get_transmitted = serial_get_transmitted, + .set_timeout = serial_set_timeout }; From 41ba0daec5e242c9f79c32c5deb49366baf729bd Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Thu, 13 Aug 2015 01:39:14 +0300 Subject: [PATCH 32/33] Use the custom set_timeout callback for HW_OSTC 3 family Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- src/hw_ostc3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 2d975b7..9f4e18c 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -341,7 +341,7 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->serial->port, 3000) == -1) { + if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); device->serial->ops->close (device->serial->port); free (device); From 9b3d34dbf929da7e88c7252922ef1f18dda3b30a Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu Date: Thu, 13 Aug 2015 01:40:32 +0300 Subject: [PATCH 33/33] Use custom set_timeout callback for Shearwater family Signed-off-by: Claudiu Olteanu Signed-off-by: Dirk Hohndel --- src/shearwater_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shearwater_common.c b/src/shearwater_common.c index b12bf9b..0b05e53 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -88,7 +88,7 @@ shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->serial->port, 3000) == -1) { + if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); device->serial->ops->close (device->serial->port); return DC_STATUS_IO;