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. 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..a27d519 --- /dev/null +++ b/include/libdivecomputer/custom_serial.h @@ -0,0 +1,64 @@ +/* + * 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); + int (*set_timeout) (serial_t *device, long timeout); +} 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/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; 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/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/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index c60dc63..8463cb2 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" { @@ -37,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/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/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; diff --git a/include/libdivecomputer/shearwater_petrel.h b/include/libdivecomputer/shearwater_petrel.h index 5092127..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 @@ -34,7 +35,10 @@ 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_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); #ifdef __cplusplus } diff --git a/include/libdivecomputer/shearwater_predator.h b/include/libdivecomputer/shearwater_predator.h index 40c7ae2..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,11 +34,14 @@ 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); 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/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/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@ diff --git a/src/Makefile.am b/src/Makefile.am index f106c09..8ab7d98 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,7 +63,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/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; } diff --git a/src/custom_serial.c b/src/custom_serial.c new file mode 100644 index 0000000..a6af432 --- /dev/null +++ b/src/custom_serial.c @@ -0,0 +1,80 @@ +/* + * 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, + .set_timeout = serial_set_timeout +}; + + +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; +} diff --git a/src/device.c b/src/device.c index d95585d..fd6fe9b 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,33 @@ 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; + 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; + } + + *out = device; + + return rc; +} int dc_device_isinstance (dc_device_t *device, const dc_device_vtable_t *vtable) diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index fa0ec79..c7dfb03 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 @@ -90,7 +91,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; @@ -186,7 +187,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); @@ -194,7 +195,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); @@ -213,7 +214,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); @@ -227,7 +228,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; @@ -236,7 +237,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); @@ -255,7 +256,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); @@ -289,37 +290,90 @@ 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); - if (rc == -1) { + int rc = dc_serial_native_open (&device->serial, context, name); + 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). - 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; + + *out = (dc_device_t *) device; + + return DC_STATUS_SUCCESS; +} + + +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 (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); + 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; @@ -359,17 +413,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); @@ -431,14 +485,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; } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index b3ef2fb..6db9d27 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,13 @@ #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; + typedef struct hw_ostc_sample_info_t { unsigned int type; unsigned int divisor; @@ -72,6 +85,12 @@ typedef struct hw_ostc_layout_t { unsigned int salinity; unsigned int duration; unsigned int temperature; + 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 { @@ -82,6 +101,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; @@ -117,6 +137,12 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 43, /* salinity */ 47, /* duration */ 13, /* temperature */ + 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 = { @@ -128,6 +154,12 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 43, /* salinity */ 47, /* duration */ 19, /* temperature */ + 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 = { @@ -139,6 +171,12 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 70, /* salinity */ 75, /* duration */ 22, /* temperature */ + 50, /* battery volt after dive */ + 26, /* desat */ + 48, /* fw_version */ + 77, /* deco_info1 */ + 78, /* deco_info2 */ + 79, /* decomode */ }; static unsigned int @@ -260,7 +298,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; @@ -288,6 +326,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; @@ -380,6 +419,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 +445,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 +541,56 @@ 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; + case 2: /* fw_version */ + string->desc = "FW Version"; + snprintf(buf, BUFLEN, "%0u.%02u", data[layout->fw_version], data[layout->fw_version + 1]); + break; + case 3: /* serial */ + 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; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } 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 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 4d0d97e..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); @@ -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: @@ -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: @@ -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/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. diff --git a/src/shearwater_common.c b/src/shearwater_common.c index b809a3c..0b05e53 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,61 @@ 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; } // 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; +} + + +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 (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; + } + + // 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; } @@ -74,7 +106,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 +186,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 +215,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 +233,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 +256,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 +275,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..8e4112f 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,12 +36,15 @@ 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 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) { diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index f5ada2b..40b71c7 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 @@ -61,6 +67,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); @@ -89,7 +96,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; @@ -103,6 +110,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); parser->samplesize = SZ_SAMPLE_PETREL; @@ -128,16 +136,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); } @@ -188,6 +196,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) { @@ -291,7 +301,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) { @@ -325,6 +337,24 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ break; case DC_FIELD_DIVEMODE: *((dc_divemode_t *) value) = shearwater_predator_parser_get_divemode (parser); + case DC_FIELD_STRING: + switch(flags) { + 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; + } + string->value = strdup(buf); break; default: return DC_STATUS_UNSUPPORTED; @@ -390,9 +420,11 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal // Status flags. unsigned int status = data[offset + 11]; - // 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); + } if ((status & OC) == 0) { // Setpoint diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 4fd94aa..9931814 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; @@ -188,7 +190,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; @@ -205,6 +207,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; @@ -289,6 +292,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) @@ -304,6 +308,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) { @@ -349,6 +356,17 @@ 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, "%08u", parser->serial); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 10577b2..86a60c4 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" @@ -68,6 +74,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 +89,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; @@ -568,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); } @@ -868,6 +877,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 +927,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 +1004,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 +1043,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; } @@ -1063,6 +1112,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 @@ -1070,6 +1122,21 @@ 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); + + 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; } @@ -1096,6 +1163,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; }