From 4b887341f3cf4f51da4ae5eeb303d04a5c3c5e81 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 27 Jan 2011 16:53:30 +0100 Subject: [PATCH] Add support for the Atomics Cobalt. --- examples/universal.c | 10 +- src/Makefile.am | 6 +- src/atomics.h | 27 +++++ src/atomics_cobalt.c | 170 ++++++++++++++++++++++++++++ src/atomics_cobalt.h | 41 +++++++ src/atomics_cobalt_parser.c | 218 ++++++++++++++++++++++++++++++++++++ src/device.h | 3 +- src/libdivecomputer.symbols | 2 + src/parser.h | 3 +- 9 files changed, 476 insertions(+), 4 deletions(-) create mode 100644 src/atomics.h create mode 100644 src/atomics_cobalt.c create mode 100644 src/atomics_cobalt.h create mode 100644 src/atomics_cobalt_parser.c diff --git a/examples/universal.c b/examples/universal.c index cb70fc2..3f18685 100644 --- a/examples/universal.c +++ b/examples/universal.c @@ -42,6 +42,7 @@ #include #include #include +#include #include static const char *g_cachedir = NULL; @@ -90,7 +91,8 @@ static const backend_table_t g_backends[] = { {"iconhd", DEVICE_TYPE_MARES_ICONHD}, {"ostc", DEVICE_TYPE_HW_OSTC}, {"edy", DEVICE_TYPE_CRESSI_EDY}, - {"n2ition3", DEVICE_TYPE_ZEAGLE_N2ITION3} + {"n2ition3", DEVICE_TYPE_ZEAGLE_N2ITION3}, + {"cobalt", DEVICE_TYPE_ATOMICS_COBALT} }; static device_type_t @@ -340,6 +342,9 @@ doparse (FILE *fp, device_data_t *devdata, const unsigned char data[], unsigned case DEVICE_TYPE_ZEAGLE_N2ITION3: rc = cressi_edy_parser_create (&parser, devdata->devinfo.model); break; + case DEVICE_TYPE_ATOMICS_COBALT: + rc = atomics_cobalt_parser_create (&parser); + break; default: rc = PARSER_STATUS_ERROR; break; @@ -662,6 +667,9 @@ dowork (device_type_t backend, const char *devname, const char *rawfile, const c case DEVICE_TYPE_ZEAGLE_N2ITION3: rc = zeagle_n2ition3_device_open (&device, devname); break; + case DEVICE_TYPE_ATOMICS_COBALT: + rc = atomics_cobalt_device_open (&device); + break; default: rc = DEVICE_STATUS_ERROR; break; diff --git a/src/Makefile.am b/src/Makefile.am index 0cd74ec..a0724ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,7 +38,9 @@ libdivecomputer_HEADERS = \ cressi.h \ cressi_edy.h \ zeagle.h \ - zeagle_n2ition3.h + zeagle_n2ition3.h \ + atomics.h \ + atomics_cobalt.h # # Source files. @@ -88,6 +90,8 @@ libdivecomputer_la_SOURCES = \ cressi_edy.h cressi_edy.c cressi_edy_parser.c \ zeagle.h \ zeagle_n2ition3.h zeagle_n2ition3.c \ + atomics.h \ + atomics_cobalt.h atomics_cobalt.c atomics_cobalt_parser.c \ ringbuffer.h ringbuffer.c \ checksum.h checksum.c \ array.h array.c \ diff --git a/src/atomics.h b/src/atomics.h new file mode 100644 index 0000000..eefb002 --- /dev/null +++ b/src/atomics.h @@ -0,0 +1,27 @@ +/* + * libdivecomputer + * + * Copyright (C) 2011 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 ATOMICS_H +#define ATOMICS_H + +#include "atomics_cobalt.h" + +#endif /* ATOMICS_H */ diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c new file mode 100644 index 0000000..2af6a0c --- /dev/null +++ b/src/atomics_cobalt.c @@ -0,0 +1,170 @@ +/* + * libdivecomputer + * + * Copyright (C) 2011 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 // memcmp, memcpy +#include // malloc, free + +#include "device-private.h" +#include "atomics_cobalt.h" +#include "checksum.h" +#include "utils.h" +#include "array.h" + +#define FP_OFFSET 20 + +typedef struct atomics_cobalt_device_t { + device_t base; + unsigned char fingerprint[6]; +} atomics_cobalt_device_t; + +static device_status_t atomics_cobalt_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size); +static device_status_t atomics_cobalt_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata); +static device_status_t atomics_cobalt_device_close (device_t *abstract); + +static const device_backend_t atomics_cobalt_device_backend = { + DEVICE_TYPE_ATOMICS_COBALT, + atomics_cobalt_device_set_fingerprint, /* set_fingerprint */ + NULL, /* version */ + NULL, /* read */ + NULL, /* write */ + NULL, /* dump */ + atomics_cobalt_device_foreach, /* foreach */ + atomics_cobalt_device_close /* close */ +}; + +static int +device_is_atomics_cobalt (device_t *abstract) +{ + if (abstract == NULL) + return 0; + + return abstract->backend == &atomics_cobalt_device_backend; +} + + +device_status_t +atomics_cobalt_device_open (device_t **out) +{ + if (out == NULL) + return DEVICE_STATUS_ERROR; + + // Allocate memory. + atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t)); + if (device == NULL) { + WARNING ("Failed to allocate memory."); + return DEVICE_STATUS_MEMORY; + } + + // Initialize the base class. + device_init (&device->base, &atomics_cobalt_device_backend); + + // Set the default values. + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + *out = (device_t*) device; + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +atomics_cobalt_device_close (device_t *abstract) +{ + atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; + + if (! device_is_atomics_cobalt (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // Free memory. + free (device); + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +atomics_cobalt_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size) +{ + atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; + + if (! device_is_atomics_cobalt (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + if (size && size != sizeof (device->fingerprint)) + return DEVICE_STATUS_ERROR; + + if (size) + memcpy (device->fingerprint, data, sizeof (device->fingerprint)); + else + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +atomics_cobalt_read_dive (device_t *abstract, dc_buffer_t *buffer, int init) +{ + return DEVICE_STATUS_UNSUPPORTED; +} + + +static device_status_t +atomics_cobalt_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata) +{ + atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; + + if (! device_is_atomics_cobalt (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // Allocate a memory buffer. + dc_buffer_t *buffer = dc_buffer_new (0); + if (buffer == NULL) + return DEVICE_STATUS_MEMORY; + + unsigned int ndives = 0; + device_status_t rc = DEVICE_STATUS_SUCCESS; + while ((rc = atomics_cobalt_read_dive (abstract, buffer, (ndives == 0))) == DEVICE_STATUS_SUCCESS) { + unsigned char *data = dc_buffer_get_data (buffer); + unsigned int size = dc_buffer_get_size (buffer); + + if (size == 0) { + dc_buffer_free (buffer); + return DEVICE_STATUS_SUCCESS; + } + + if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) { + dc_buffer_free (buffer); + return DEVICE_STATUS_SUCCESS; + } + + if (callback && !callback (data, size, data + FP_OFFSET, sizeof (device->fingerprint), userdata)) { + dc_buffer_free (buffer); + return DEVICE_STATUS_SUCCESS; + } + + ndives++; + } + + dc_buffer_free (buffer); + + return rc; +} diff --git a/src/atomics_cobalt.h b/src/atomics_cobalt.h new file mode 100644 index 0000000..88ea14e --- /dev/null +++ b/src/atomics_cobalt.h @@ -0,0 +1,41 @@ +/* + * libdivecomputer + * + * Copyright (C) 2011 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 ATOMICS_COBALT_H +#define ATOMICS_COBALT_H + +#include "device.h" +#include "parser.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +device_status_t +atomics_cobalt_device_open (device_t **device); + +parser_status_t +atomics_cobalt_parser_create (parser_t **parser); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ATOMICS_COBALT_H */ diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c new file mode 100644 index 0000000..596aa31 --- /dev/null +++ b/src/atomics_cobalt_parser.c @@ -0,0 +1,218 @@ +/* + * libdivecomputer + * + * Copyright (C) 2011 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 "atomics_cobalt.h" +#include "parser-private.h" +#include "utils.h" +#include "array.h" +#include "units.h" + +#define SZ_HEADER 228 +#define SZ_GASMIX 18 +#define SZ_GASSWITCH 6 +#define SZ_SEGMENT 16 + +typedef struct atomics_cobalt_parser_t atomics_cobalt_parser_t; + +struct atomics_cobalt_parser_t { + parser_t base; +}; + +static parser_status_t atomics_cobalt_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size); +static parser_status_t atomics_cobalt_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime); +static parser_status_t atomics_cobalt_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value); +static parser_status_t atomics_cobalt_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata); +static parser_status_t atomics_cobalt_parser_destroy (parser_t *abstract); + +static const parser_backend_t atomics_cobalt_parser_backend = { + PARSER_TYPE_ATOMICS_COBALT, + atomics_cobalt_parser_set_data, /* set_data */ + atomics_cobalt_parser_get_datetime, /* datetime */ + atomics_cobalt_parser_get_field, /* fields */ + atomics_cobalt_parser_samples_foreach, /* samples_foreach */ + atomics_cobalt_parser_destroy /* destroy */ +}; + + +static int +parser_is_atomics_cobalt (parser_t *abstract) +{ + if (abstract == NULL) + return 0; + + return abstract->backend == &atomics_cobalt_parser_backend; +} + + +parser_status_t +atomics_cobalt_parser_create (parser_t **out) +{ + if (out == NULL) + return PARSER_STATUS_ERROR; + + // Allocate memory. + atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t *) malloc (sizeof (atomics_cobalt_parser_t)); + if (parser == NULL) { + WARNING ("Failed to allocate memory."); + return PARSER_STATUS_MEMORY; + } + + // Initialize the base class. + parser_init (&parser->base, &atomics_cobalt_parser_backend); + + *out = (parser_t*) parser; + + return PARSER_STATUS_SUCCESS; +} + + +static parser_status_t +atomics_cobalt_parser_destroy (parser_t *abstract) +{ + if (! parser_is_atomics_cobalt (abstract)) + return PARSER_STATUS_TYPE_MISMATCH; + + // Free memory. + free (abstract); + + return PARSER_STATUS_SUCCESS; +} + + +static parser_status_t +atomics_cobalt_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size) +{ + if (! parser_is_atomics_cobalt (abstract)) + return PARSER_STATUS_TYPE_MISMATCH; + + return PARSER_STATUS_SUCCESS; +} + + +static parser_status_t +atomics_cobalt_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) +{ + if (abstract->size < SZ_HEADER) + return PARSER_STATUS_ERROR; + + const unsigned char *p = abstract->data; + + if (datetime) { + datetime->year = array_uint16_le (p + 0x14); + datetime->month = p[0x16]; + datetime->day = p[0x17]; + datetime->hour = p[0x18]; + datetime->minute = p[0x19]; + datetime->second = 0; + } + + return PARSER_STATUS_SUCCESS; +} + + +static parser_status_t +atomics_cobalt_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value) +{ + if (abstract->size < SZ_HEADER) + return PARSER_STATUS_ERROR; + + const unsigned char *p = abstract->data; + + gasmix_t *gasmix = (gasmix_t *) value; + + if (value) { + switch (type) { + case FIELD_TYPE_DIVETIME: + *((unsigned int *) value) = array_uint16_le (p + 0x58) * 60; + break; + case FIELD_TYPE_MAXDEPTH: + *((double *) value) = (array_uint16_le (p + 0x56) - 1000.0) / 100.0; + break; + case FIELD_TYPE_GASMIX_COUNT: + *((unsigned int *) value) = p[0x2a]; + break; + case FIELD_TYPE_GASMIX: + gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0; + gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0; + gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; + break; + default: + return PARSER_STATUS_UNSUPPORTED; + } + } + + return PARSER_STATUS_SUCCESS; +} + + +static parser_status_t +atomics_cobalt_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) +{ + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + if (size < SZ_HEADER) + return PARSER_STATUS_ERROR; + + unsigned int interval = data[0x1a]; + unsigned int ngasmixes = data[0x2a]; + unsigned int nswitches = data[0x2b]; + unsigned int nsegments = array_uint16_le (data + 0x50); + + unsigned int header = SZ_HEADER + SZ_GASMIX * ngasmixes + + SZ_GASSWITCH * nswitches; + + if (size < header + SZ_SEGMENT * nsegments) + return PARSER_STATUS_ERROR; + + unsigned int time = 0; + unsigned int offset = header; + while (offset + SZ_SEGMENT <= size) { + parser_sample_value_t sample = {0}; + + // Time (seconds). + time += interval; + sample.time = time; + if (callback) callback (SAMPLE_TYPE_TIME, sample, userdata); + + // Depth (1/1000 bar). + unsigned int depth = array_uint16_le (data + offset + 0); + sample.depth = (depth - 1000.0) / 100.0; + if (callback) callback (SAMPLE_TYPE_DEPTH, sample, userdata); + + // Pressure (1 psi). + unsigned int pressure = array_uint16_le (data + offset + 2); + sample.pressure.tank = 0; + sample.pressure.value = pressure * PSI / BAR; + if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); + + // Temperature (1 °F). + unsigned int temperature = data[offset + 8]; + sample.temperature = (temperature - 32.0) * (5.0 / 9.0); + if (callback) callback (SAMPLE_TYPE_TEMPERATURE, sample, userdata); + + offset += SZ_SEGMENT; + } + + return PARSER_STATUS_SUCCESS; +} diff --git a/src/device.h b/src/device.h index b119200..bc7c4aa 100644 --- a/src/device.h +++ b/src/device.h @@ -50,7 +50,8 @@ typedef enum device_type_t { DEVICE_TYPE_MARES_ICONHD, DEVICE_TYPE_HW_OSTC, DEVICE_TYPE_CRESSI_EDY, - DEVICE_TYPE_ZEAGLE_N2ITION3 + DEVICE_TYPE_ZEAGLE_N2ITION3, + DEVICE_TYPE_ATOMICS_COBALT } device_type_t; typedef enum device_status_t { diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 93cb1d9..d790fc0 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -42,6 +42,7 @@ oceanic_veo250_parser_create oceanic_atom2_parser_create hw_ostc_parser_create cressi_edy_parser_create +atomics_cobalt_parser_create device_close device_dump @@ -114,3 +115,4 @@ uwatec_smart_extract_dives hw_ostc_device_open hw_ostc_extract_dives zeagle_n2ition3_device_open +atomics_cobalt_device_open diff --git a/src/parser.h b/src/parser.h index 2b58bac..5f9c060 100644 --- a/src/parser.h +++ b/src/parser.h @@ -45,7 +45,8 @@ typedef enum parser_type_t { PARSER_TYPE_OCEANIC_VEO250, PARSER_TYPE_OCEANIC_ATOM2, PARSER_TYPE_HW_OSTC, - PARSER_TYPE_CRESSI_EDY + PARSER_TYPE_CRESSI_EDY, + PARSER_TYPE_ATOMICS_COBALT } parser_type_t; typedef enum parser_status_t {