[PATCH 7/8] Renamed Cochran backend
John Van Ostrand
john at vanostrand.com
Sun Nov 2 18:52:33 PST 2014
Family is not COCHRAN_COMMANDER and functions are cochran_commander_*.
---
examples/cochran_download.c | 2 +-
include/libdivecomputer/cochran.h | 19 +-
include/libdivecomputer/cochran_commander.h | 44 ++
include/libdivecomputer/common.h | 2 +-
src/Makefile.am | 4 +-
src/cochran_cmdr_parser.c | 6 +-
src/cochran_commander.c | 890 ++++++++++++++++++++++++++++
src/cochran_commander.h | 157 +++++
src/cochran_commander_parser.c | 218 +++++++
src/cochran_commander_parser.h | 115 ++++
src/cochran_common.c | 890 ----------------------------
src/cochran_common.h | 157 -----
src/cochran_common_parser.c | 218 -------
src/cochran_common_parser.h | 115 ----
src/cochran_emc_parser.c | 6 +-
src/descriptor.c | 6 +-
src/device.c | 4 +-
src/parser.c | 4 +-
18 files changed, 1442 insertions(+), 1415 deletions(-)
create mode 100644 include/libdivecomputer/cochran_commander.h
create mode 100644 src/cochran_commander.c
create mode 100644 src/cochran_commander.h
create mode 100644 src/cochran_commander_parser.c
create mode 100644 src/cochran_commander_parser.h
delete mode 100644 src/cochran_common.c
delete mode 100644 src/cochran_common.h
delete mode 100644 src/cochran_common_parser.c
delete mode 100644 src/cochran_common_parser.h
diff --git a/examples/cochran_download.c b/examples/cochran_download.c
index a9253af..01df25d 100644
--- a/examples/cochran_download.c
+++ b/examples/cochran_download.c
@@ -309,7 +309,7 @@ main (int argc, char *argv[])
extern int optind, opterr, optopt;
// Default values.
- dc_family_t backend = DC_FAMILY_COCHRAN;
+ dc_family_t backend = DC_FAMILY_COCHRAN_COMMANDER;
// Command line arguments
const char *devname = NULL, *dirname;
diff --git a/include/libdivecomputer/cochran.h b/include/libdivecomputer/cochran.h
index 90b1bb5..a2a0962 100644
--- a/include/libdivecomputer/cochran.h
+++ b/include/libdivecomputer/cochran.h
@@ -22,23 +22,6 @@
#ifndef COCHRAN_H
#define COCHRAN_H
-#include "context.h"
-#include "device.h"
-#include "parser.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-dc_status_t
-cochran_common_device_open (dc_device_t **device, dc_context_t *context,
- const char *name);
-
-dc_status_t
-cochran_common_parser_create (dc_parser_t **parser, dc_context_t *context);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+#include "cochran_commander.h"
#endif /* COCHRAN_H */
diff --git a/include/libdivecomputer/cochran_commander.h b/include/libdivecomputer/cochran_commander.h
new file mode 100644
index 0000000..143c451
--- /dev/null
+++ b/include/libdivecomputer/cochran_commander.h
@@ -0,0 +1,44 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 John Van Ostrand
+ *
+ * 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 COCHRAN_COMMANDER_H
+#define COCHRAN_COMMANDER_H
+
+#include "context.h"
+#include "device.h"
+#include "parser.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+dc_status_t
+cochran_commander_device_open (dc_device_t **device, dc_context_t *context,
+ const char *name);
+
+dc_status_t
+cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* COCHRAN_COMMANDER_H */
diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h
index 218548f..a2ff47f 100644
--- a/include/libdivecomputer/common.h
+++ b/include/libdivecomputer/common.h
@@ -84,7 +84,7 @@ typedef enum dc_family_t {
/* Dive Rite */
DC_FAMILY_DIVERITE_NITEKQ = (11 << 16),
/* Cochran */
- DC_FAMILY_COCHRAN = (12 << 16),
+ DC_FAMILY_COCHRAN_COMMANDER = (12 << 16),
} dc_family_t;
#ifdef __cplusplus
diff --git a/src/Makefile.am b/src/Makefile.am
index 33d4713..33bd5e2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,8 +56,8 @@ libdivecomputer_la_SOURCES = \
checksum.h checksum.c \
array.h array.c \
buffer.c \
- cochran_common.h cochran_common.c \
- cochran_common_parser.h cochran_common_parser.c \
+ cochran_commander.h cochran_commander.c \
+ cochran_commander_parser.h cochran_commander_parser.c \
cochran_cmdr_parser.c cochran_emc_parser.c
if OS_WIN32
diff --git a/src/cochran_cmdr_parser.c b/src/cochran_cmdr_parser.c
index 8b94fcf..7cfd650 100644
--- a/src/cochran_cmdr_parser.c
+++ b/src/cochran_cmdr_parser.c
@@ -31,8 +31,8 @@
#include "serial.h"
#include "array.h"
-#include "cochran_common.h"
-#include "cochran_common_parser.h"
+#include "cochran_commander.h"
+#include "cochran_commander_parser.h"
#define SZ_SAMPLE 2
@@ -151,7 +151,7 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
// Check for event
if (s[0] & 0x80) {
- offset += cochran_common_handle_event(abstract, callback, userdata,
+ offset += cochran_commander_handle_event(abstract, callback, userdata,
s[0], offset, time);
if (s[0] == 0xC5)
deco_obligation = 1; // Deco obligation begins
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
new file mode 100644
index 0000000..fc25932
--- /dev/null
+++ b/src/cochran_commander.c
@@ -0,0 +1,890 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 John Van Ostrand
+ *
+ * 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 <string.h> // memcpy, memcmp
+#include <stdlib.h> // malloc, free
+#include <assert.h> // assert
+#include <time.h>
+
+#include <libdivecomputer/cochran.h>
+
+#include "context-private.h"
+#include "device-private.h"
+#include "serial.h"
+#include "array.h"
+
+#include "cochran_commander.h"
+
+
+#define EXITCODE(rc) \
+( \
+ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
+)
+
+static const dc_device_vtable_t cochran_commander_device_vtable = {
+ DC_FAMILY_COCHRAN_COMMANDER,
+ cochran_commander_device_set_fingerprint, /* set_fingerprint */
+ cochran_commander_device_read, /* read */
+ NULL, /* write */
+ cochran_commander_device_dump, /* dump */
+ cochran_commander_device_foreach, /* foreach */
+ cochran_commander_device_close /* close */
+};
+
+
+dc_status_t
+cochran_packet (cochran_device_t *device, const unsigned char command[],
+ unsigned int csize, unsigned char answer[], unsigned int asize,
+ int high_speed)
+{
+ dc_device_t *abstract = (dc_device_t *) device;
+ unsigned int bytes_read = 0, n, read_size;
+ unsigned int ptr;
+
+ if (device_is_cancelled (abstract))
+ return DC_STATUS_CANCELLED;
+
+ // Send the command to the device, one byte at a time
+ for (ptr = 0; ptr < csize; ptr++) {
+ if (ptr) serial_sleep(device->port, 16); // 16 ms
+ n = serial_write(device->port, command + ptr, 1);
+ if (n != 1) {
+ ERROR (abstract->context, "Failed to send the command.");
+ return EXITCODE (n);
+ }
+ }
+
+ if (high_speed) {
+ serial_sleep(device->port, 45);
+
+ // Weird but I only get the right result when I do it twice
+ // Rates are odd, like 825600 for the EMC, 115200 for commander
+ serial_configure(device->port, device->data.high_baud, 8,
+ SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
+ serial_configure(device->port, device->data.high_baud, 8,
+ SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
+ }
+
+ // Receive the answer from the device.
+ // Use 1024 byte "packets" so we can display progress.
+ while (bytes_read < asize) {
+ if (asize - bytes_read > 1024)
+ read_size = 1024;
+ else
+ read_size = asize - bytes_read;
+
+ n = serial_read (device->port, answer + bytes_read, read_size);
+ if (n != read_size) {
+ ERROR (abstract->context, "Failed to receive data, expected %u,"
+ "read %u.", read_size, n);
+ return EXITCODE (n);
+ }
+
+ bytes_read += n;
+
+ if (device->progress) {
+ device->progress->current = bytes_read;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
+ }
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+cochran_commander_serial_setup (cochran_device_t *device, dc_context_t *context)
+{
+ int rc;
+
+ // Set the serial communication protocol (9600 8N2, no FC).
+ rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE,
+ 2, SERIAL_FLOWCONTROL_NONE);
+ if (rc == -1) {
+ ERROR (context, "Failed to set the terminal attributes.");
+ serial_close (device->port);
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ serial_set_queue_size(device->port, 4096, 4096);
+
+ // Make sure everything is in a sane state.
+ // Mimicing Analyst software with excessive flushes
+ serial_flush (device->port, SERIAL_QUEUE_OUTPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+ serial_flush (device->port, SERIAL_QUEUE_INPUT);
+
+ serial_set_break(device->port, 1);
+ serial_sleep(device->port, 16);
+
+ serial_set_break(device->port, 0);
+
+ // Set the timeout for receiving data (5000 ms).
+ if (serial_set_timeout (device->port, 5000) == -1) {
+ ERROR (context, "Failed to set the timeout.");
+ serial_close (device->port);
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Wait for heartbeat byte before send
+ int n;
+ char answer[1];
+ if ((n = serial_read(device->port, answer, 1)) != 1) {
+ ERROR (context, "Failed to receive device heartbeat.");
+ return EXITCODE (n);
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_serial_open(cochran_device_t *device, dc_context_t *context)
+{
+ // Open the device.
+ int rc = serial_open (&device->port, context, device->name);
+ if (rc == -1) {
+ ERROR (context, "Failed to open the serial port.");
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ return cochran_commander_serial_setup(device, context);
+}
+
+
+dc_status_t
+cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
+ const char *name)
+{
+ dc_status_t rc;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ cochran_device_t *device = (cochran_device_t *) malloc (
+ sizeof (cochran_device_t));
+ if (device == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Initialize the base class.
+ device_init (&device->base, context, &cochran_commander_device_vtable);
+
+ // Set the default values.
+ device->port = NULL;
+ device->name = name;
+ device->progress = NULL;
+ device->data.logbook = NULL;
+ device->data.sample = NULL;
+ cochran_commander_device_set_fingerprint((dc_device_t *) device, "", 0);
+
+ if ((rc = cochran_commander_serial_open(device, context))
+ != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Read ID from the device
+ rc = cochran_read_id((dc_device_t *) device);
+
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (context, "Device not responding.");
+ serial_close (device->port);
+ free (device);
+ return rc;
+ }
+
+ // Check ID
+ if ((device->data.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
+ ERROR (context, "Device not recognized.");
+ serial_close (device->port);
+ free (device);
+ return DC_STATUS_UNSUPPORTED;
+ }
+
+ *out = (dc_device_t *) device;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_device_close (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t*) abstract;
+
+ // Close the device.
+ if (serial_close (device->port) == -1) {
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Free memory.
+ free (device->data.logbook);
+ free (device->data.sample);
+ free (device);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_device_set_fingerprint (dc_device_t *abstract,
+ const unsigned char data[], unsigned int size)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = &(device->data);
+
+ if (size && size != sizeof (d->fingerprint))
+ return DC_STATUS_INVALIDARGS;
+
+ if (size)
+ memcpy (&(d->fingerprint), data, sizeof (d->fingerprint));
+ else
+ memset (&(d->fingerprint), 0xFF, sizeof (d->fingerprint));
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_device_read (dc_device_t *abstract, unsigned int address,
+ unsigned char data[], unsigned int size)
+{
+ cochran_device_t *device = (cochran_device_t*) abstract;
+
+ // Build the command
+ unsigned char command[10];
+ unsigned char command_size;
+
+ switch (device->data.address_length)
+ {
+ case COCHRAN_ADDRESS_LENGTH_32:
+ // EMC uses 32 bit addressing
+ command[0] = 0x15;
+ command[1] = (address ) & 0xff;
+ command[2] = (address >> 8) & 0xff;
+ command[3] = (address >> 16) & 0xff;
+ command[4] = (address >> 24) & 0xff;
+ command[5] = (size ) & 0xff;
+ command[6] = (size >> 8 ) & 0xff;
+ command[7] = (size >> 16 ) & 0xff;
+ command[8] = (size >> 24 ) & 0xff;
+ command[9] = 0x05;
+ command_size = 10;
+ break;
+ case COCHRAN_ADDRESS_LENGTH_24:
+ // Commander uses 24 byte addressing
+ command[0] = 0x15;
+ command[1] = (address ) & 0xff;
+ command[2] = (address >> 8) & 0xff;
+ command[3] = (address >> 16) & 0xff;
+ command[4] = (size ) & 0xff;
+ command[5] = (size >> 8 ) & 0xff;
+ command[6] = (size >> 16 ) & 0xff;
+ command[7] = 0x04;
+ command_size = 8;
+ break; default:
+ return DC_STATUS_UNSUPPORTED;
+ }
+
+ // Read data at high speed
+ dc_status_t rc = cochran_packet (device, command, command_size, data,
+ size, 1);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static void
+cochran_set_device_config (cochran_device_t *device)
+{
+ dc_device_t *abstract = (dc_device_t *) device;
+ // Determine model
+ if (memcmp(device->data.id + 0x3B, "AM2315\xA3\x71", 8) == 0)
+ {
+ device->data.model = COCHRAN_MODEL_EMC_20;
+ device->data.log_size = 512;
+ device->data.sample_memory_start_address = 0x94000;
+ device->data.dive_num_ptr = 0x56;
+ device->data.dive_count_ptr = 0xD2;
+ device->data.dive_count_endian = COCHRAN_LE_TYPE;
+ device->data.sample_end_ptr = 256;
+ device->data.log_pre_dive_ptr = 30;
+ device->data.log_end_dive_ptr = 256;
+ device->data.last_interdive_ptr = 233;
+ device->data.last_entry_ptr = 194;
+ device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+ device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
+ device->data.high_baud = 825600;
+ }
+ else if (memcmp(device->data.id + 0x3B, "AMA315\xC3\xC5", 8) == 0)
+ {
+ device->data.model = COCHRAN_MODEL_EMC_16;
+ device->data.log_size = 512;
+ device->data.sample_memory_start_address = 0x94000;
+ device->data.dive_num_ptr = 0x56;
+ device->data.dive_count_ptr = 0xD2;
+ device->data.dive_count_endian = COCHRAN_LE_TYPE;
+ device->data.sample_end_ptr = 256;
+ device->data.log_pre_dive_ptr = 30;
+ device->data.log_end_dive_ptr = 256;
+ device->data.last_interdive_ptr = 233;
+ device->data.last_entry_ptr = 194;
+ device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+ device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
+ device->data.high_baud = 825600;
+ }
+ else if (memcmp(device->data.id + 0x3B, "AM\x11""2212\x02", 8) == 0)
+ {
+ device->data.model = COCHRAN_MODEL_COMMANDER_AIR_NITROX;
+ device->data.log_size = 256;
+ device->data.sample_memory_start_address = 0x20000;
+ device->data.dive_num_ptr = 0x46;
+ device->data.dive_count_ptr = 0x46;
+ device->data.dive_count_endian = COCHRAN_BE_TYPE;
+ device->data.sample_end_ptr = 256;
+ device->data.log_pre_dive_ptr = 30;
+ device->data.log_end_dive_ptr = 128;
+ device->data.last_interdive_ptr = 167;
+ device->data.last_entry_ptr = -1;
+ device->data.date_format = COCHRAN_DATE_FORMAT_MSDHYM;
+ device->data.address_length = COCHRAN_ADDRESS_LENGTH_24;
+ device->data.high_baud = 115200;
+ }
+ else
+ {
+ device->data.model = 0;
+ ERROR (abstract->context,
+ "Unknown Cochran model %02x %02x %02x %02x %02x %02x %02x %02x",
+ *(device->data.id + 0x3B), *(device->data.id + 0x3B + 1),
+ *(device->data.id + 0x3B + 2), *(device->data.id + 0x3B + 3),
+ *(device->data.id + 0x3B + 4), *(device->data.id + 0x3B + 5),
+ *(device->data.id + 0x3B + 6), *(device->data.id + 0x3B + 7));
+ }
+
+ return;
+}
+
+
+static dc_status_t
+cochran_read_id (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ dc_status_t rc;
+ unsigned char command[6] = {0x05, 0x9D, 0xFF, 0x00, 0x43, 0x00};
+
+ rc = cochran_packet(device, command, 6, device->data.id, 67, 0);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ if (strncmp(device->data.id, "(C)", 3) != 0) {
+ // It's a Commander, read again
+ memcpy(device->data.id0, device->data.id, 67);
+
+ command[1] = 0xBD;
+ command[2] = 0x7F;
+
+ rc = cochran_packet(device, command, 6, device->data.id, 67, 0);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+ }
+
+ cochran_set_device_config(device);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+cochran_read_config (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *data = &device->data;
+ dc_status_t rc;
+ unsigned char command[2] = { 0x96, 0x00 };
+
+ if ((data->model & 0xFF0000) == COCHRAN_MODEL_EMC_FAMILY)
+ data->config_count = 2;
+ else
+ data->config_count = 4;
+
+ int n;
+ for (n = 0; n < data->config_count; n++) {
+ command[1] = n;
+ rc = cochran_packet(device, command, 2, data->config[n], 512, 0);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+cochran_read_misc (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+
+ unsigned char command[7] = { 0x89, 0x05, 0x00, 0x00, 0x00, 0xDC, 0x05 };
+
+ switch (device->data.model & 0xFF0000)
+ {
+ case COCHRAN_MODEL_COMMANDER_FAMILY:
+ command[2] = 0xCA;
+ command[3] = 0xFD;
+ break;
+ case COCHRAN_MODEL_EMC_FAMILY:
+ command[2] = 0xE0;
+ command[3] = 0x03;
+ break;
+ default:
+ return DC_STATUS_UNSUPPORTED;
+ }
+
+ // Send first byte then wait for heartbeat before sending the rest
+ serial_write(device->port, command, 1);
+
+ int n;
+ char answer[1];
+ if ((n = serial_read(device->port, answer, 1)) != 1) {
+ ERROR (abstract->context, "Failed to receive device heartbeat.");
+ return EXITCODE (n);
+ }
+
+ return cochran_packet(device, command + 1, 6, device->data.misc, 1500, 0);
+}
+
+
+static dc_status_t
+cochran_read_logbook (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = &(device->data);
+ dc_status_t rc;
+
+ if (d->logbook)
+ free(d->logbook);
+
+ // Allocate space for log book.
+ d->logbook = (unsigned char *) malloc(d->logbook_size);
+ if (device == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Enable progress notifications.
+ device->progress = malloc(sizeof(dc_event_progress_t));
+ if (device->progress == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ device->progress->current = 0;
+ device->progress->maximum = d->logbook_size;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
+
+ serial_sleep(device->port, 800);
+
+ // set back to 9600 baud
+ cochran_commander_serial_setup(device, abstract->context);
+
+ // Request log book
+ rc = cochran_commander_device_read(abstract, 0, d->logbook, d->logbook_size);
+
+ device->progress->current = d->logbook_size;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
+ free (device->progress);
+
+ return rc;
+}
+
+
+static void
+cochran_find_fingerprint(dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = (cochran_data_t *) &(device->data);
+
+ // Skip to fingerprint to reduce time
+ d->fp_dive_num = d->dive_count - 1;
+
+ while (d->fp_dive_num >= 0 && memcmp(&(d->fingerprint),
+ d->logbook + d->fp_dive_num * d->log_size
+ + d->dive_num_ptr,
+ sizeof(d->fingerprint)))
+ d->fp_dive_num--;
+}
+
+
+static void
+cochran_get_sample_parms(dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = (cochran_data_t *) &(device->data);
+ unsigned int pre_dive_offset, end_dive_offset;
+ unsigned int low_offset, high_offset;
+
+ // Find lowest and highest offsets into sample data
+ low_offset = 0xFFFFFFFF;
+ high_offset = 0;
+
+ int i;
+ for (i = d->fp_dive_num + 1; i < d->dive_count; i++) {
+ pre_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
+ + d->log_pre_dive_ptr]));
+ end_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
+ + d->log_end_dive_ptr]));
+
+ // Check for ring buffer wrap-around.
+ if (pre_dive_offset > end_dive_offset)
+ break;
+
+ if (pre_dive_offset < low_offset)
+ low_offset = pre_dive_offset;
+ if (end_dive_offset > high_offset && end_dive_offset != 0xFFFFFFFF )
+ high_offset = end_dive_offset;
+ }
+
+ if (pre_dive_offset > end_dive_offset) {
+ // Since I can't tell how much memory it has, I'll round.
+ // I'll round to 128K, dives longer than 12 hrs aren't likely
+ // and memory in sizes not rounded to 128K might be odd.
+ high_offset = ((pre_dive_offset - 1) & 0xE0000) + 0x20000;
+ d->sample_memory_end_address = high_offset;
+ low_offset = d->sample_memory_start_address;
+ d->sample_data_offset = low_offset;
+ d->sample_size = high_offset - low_offset;
+ } else if (low_offset < 0xFFFFFFFF && high_offset > 0) {
+ // Round offset and size to 16K boundary
+ d->sample_data_offset = low_offset & 0xFFFFC000;
+ high_offset = ((high_offset - 1) & 0xFFFFC000) + 0x4000;
+ d->sample_size = high_offset - d->sample_data_offset;
+ } else {
+ d->sample_data_offset = 0;
+ d->sample_size = 0;
+ }
+}
+
+
+static dc_status_t
+cochran_read_samples(dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = (cochran_data_t *) &(device->data);
+ dc_status_t rc;
+
+
+ if (d->sample_size > 0) {
+ if (d->sample)
+ free(d->sample);
+
+ d->sample = (unsigned char *) malloc(d->sample_size);
+ if (device == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Enable progress notifications.
+ device->progress = malloc(sizeof(dc_event_progress_t));
+ if (device->progress == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ device->progress->current = 0;
+ device->progress->maximum = d->sample_size;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
+
+ serial_sleep(device->port, 800);
+
+ // set back to 9600 baud
+ cochran_commander_serial_setup(device, abstract->context);
+
+ // Read the sample data
+ rc = cochran_commander_device_read (abstract, d->sample_data_offset,
+ d->sample, d->sample_size);
+ if (rc != DC_STATUS_SUCCESS) {
+ free (device->progress);
+ ERROR (abstract->context, "Failed to read the sample data.");
+ return rc;
+ }
+
+ device->progress->current = d->sample_size;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
+ free (device->progress);
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+cochran_commander_device_read_all (dc_device_t *abstract)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = (cochran_data_t *) &(device->data);
+
+ dc_status_t rc;
+
+ // Read config
+ rc = cochran_read_config(abstract);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ rc = cochran_read_misc(abstract);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Determine size of dive list to read. Round up to nearest 16K
+ if (d->dive_count_endian == COCHRAN_LE_TYPE)
+ d->dive_count = array_uint16_le (d->config[0] + d->dive_count_ptr);
+ else
+ d->dive_count = array_uint16_be (d->config[0] + d->dive_count_ptr);
+
+ d->logbook_size = ((d->dive_count * d->log_size) & 0xFFFFC000)
+ + 0x4000;
+
+ rc = cochran_read_logbook(abstract);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Determine sample memory to read
+ cochran_find_fingerprint(abstract);
+ cochran_get_sample_parms(abstract);
+
+ rc = cochran_read_samples(abstract);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+#define pack_uint32_array_le(d, i) ((d)[0] = (i) & 0xff, \
+ (d)[1] = ((i) >> 8) & 0xff, \
+ (d)[2] = ((i) >> 16) & 0xff, \
+ (d)[3] = ((i) >> 24) & 0xff)
+
+dc_status_t
+cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = (cochran_data_t *) &(device->data);
+ int ptr = 0;
+
+ dc_status_t rc;
+ char *b;
+ int size;
+
+ rc = cochran_commander_device_read_all (abstract);
+
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Reserve space for block pointers
+ // Structure is:
+ // int ptr;
+ // char data_valid_flag;
+ dc_buffer_resize(data, 10 * 5);
+
+ // Set pointer to first block
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ if (d->extra_id_flag) {
+ dc_buffer_append(data, d->id0, 67);
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+ } else {
+ dc_buffer_resize(data, size + 67);
+ b = dc_buffer_get_data(data);
+
+ memset(b + size, 0, 67);
+ }
+
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ dc_buffer_append (data, d->id, 67);
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+
+ // Add config blocks
+ int n;
+ for (n = 0; n < d->config_count; n++) {
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ dc_buffer_append (data, d->config[n], 512);
+
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+ }
+
+ // Add blank config blocks
+ for (n = d->config_count; n < 4; n++) {
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ dc_buffer_resize(data, size + 512);
+
+ b = dc_buffer_get_data(data);
+ memset(b + size, 0, 512);
+ }
+
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ if (d->misc) {
+ dc_buffer_append (data, d->misc, 1500);
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+ } else {
+ dc_buffer_resize(data, size + 1500);
+
+ b = dc_buffer_get_data(data);
+ memset(b + size, 0, 1500);
+ }
+
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ if (d->logbook) {
+ dc_buffer_append (data, d->logbook, d->logbook_size);
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+ } else {
+ dc_buffer_resize(data, size + d->logbook_size);
+
+ b = dc_buffer_get_data(data);
+ memset(b + size, 0, d->logbook_size);
+ }
+
+ // Set pointer to next block
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ if (d->sample) {
+ dc_buffer_append (data, d->sample, d->sample_size);
+ *(dc_buffer_get_data(data) + ptr + 4) = 1;
+ } else {
+ dc_buffer_resize(data, dc_buffer_get_size(data) + d->sample_size);
+
+ b = dc_buffer_get_data(data);
+ memset(b + size, 0, d->logbook_size);
+ }
+
+ // Set pointer to end
+ ptr += 5;
+ size = dc_buffer_get_size(data);
+ pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+
+dc_status_t
+cochran_commander_device_foreach (dc_device_t *abstract,
+ dc_dive_callback_t callback, void *userdata)
+{
+ cochran_device_t *device = (cochran_device_t *) abstract;
+ cochran_data_t *d = &(device->data);
+ unsigned int sample_start_offset, sample_end_offset;
+ struct tm t;
+ dc_status_t rc;
+
+ rc = cochran_commander_device_read_all (abstract);
+
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Loop through each dive
+ int i;
+ for (i = d->dive_count - 1; i > d->fp_dive_num; i--) {
+
+ d->current_log = d->logbook + i * d->log_size;
+
+ sample_start_offset = array_uint32_le (d->current_log + 6);
+ sample_end_offset = array_uint32_le (d->current_log
+ + d->log_size/2);
+
+ d->current_sample = d->sample + sample_start_offset
+ - d->sample_data_offset;
+
+ // Check for corrupt post-dive section
+ if (array_uint32_le(d->current_log + d->log_size/2) == 0xFFFFFFFF)
+ d->corrupt_dive = 1;
+ else
+ d->corrupt_dive = 0;
+
+ // Check for ring buffer wrap
+ if (sample_start_offset > sample_end_offset)
+ d->current_sample_size = d->sample_memory_end_address
+ - sample_start_offset + 1 + sample_end_offset
+ - d->sample_memory_start_address + 1;
+ else
+ d->current_sample_size = sample_end_offset - sample_start_offset;
+
+ d->current_fingerprint = d->current_log + d->dive_num_ptr;
+
+ if (d->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
+ t.tm_sec = d->current_log[0];
+ t.tm_min = d->current_log[1];
+ t.tm_hour = d->current_log[2];
+ t.tm_mday = d->current_log[3];
+ t.tm_mon = d->current_log[4];
+ t.tm_year = d->current_log[5];
+ t.tm_wday = t.tm_yday = t.tm_isdst = 0;
+ } else {
+ t.tm_sec = d->current_log[1];
+ t.tm_min = d->current_log[0];
+ t.tm_hour = d->current_log[3];
+ t.tm_mday = d->current_log[2];
+ t.tm_mon = d->current_log[5];
+ t.tm_year = d->current_log[4];
+ t.tm_wday = t.tm_yday = t.tm_isdst = 0;
+ }
+ d->current_dive_start_time = mktime(&t);
+
+ if (callback && !callback ((unsigned char *) d, sizeof(device->data),
+ d->current_fingerprint, sizeof (d->fingerprint), userdata))
+ return DC_STATUS_SUCCESS;
+ }
+
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
new file mode 100644
index 0000000..d16de42
--- /dev/null
+++ b/src/cochran_commander.h
@@ -0,0 +1,157 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 John Van Ostrand
+ *
+ * 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
+ */
+
+// seconds to add to Cochran time stamps to get unix time
+// Equivalent to Jan 1, 1992 00:00:00
+#define COCHRAN_TIMESTAMP_OFFSET 694224000
+
+#define COCHRAN_LE_TYPE 0
+#define COCHRAN_BE_TYPE 1
+
+#define COCHRAN_DATE_FORMAT_SMHDMY 0
+#define COCHRAN_DATE_FORMAT_MSDHYM 1
+
+#define COCHRAN_ADDRESS_LENGTH_32 0
+#define COCHRAN_ADDRESS_LENGTH_24 1
+
+typedef enum cochran_model_t {
+ COCHRAN_MODEL_UNKNOWN = 0,
+ COCHRAN_MODEL_EMC_FAMILY = 1 << 16,
+ COCHRAN_MODEL_EMC_14,
+ COCHRAN_MODEL_EMC_16,
+ COCHRAN_MODEL_EMC_20,
+ COCHRAN_MODEL_COMMANDER_FAMILY = 2 << 16,
+ COCHRAN_MODEL_COMMANDER_AIR_NITROX,
+} cochran_model_t;
+
+typedef struct cochran_data_t {
+ cochran_model_t model;
+
+ unsigned char id0[67];
+ unsigned char id[67];
+ unsigned char config[4][512];
+ unsigned char misc[1500];
+ unsigned char *logbook;
+ unsigned char *sample;
+
+ unsigned int extra_id_flag;
+ unsigned int config_count;
+
+ unsigned short int dive_count;
+ unsigned char fingerprint[2];
+ int fp_dive_num;
+
+ unsigned int logbook_size;
+ unsigned int current_sample_size;
+
+ unsigned int sample_data_offset;
+ unsigned int sample_size;
+ unsigned int last_interdive_offset;
+ unsigned int last_entry_offset;
+
+ unsigned char *current_fingerprint;
+ unsigned char *current_log;
+ unsigned char *current_sample;
+ time_t current_dive_start_time;
+
+ // Config items
+ int log_size;
+ int sample_memory_start_address;
+ int sample_memory_end_address;
+ int dive_num_ptr;
+ int dive_count_ptr;
+ int dive_count_endian;
+ int sample_end_ptr;
+ int log_pre_dive_ptr;
+ int log_end_dive_ptr;
+ int last_interdive_ptr;
+ int last_entry_ptr;
+ int date_format;
+ int address_length;
+ int high_baud; // baud rate to switch to for log/sample download
+
+ unsigned char corrupt_dive;
+} cochran_data_t;
+
+typedef struct cochran_device_t {
+ dc_device_t base;
+ const char *name; // serial port name
+ serial_t *port;
+ cochran_data_t data; // dive data used in parsing
+ dc_event_progress_t *progress; // for progress in the _read function
+} cochran_device_t;
+
+
+// Commander log fields
+#define CMD_SEC 1
+#define CMD_MIN 0
+#define CMD_HOUR 3
+#define CMD_DAY 2
+#define CMD_MON 5
+#define CMD_YEAR 4
+#define CME_START_OFFSET 6 // 4 bytes
+#define CMD_WATER_CONDUCTIVITY 24 // 1 byte, 0=low, 2=high
+#define CMD_START_TEMP 45 // 1 byte, F
+#define CMD_START_DEPTH 56 // 2 byte, /4=ft
+#define CMD_ALTITUDE 73 // 1 byte, /4=Kilofeet
+#define CMD_END_OFFSET 128 // 4 bytes
+#define CMD_MIN_TEMP 153 // 1 byte, F
+#define CMD_BT 166 // 2 bytes, minutes
+#define CMD_MAX_DEPTH 168 // 2 bytes, /4=ft
+#define CMD_AVG_DEPTH 170 // 2 bytes, /4=ft
+#define CMD_O2_PERCENT 210 // 8 bytes, 4 x 2 byte, /256=%
+
+// EMC log fields
+#define EMC_SEC 0
+#define EMC_MIN 1
+#define EMC_HOUR 2
+#define EMC_DAY 3
+#define EMC_MON 4
+#define EMC_YEAR 5
+#define EMC_START_OFFSET 6 // 4 bytes
+#define EMC_WATER_CONDUCTIVITY 25 // 1 byte, 0=low, 2=high
+#define EMC_START_DEPTH 42 // 2 byte, /256=ft
+#define EMC_START_TEMP 55 // 1 byte, F
+#define EMC_ALTITUDE 89 // 1 byte, /4=Kilofeet
+#define EMC_O2_PERCENT 144 // 20 bytes, 10 x 2 bytes, /256=%
+#define EMC_HE_PERCENT 164 // 20 bytes, 10 x 2 bytes, /256=%
+#define EMC_END_OFFSET 256 // 4 bytes
+#define EMC_MIN_TEMP 293 // 1 byte, F
+#define EMC_BT 304 // 2 bytes, minutes
+#define EMC_MAX_DEPTH 306 // 2 bytes, /4=ft
+#define EMC_AVG_DEPTH 310 // 2 bytes, /4=ft
+
+
+dc_status_t cochran_packet (cochran_device_t *device,
+ const unsigned char command[], unsigned int csize,
+ unsigned char answer[], unsigned int asize, int high_speed);
+dc_status_t cochran_commander_device_open (dc_device_t **out,
+ dc_context_t *context, const char *name);
+dc_status_t cochran_commander_device_close (dc_device_t *abstract);
+dc_status_t cochran_commander_device_set_fingerprint (dc_device_t *abstract,
+ const unsigned char data[], unsigned int size);
+dc_status_t cochran_commander_device_read (dc_device_t *abstract,
+ unsigned int address, unsigned char data[], unsigned int size);
+static dc_status_t cochran_read_id (dc_device_t *abstract);
+dc_status_t cochran_commander_device_foreach (dc_device_t *abstract,
+ dc_dive_callback_t callback, void *userdata);
+dc_status_t cochran_commander_device_dump (dc_device_t *abstract,
+ dc_buffer_t *data);
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c
new file mode 100644
index 0000000..004ab7e
--- /dev/null
+++ b/src/cochran_commander_parser.c
@@ -0,0 +1,218 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 John Van Ostrand
+ *
+ * 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 <stdlib.h>
+#include <time.h>
+
+#include <libdivecomputer/units.h>
+#include <libdivecomputer/cochran.h>
+
+#include "context-private.h"
+#include "device-private.h"
+#include "parser-private.h"
+#include "serial.h"
+#include "array.h"
+
+#include "cochran_commander.h"
+#include "cochran_commander_parser.h"
+
+
+dc_status_t cochran_commander_parser_set_data (dc_parser_t *abstract,
+ const unsigned char *data, unsigned int size);
+dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *abstract,
+ dc_datetime_t *datetime);
+static dc_status_t cochran_commander_parser_get_field (dc_parser_t *abstract,
+ dc_field_type_t type, unsigned int flags, void *value);
+dc_status_t cochran_commander_parser_destroy (dc_parser_t *abstract);
+static dc_status_t cochran_commander_parser_samples_foreach
+ (dc_parser_t *abstract, dc_sample_callback_t callback,
+ void *userdata);
+int cochran_commander_handle_event (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata, unsigned char code,
+ unsigned int offset, unsigned int time);
+
+
+static dc_parser_vtable_t cochran_commander_parser_vtable = {
+ DC_FAMILY_COCHRAN_COMMANDER,
+ cochran_commander_parser_set_data, /* set_data */
+ cochran_commander_parser_get_datetime, /* datetime */
+ cochran_commander_parser_get_field, /* fields */
+ cochran_commander_parser_samples_foreach, /* samples_foreach */
+ cochran_commander_parser_destroy /* destroy */
+};
+
+
+
+dc_status_t
+cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context)
+{
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ dc_parser_t *parser = (dc_parser_t *) malloc (sizeof (dc_parser_t));
+ if (parser == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ parser_init (parser, context, &cochran_commander_parser_vtable);
+
+ *out = parser;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_parser_destroy (dc_parser_t *abstract)
+{
+ // Free memory.
+ free (abstract);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+dc_status_t
+cochran_commander_parser_set_data (dc_parser_t *abstract,
+ const unsigned char *data, unsigned int size)
+{
+ abstract->data = data;
+ abstract->size = size;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+// There are two date formats used by Cochran
+dc_status_t
+cochran_commander_parser_get_datetime (dc_parser_t *abstract,
+ dc_datetime_t *datetime)
+{
+ cochran_data_t *data = (cochran_data_t *) abstract->data;
+ const unsigned char *log = data->current_log;
+
+ if (data->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
+ datetime->second = log[0];
+ datetime->minute = log[1];
+ datetime->hour = log[2];
+ datetime->day = log[3];
+ datetime->month = log[4];
+ datetime->year = log[5] + (log[5] > 91 ? 1900 : 2000);
+ } else {
+ datetime->second = log[1];
+ datetime->minute = log[0];
+ datetime->hour = log[3];
+ datetime->day = log[2];
+ datetime->month = log[5];
+ datetime->year = log[4] + (log[5] > 91 ? 1900 : 2000);
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
+ unsigned int flags, void *value)
+{
+ cochran_data_t *data = (cochran_data_t *) abstract->data;
+
+ switch (data->model & 0xFF0000)
+ {
+ case COCHRAN_MODEL_COMMANDER_FAMILY:
+ return cochran_cmdr_parser_get_field(abstract, type, flags, value);
+ break;
+ case COCHRAN_MODEL_EMC_FAMILY:
+ return cochran_emc_parser_get_field(abstract, type, flags, value);
+ break;
+ }
+}
+
+static dc_status_t
+cochran_commander_parser_samples_foreach (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata)
+{
+ cochran_data_t *data = (cochran_data_t *) abstract->data;
+
+ switch (data->model & 0xFF0000)
+ {
+ case COCHRAN_MODEL_COMMANDER_FAMILY:
+ return cochran_cmdr_parser_samples_foreach(abstract, callback,
+ userdata);
+ break;
+ case COCHRAN_MODEL_EMC_FAMILY:
+ return cochran_emc_parser_samples_foreach(abstract, callback,
+ userdata);
+ break;
+ }
+}
+
+
+
+int
+cochran_commander_handle_event (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata, unsigned char code,
+ unsigned int offset, unsigned int time)
+{
+ cochran_data_t *data = (cochran_data_t *) abstract->data;
+ cochran_events_t *e = cochran_events;
+
+ dc_sample_value_t sample = {0};
+
+ unsigned char event_ptr = 0;
+
+ while (e[event_ptr].code && e[event_ptr].code != code)
+ event_ptr++;
+
+ sample.event.time = 0;
+
+ if (e[event_ptr].code) {
+ switch (e[event_ptr].code)
+ {
+ case 0xAB: // Ceiling decrease
+ // Indicated to lower ceiling by 10 ft (deeper)
+ // Bytes 1-2: first stop duration (min)
+ // Bytes 3-4: total stop duration (min)
+ // Handled in calling function
+ break;
+ case 0xAD: // Ceiling increase
+ // Indicates to raise ceiling by 10 ft (shallower)
+ // Handled in calling function
+ break;
+ default:
+ // Don't send known events of type NONE
+ if (! e[event_ptr].type == SAMPLE_EVENT_NONE) {
+ sample.event.type = e[event_ptr].type;
+ sample.event.flags = e[event_ptr].flag;
+ if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ }
+ }
+ } else {
+ // Unknown event, send it so we know we missed something
+ sample.event.type = SAMPLE_EVENT_NONE;
+ sample.event.flags = SAMPLE_FLAGS_NONE;
+ sample.event.value = code;
+ if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ }
+
+ return e[event_ptr].data_bytes;
+}
diff --git a/src/cochran_commander_parser.h b/src/cochran_commander_parser.h
new file mode 100644
index 0000000..314d538
--- /dev/null
+++ b/src/cochran_commander_parser.h
@@ -0,0 +1,115 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 John Van Ostrand
+ *
+ * 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
+ */
+
+typedef struct cochran_events_t {
+ unsigned char code;
+ unsigned char data_bytes;
+ char *name;
+ parser_sample_event_t type;
+ parser_sample_flags_t flag;
+} cochran_events_t;
+
+static cochran_events_t cochran_events[] = {
+ { 0xA8, 1, "Entered PDI mode",
+ SAMPLE_EVENT_SURFACE, SAMPLE_FLAGS_BEGIN },
+ { 0xA9, 1, "Exited PDI mode",
+ SAMPLE_EVENT_SURFACE, SAMPLE_FLAGS_END },
+ { 0xAB, 5, "Ceiling decrease",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xAD, 5, "Ceiling increase",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xBD, 1, "Switched to nomal PO2 setting",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xC0, 1, "Switched to FO2 21% mode",
+ SAMPLE_EVENT_GASCHANGE, SAMPLE_FLAGS_NONE },
+ { 0xC1, 1, "Ascent rate greater than limit",
+ SAMPLE_EVENT_ASCENT, SAMPLE_FLAGS_BEGIN },
+ { 0xC2, 1, "Low battery warning",
+ SAMPLE_EVENT_BATTERY, SAMPLE_FLAGS_NONE },
+ { 0xC3, 1, "CNS Oxygen toxicity warning",
+ SAMPLE_EVENT_OLF, SAMPLE_FLAGS_NONE },
+ { 0xC4, 1, "Depth exceeds user set point",
+ SAMPLE_EVENT_MAXDEPTH, SAMPLE_FLAGS_NONE },
+ { 0xC5, 1, "Entered decompression mode",
+ SAMPLE_EVENT_DEEPSTOP, SAMPLE_FLAGS_BEGIN },
+ { 0xC8, 1, "PO2 too high",
+ SAMPLE_EVENT_FLOOR, SAMPLE_FLAGS_BEGIN },
+ { 0xCC, 1, "Low Cylinder 1 pressure",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
+ { 0xCE, 1, "Non-decompression warning",
+ SAMPLE_EVENT_RBT, SAMPLE_FLAGS_BEGIN },
+ { 0xCD, 1, "Switched to deco blend",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
+ { 0xD0, 1, "Breathing rate alarm",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
+ { 0xD3, 1, "Low gas 1 flow rate",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xD6, 1, "Depth is less than ceiling",
+ SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_BEGIN },
+ { 0xD8, 1, "End decompression mode",
+ SAMPLE_EVENT_DEEPSTOP, SAMPLE_FLAGS_END },
+ { 0xE1, 1, "End ascent rate warning",
+ SAMPLE_EVENT_ASCENT, SAMPLE_FLAGS_END },
+ { 0xE2, 1, "Low SBAT battery warning",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xE3, 1, "Switched to FO2 mode",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xE5, 1, "Switched to PO2 mode",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
+ { 0xEE, 1, "End non-decompresison warning",
+ SAMPLE_EVENT_RBT, SAMPLE_FLAGS_END },
+ { 0xEF, 1, "Switch to blend 2",
+ SAMPLE_EVENT_GASCHANGE2, SAMPLE_FLAGS_NONE },
+ { 0xF0, 1, "Breathing rate alarm",
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_END },
+ { 0xF3, 1, "Switch to blend 1",
+ SAMPLE_EVENT_GASCHANGE2, SAMPLE_FLAGS_NONE },
+ { 0xF6, 1, "End Depth is less than ceiling",
+ SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_END },
+ { 0x00, 1, NULL,
+ SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE }
+};
+
+
+// Common
+dc_status_t cochran_commander_parser_create (dc_parser_t **out,
+ dc_context_t *context);
+dc_status_t cochran_commander_parser_destroy (dc_parser_t *abstract);
+dc_status_t cochran_commander_parser_set_data (dc_parser_t *abstract,
+ const unsigned char *data, unsigned int size);
+dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *abstract,
+ dc_datetime_t *datetime);
+int cochran_commander_handle_event (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata, unsigned char code,
+ unsigned int offset, unsigned int time);
+
+// EMC FAMILY
+dc_status_t cochran_emc_parser_get_field (dc_parser_t *abstract,
+ dc_field_type_t type, unsigned int flags, void *value);
+dc_status_t cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata);
+
+// COMMANDER FAMILY
+dc_status_t cochran_cmdr_parser_get_field(dc_parser_t *abstract,
+ dc_field_type_t type, unsigned int flags, void *value);
+dc_status_t cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
+ dc_sample_callback_t callback, void *userdata);
+
diff --git a/src/cochran_common.c b/src/cochran_common.c
deleted file mode 100644
index 4fcd751..0000000
--- a/src/cochran_common.c
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- * libdivecomputer
- *
- * Copyright (C) 2014 John Van Ostrand
- *
- * 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 <string.h> // memcpy, memcmp
-#include <stdlib.h> // malloc, free
-#include <assert.h> // assert
-#include <time.h>
-
-#include <libdivecomputer/cochran.h>
-
-#include "context-private.h"
-#include "device-private.h"
-#include "serial.h"
-#include "array.h"
-
-#include "cochran_common.h"
-
-
-#define EXITCODE(rc) \
-( \
- rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
-)
-
-static const dc_device_vtable_t cochran_common_device_vtable = {
- DC_FAMILY_COCHRAN,
- cochran_common_device_set_fingerprint, /* set_fingerprint */
- cochran_common_device_read, /* read */
- NULL, /* write */
- cochran_common_device_dump, /* dump */
- cochran_common_device_foreach, /* foreach */
- cochran_common_device_close /* close */
-};
-
-
-dc_status_t
-cochran_packet (cochran_device_t *device, const unsigned char command[],
- unsigned int csize, unsigned char answer[], unsigned int asize,
- int high_speed)
-{
- dc_device_t *abstract = (dc_device_t *) device;
- unsigned int bytes_read = 0, n, read_size;
- unsigned int ptr;
-
- if (device_is_cancelled (abstract))
- return DC_STATUS_CANCELLED;
-
- // Send the command to the device, one byte at a time
- for (ptr = 0; ptr < csize; ptr++) {
- if (ptr) serial_sleep(device->port, 16); // 16 ms
- n = serial_write(device->port, command + ptr, 1);
- if (n != 1) {
- ERROR (abstract->context, "Failed to send the command.");
- return EXITCODE (n);
- }
- }
-
- if (high_speed) {
- serial_sleep(device->port, 45);
-
- // Weird but I only get the right result when I do it twice
- // Rates are odd, like 825600 for the EMC, 115200 for commander
- serial_configure(device->port, device->data.high_baud, 8,
- SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
- serial_configure(device->port, device->data.high_baud, 8,
- SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
- }
-
- // Receive the answer from the device.
- // Use 1024 byte "packets" so we can display progress.
- while (bytes_read < asize) {
- if (asize - bytes_read > 1024)
- read_size = 1024;
- else
- read_size = asize - bytes_read;
-
- n = serial_read (device->port, answer + bytes_read, read_size);
- if (n != read_size) {
- ERROR (abstract->context, "Failed to receive data, expected %u,"
- "read %u.", read_size, n);
- return EXITCODE (n);
- }
-
- bytes_read += n;
-
- if (device->progress) {
- device->progress->current = bytes_read;
- device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
- }
- }
-
- return DC_STATUS_SUCCESS;
-}
-
-
-static dc_status_t
-cochran_common_serial_setup (cochran_device_t *device, dc_context_t *context)
-{
- int rc;
-
- // Set the serial communication protocol (9600 8N2, no FC).
- rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE,
- 2, SERIAL_FLOWCONTROL_NONE);
- if (rc == -1) {
- ERROR (context, "Failed to set the terminal attributes.");
- serial_close (device->port);
- free (device);
- return DC_STATUS_IO;
- }
-
- serial_set_queue_size(device->port, 4096, 4096);
-
- // Make sure everything is in a sane state.
- // Mimicing Analyst software with excessive flushes
- serial_flush (device->port, SERIAL_QUEUE_OUTPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
- serial_flush (device->port, SERIAL_QUEUE_INPUT);
-
- serial_set_break(device->port, 1);
- serial_sleep(device->port, 16);
-
- serial_set_break(device->port, 0);
-
- // Set the timeout for receiving data (5000 ms).
- if (serial_set_timeout (device->port, 5000) == -1) {
- ERROR (context, "Failed to set the timeout.");
- serial_close (device->port);
- free (device);
- return DC_STATUS_IO;
- }
-
- // Wait for heartbeat byte before send
- int n;
- char answer[1];
- if ((n = serial_read(device->port, answer, 1)) != 1) {
- ERROR (context, "Failed to receive device heartbeat.");
- return EXITCODE (n);
- }
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_serial_open(cochran_device_t *device, dc_context_t *context)
-{
- // Open the device.
- int rc = serial_open (&device->port, context, device->name);
- if (rc == -1) {
- ERROR (context, "Failed to open the serial port.");
- free (device);
- return DC_STATUS_IO;
- }
-
- return cochran_common_serial_setup(device, context);
-}
-
-
-dc_status_t
-cochran_common_device_open (dc_device_t **out, dc_context_t *context,
- const char *name)
-{
- dc_status_t rc;
-
- if (out == NULL)
- return DC_STATUS_INVALIDARGS;
-
- // Allocate memory.
- cochran_device_t *device = (cochran_device_t *) malloc (
- sizeof (cochran_device_t));
- if (device == NULL) {
- ERROR (context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- // Initialize the base class.
- device_init (&device->base, context, &cochran_common_device_vtable);
-
- // Set the default values.
- device->port = NULL;
- device->name = name;
- device->progress = NULL;
- device->data.logbook = NULL;
- device->data.sample = NULL;
- cochran_common_device_set_fingerprint((dc_device_t *) device, "", 0);
-
- if ((rc = cochran_common_serial_open(device, context))
- != DC_STATUS_SUCCESS)
- return rc;
-
- // Read ID from the device
- rc = cochran_read_id((dc_device_t *) device);
-
- if (rc != DC_STATUS_SUCCESS) {
- ERROR (context, "Device not responding.");
- serial_close (device->port);
- free (device);
- return rc;
- }
-
- // Check ID
- if ((device->data.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
- ERROR (context, "Device not recognized.");
- serial_close (device->port);
- free (device);
- return DC_STATUS_UNSUPPORTED;
- }
-
- *out = (dc_device_t *) device;
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_device_close (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t*) abstract;
-
- // Close the device.
- if (serial_close (device->port) == -1) {
- free (device);
- return DC_STATUS_IO;
- }
-
- // Free memory.
- free (device->data.logbook);
- free (device->data.sample);
- free (device);
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_device_set_fingerprint (dc_device_t *abstract,
- const unsigned char data[], unsigned int size)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = &(device->data);
-
- if (size && size != sizeof (d->fingerprint))
- return DC_STATUS_INVALIDARGS;
-
- if (size)
- memcpy (&(d->fingerprint), data, sizeof (d->fingerprint));
- else
- memset (&(d->fingerprint), 0xFF, sizeof (d->fingerprint));
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_device_read (dc_device_t *abstract, unsigned int address,
- unsigned char data[], unsigned int size)
-{
- cochran_device_t *device = (cochran_device_t*) abstract;
-
- // Build the command
- unsigned char command[10];
- unsigned char command_size;
-
- switch (device->data.address_length)
- {
- case COCHRAN_ADDRESS_LENGTH_32:
- // EMC uses 32 bit addressing
- command[0] = 0x15;
- command[1] = (address ) & 0xff;
- command[2] = (address >> 8) & 0xff;
- command[3] = (address >> 16) & 0xff;
- command[4] = (address >> 24) & 0xff;
- command[5] = (size ) & 0xff;
- command[6] = (size >> 8 ) & 0xff;
- command[7] = (size >> 16 ) & 0xff;
- command[8] = (size >> 24 ) & 0xff;
- command[9] = 0x05;
- command_size = 10;
- break;
- case COCHRAN_ADDRESS_LENGTH_24:
- // Commander uses 24 byte addressing
- command[0] = 0x15;
- command[1] = (address ) & 0xff;
- command[2] = (address >> 8) & 0xff;
- command[3] = (address >> 16) & 0xff;
- command[4] = (size ) & 0xff;
- command[5] = (size >> 8 ) & 0xff;
- command[6] = (size >> 16 ) & 0xff;
- command[7] = 0x04;
- command_size = 8;
- break; default:
- return DC_STATUS_UNSUPPORTED;
- }
-
- // Read data at high speed
- dc_status_t rc = cochran_packet (device, command, command_size, data,
- size, 1);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- return DC_STATUS_SUCCESS;
-}
-
-
-static void
-cochran_set_device_config (cochran_device_t *device)
-{
- dc_device_t *abstract = (dc_device_t *) device;
- // Determine model
- if (memcmp(device->data.id + 0x3B, "AM2315\xA3\x71", 8) == 0)
- {
- device->data.model = COCHRAN_MODEL_EMC_20;
- device->data.log_size = 512;
- device->data.sample_memory_start_address = 0x94000;
- device->data.dive_num_ptr = 0x56;
- device->data.dive_count_ptr = 0xD2;
- device->data.dive_count_endian = COCHRAN_LE_TYPE;
- device->data.sample_end_ptr = 256;
- device->data.log_pre_dive_ptr = 30;
- device->data.log_end_dive_ptr = 256;
- device->data.last_interdive_ptr = 233;
- device->data.last_entry_ptr = 194;
- device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
- device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
- device->data.high_baud = 825600;
- }
- else if (memcmp(device->data.id + 0x3B, "AMA315\xC3\xC5", 8) == 0)
- {
- device->data.model = COCHRAN_MODEL_EMC_16;
- device->data.log_size = 512;
- device->data.sample_memory_start_address = 0x94000;
- device->data.dive_num_ptr = 0x56;
- device->data.dive_count_ptr = 0xD2;
- device->data.dive_count_endian = COCHRAN_LE_TYPE;
- device->data.sample_end_ptr = 256;
- device->data.log_pre_dive_ptr = 30;
- device->data.log_end_dive_ptr = 256;
- device->data.last_interdive_ptr = 233;
- device->data.last_entry_ptr = 194;
- device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
- device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
- device->data.high_baud = 825600;
- }
- else if (memcmp(device->data.id + 0x3B, "AM\x11""2212\x02", 8) == 0)
- {
- device->data.model = COCHRAN_MODEL_COMMANDER_AIR_NITROX;
- device->data.log_size = 256;
- device->data.sample_memory_start_address = 0x20000;
- device->data.dive_num_ptr = 0x46;
- device->data.dive_count_ptr = 0x46;
- device->data.dive_count_endian = COCHRAN_BE_TYPE;
- device->data.sample_end_ptr = 256;
- device->data.log_pre_dive_ptr = 30;
- device->data.log_end_dive_ptr = 128;
- device->data.last_interdive_ptr = 167;
- device->data.last_entry_ptr = -1;
- device->data.date_format = COCHRAN_DATE_FORMAT_MSDHYM;
- device->data.address_length = COCHRAN_ADDRESS_LENGTH_24;
- device->data.high_baud = 115200;
- }
- else
- {
- device->data.model = 0;
- ERROR (abstract->context,
- "Unknown Cochran model %02x %02x %02x %02x %02x %02x %02x %02x",
- *(device->data.id + 0x3B), *(device->data.id + 0x3B + 1),
- *(device->data.id + 0x3B + 2), *(device->data.id + 0x3B + 3),
- *(device->data.id + 0x3B + 4), *(device->data.id + 0x3B + 5),
- *(device->data.id + 0x3B + 6), *(device->data.id + 0x3B + 7));
- }
-
- return;
-}
-
-
-static dc_status_t
-cochran_read_id (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- dc_status_t rc;
- unsigned char command[6] = {0x05, 0x9D, 0xFF, 0x00, 0x43, 0x00};
-
- rc = cochran_packet(device, command, 6, device->data.id, 67, 0);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- if (strncmp(device->data.id, "(C)", 3) != 0) {
- // It's a Commander, read again
- memcpy(device->data.id0, device->data.id, 67);
-
- command[1] = 0xBD;
- command[2] = 0x7F;
-
- rc = cochran_packet(device, command, 6, device->data.id, 67, 0);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
- }
-
- cochran_set_device_config(device);
-
- return DC_STATUS_SUCCESS;
-}
-
-
-static dc_status_t
-cochran_read_config (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *data = &device->data;
- dc_status_t rc;
- unsigned char command[2] = { 0x96, 0x00 };
-
- if ((data->model & 0xFF0000) == COCHRAN_MODEL_EMC_FAMILY)
- data->config_count = 2;
- else
- data->config_count = 4;
-
- int n;
- for (n = 0; n < data->config_count; n++) {
- command[1] = n;
- rc = cochran_packet(device, command, 2, data->config[n], 512, 0);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
- }
-
- return DC_STATUS_SUCCESS;
-}
-
-
-static dc_status_t
-cochran_read_misc (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
-
- unsigned char command[7] = { 0x89, 0x05, 0x00, 0x00, 0x00, 0xDC, 0x05 };
-
- switch (device->data.model & 0xFF0000)
- {
- case COCHRAN_MODEL_COMMANDER_FAMILY:
- command[2] = 0xCA;
- command[3] = 0xFD;
- break;
- case COCHRAN_MODEL_EMC_FAMILY:
- command[2] = 0xE0;
- command[3] = 0x03;
- break;
- default:
- return DC_STATUS_UNSUPPORTED;
- }
-
- // Send first byte then wait for heartbeat before sending the rest
- serial_write(device->port, command, 1);
-
- int n;
- char answer[1];
- if ((n = serial_read(device->port, answer, 1)) != 1) {
- ERROR (abstract->context, "Failed to receive device heartbeat.");
- return EXITCODE (n);
- }
-
- return cochran_packet(device, command + 1, 6, device->data.misc, 1500, 0);
-}
-
-
-static dc_status_t
-cochran_read_logbook (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = &(device->data);
- dc_status_t rc;
-
- if (d->logbook)
- free(d->logbook);
-
- // Allocate space for log book.
- d->logbook = (unsigned char *) malloc(d->logbook_size);
- if (device == NULL) {
- ERROR (abstract->context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- // Enable progress notifications.
- device->progress = malloc(sizeof(dc_event_progress_t));
- if (device->progress == NULL) {
- ERROR (abstract->context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- device->progress->current = 0;
- device->progress->maximum = d->logbook_size;
- device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
-
- serial_sleep(device->port, 800);
-
- // set back to 9600 baud
- cochran_common_serial_setup(device, abstract->context);
-
- // Request log book
- rc = cochran_common_device_read(abstract, 0, d->logbook, d->logbook_size);
-
- device->progress->current = d->logbook_size;
- device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
- free (device->progress);
-
- return rc;
-}
-
-
-static void
-cochran_find_fingerprint(dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &(device->data);
-
- // Skip to fingerprint to reduce time
- d->fp_dive_num = d->dive_count - 1;
-
- while (d->fp_dive_num >= 0 && memcmp(&(d->fingerprint),
- d->logbook + d->fp_dive_num * d->log_size
- + d->dive_num_ptr,
- sizeof(d->fingerprint)))
- d->fp_dive_num--;
-}
-
-
-static void
-cochran_get_sample_parms(dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &(device->data);
- unsigned int pre_dive_offset, end_dive_offset;
- unsigned int low_offset, high_offset;
-
- // Find lowest and highest offsets into sample data
- low_offset = 0xFFFFFFFF;
- high_offset = 0;
-
- int i;
- for (i = d->fp_dive_num + 1; i < d->dive_count; i++) {
- pre_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
- + d->log_pre_dive_ptr]));
- end_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
- + d->log_end_dive_ptr]));
-
- // Check for ring buffer wrap-around.
- if (pre_dive_offset > end_dive_offset)
- break;
-
- if (pre_dive_offset < low_offset)
- low_offset = pre_dive_offset;
- if (end_dive_offset > high_offset && end_dive_offset != 0xFFFFFFFF )
- high_offset = end_dive_offset;
- }
-
- if (pre_dive_offset > end_dive_offset) {
- // Since I can't tell how much memory it has, I'll round.
- // I'll round to 128K, dives longer than 12 hrs aren't likely
- // and memory in sizes not rounded to 128K might be odd.
- high_offset = ((pre_dive_offset - 1) & 0xE0000) + 0x20000;
- d->sample_memory_end_address = high_offset;
- low_offset = d->sample_memory_start_address;
- d->sample_data_offset = low_offset;
- d->sample_size = high_offset - low_offset;
- } else if (low_offset < 0xFFFFFFFF && high_offset > 0) {
- // Round offset and size to 16K boundary
- d->sample_data_offset = low_offset & 0xFFFFC000;
- high_offset = ((high_offset - 1) & 0xFFFFC000) + 0x4000;
- d->sample_size = high_offset - d->sample_data_offset;
- } else {
- d->sample_data_offset = 0;
- d->sample_size = 0;
- }
-}
-
-
-static dc_status_t
-cochran_read_samples(dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &(device->data);
- dc_status_t rc;
-
-
- if (d->sample_size > 0) {
- if (d->sample)
- free(d->sample);
-
- d->sample = (unsigned char *) malloc(d->sample_size);
- if (device == NULL) {
- ERROR (abstract->context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- // Enable progress notifications.
- device->progress = malloc(sizeof(dc_event_progress_t));
- if (device->progress == NULL) {
- ERROR (abstract->context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- device->progress->current = 0;
- device->progress->maximum = d->sample_size;
- device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
-
- serial_sleep(device->port, 800);
-
- // set back to 9600 baud
- cochran_common_serial_setup(device, abstract->context);
-
- // Read the sample data
- rc = cochran_common_device_read (abstract, d->sample_data_offset,
- d->sample, d->sample_size);
- if (rc != DC_STATUS_SUCCESS) {
- free (device->progress);
- ERROR (abstract->context, "Failed to read the sample data.");
- return rc;
- }
-
- device->progress->current = d->sample_size;
- device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
- free (device->progress);
- }
-
- return DC_STATUS_SUCCESS;
-}
-
-
-static dc_status_t
-cochran_common_device_read_all (dc_device_t *abstract)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &(device->data);
-
- dc_status_t rc;
-
- // Read config
- rc = cochran_read_config(abstract);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- rc = cochran_read_misc(abstract);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- // Determine size of dive list to read. Round up to nearest 16K
- if (d->dive_count_endian == COCHRAN_LE_TYPE)
- d->dive_count = array_uint16_le (d->config[0] + d->dive_count_ptr);
- else
- d->dive_count = array_uint16_be (d->config[0] + d->dive_count_ptr);
-
- d->logbook_size = ((d->dive_count * d->log_size) & 0xFFFFC000)
- + 0x4000;
-
- rc = cochran_read_logbook(abstract);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- // Determine sample memory to read
- cochran_find_fingerprint(abstract);
- cochran_get_sample_parms(abstract);
-
- rc = cochran_read_samples(abstract);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- return DC_STATUS_SUCCESS;
-}
-
-
-#define pack_uint32_array_le(d, i) ((d)[0] = (i) & 0xff, \
- (d)[1] = ((i) >> 8) & 0xff, \
- (d)[2] = ((i) >> 16) & 0xff, \
- (d)[3] = ((i) >> 24) & 0xff)
-
-dc_status_t
-cochran_common_device_dump (dc_device_t *abstract, dc_buffer_t *data)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &(device->data);
- int ptr = 0;
-
- dc_status_t rc;
- char *b;
- int size;
-
- rc = cochran_common_device_read_all (abstract);
-
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- // Reserve space for block pointers
- // Structure is:
- // int ptr;
- // char data_valid_flag;
- dc_buffer_resize(data, 10 * 5);
-
- // Set pointer to first block
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- if (d->extra_id_flag) {
- dc_buffer_append(data, d->id0, 67);
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
- } else {
- dc_buffer_resize(data, size + 67);
- b = dc_buffer_get_data(data);
-
- memset(b + size, 0, 67);
- }
-
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- dc_buffer_append (data, d->id, 67);
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
-
- // Add config blocks
- int n;
- for (n = 0; n < d->config_count; n++) {
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- dc_buffer_append (data, d->config[n], 512);
-
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
- }
-
- // Add blank config blocks
- for (n = d->config_count; n < 4; n++) {
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- dc_buffer_resize(data, size + 512);
-
- b = dc_buffer_get_data(data);
- memset(b + size, 0, 512);
- }
-
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- if (d->misc) {
- dc_buffer_append (data, d->misc, 1500);
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
- } else {
- dc_buffer_resize(data, size + 1500);
-
- b = dc_buffer_get_data(data);
- memset(b + size, 0, 1500);
- }
-
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- if (d->logbook) {
- dc_buffer_append (data, d->logbook, d->logbook_size);
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
- } else {
- dc_buffer_resize(data, size + d->logbook_size);
-
- b = dc_buffer_get_data(data);
- memset(b + size, 0, d->logbook_size);
- }
-
- // Set pointer to next block
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- if (d->sample) {
- dc_buffer_append (data, d->sample, d->sample_size);
- *(dc_buffer_get_data(data) + ptr + 4) = 1;
- } else {
- dc_buffer_resize(data, dc_buffer_get_size(data) + d->sample_size);
-
- b = dc_buffer_get_data(data);
- memset(b + size, 0, d->logbook_size);
- }
-
- // Set pointer to end
- ptr += 5;
- size = dc_buffer_get_size(data);
- pack_uint32_array_le(dc_buffer_get_data(data) + ptr, size);
-
- return DC_STATUS_SUCCESS;
-}
-
-
-
-dc_status_t
-cochran_common_device_foreach (dc_device_t *abstract,
- dc_dive_callback_t callback, void *userdata)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = &(device->data);
- unsigned int sample_start_offset, sample_end_offset;
- struct tm t;
- dc_status_t rc;
-
- rc = cochran_common_device_read_all (abstract);
-
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- // Loop through each dive
- int i;
- for (i = d->dive_count - 1; i > d->fp_dive_num; i--) {
-
- d->current_log = d->logbook + i * d->log_size;
-
- sample_start_offset = array_uint32_le (d->current_log + 6);
- sample_end_offset = array_uint32_le (d->current_log
- + d->log_size/2);
-
- d->current_sample = d->sample + sample_start_offset
- - d->sample_data_offset;
-
- // Check for corrupt post-dive section
- if (array_uint32_le(d->current_log + d->log_size/2) == 0xFFFFFFFF)
- d->corrupt_dive = 1;
- else
- d->corrupt_dive = 0;
-
- // Check for ring buffer wrap
- if (sample_start_offset > sample_end_offset)
- d->current_sample_size = d->sample_memory_end_address
- - sample_start_offset + 1 + sample_end_offset
- - d->sample_memory_start_address + 1;
- else
- d->current_sample_size = sample_end_offset - sample_start_offset;
-
- d->current_fingerprint = d->current_log + d->dive_num_ptr;
-
- if (d->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
- t.tm_sec = d->current_log[0];
- t.tm_min = d->current_log[1];
- t.tm_hour = d->current_log[2];
- t.tm_mday = d->current_log[3];
- t.tm_mon = d->current_log[4];
- t.tm_year = d->current_log[5];
- t.tm_wday = t.tm_yday = t.tm_isdst = 0;
- } else {
- t.tm_sec = d->current_log[1];
- t.tm_min = d->current_log[0];
- t.tm_hour = d->current_log[3];
- t.tm_mday = d->current_log[2];
- t.tm_mon = d->current_log[5];
- t.tm_year = d->current_log[4];
- t.tm_wday = t.tm_yday = t.tm_isdst = 0;
- }
- d->current_dive_start_time = mktime(&t);
-
- if (callback && !callback ((unsigned char *) d, sizeof(device->data),
- d->current_fingerprint, sizeof (d->fingerprint), userdata))
- return DC_STATUS_SUCCESS;
- }
-
- return DC_STATUS_SUCCESS;
-}
diff --git a/src/cochran_common.h b/src/cochran_common.h
deleted file mode 100644
index 3498696..0000000
--- a/src/cochran_common.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * libdivecomputer
- *
- * Copyright (C) 2014 John Van Ostrand
- *
- * 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
- */
-
-// seconds to add to Cochran time stamps to get unix time
-// Equivalent to Jan 1, 1992 00:00:00
-#define COCHRAN_TIMESTAMP_OFFSET 694224000
-
-#define COCHRAN_LE_TYPE 0
-#define COCHRAN_BE_TYPE 1
-
-#define COCHRAN_DATE_FORMAT_SMHDMY 0
-#define COCHRAN_DATE_FORMAT_MSDHYM 1
-
-#define COCHRAN_ADDRESS_LENGTH_32 0
-#define COCHRAN_ADDRESS_LENGTH_24 1
-
-typedef enum cochran_model_t {
- COCHRAN_MODEL_UNKNOWN = 0,
- COCHRAN_MODEL_EMC_FAMILY = 1 << 16,
- COCHRAN_MODEL_EMC_14,
- COCHRAN_MODEL_EMC_16,
- COCHRAN_MODEL_EMC_20,
- COCHRAN_MODEL_COMMANDER_FAMILY = 2 << 16,
- COCHRAN_MODEL_COMMANDER_AIR_NITROX,
-} cochran_model_t;
-
-typedef struct cochran_data_t {
- cochran_model_t model;
-
- unsigned char id0[67];
- unsigned char id[67];
- unsigned char config[4][512];
- unsigned char misc[1500];
- unsigned char *logbook;
- unsigned char *sample;
-
- unsigned int extra_id_flag;
- unsigned int config_count;
-
- unsigned short int dive_count;
- unsigned char fingerprint[2];
- int fp_dive_num;
-
- unsigned int logbook_size;
- unsigned int current_sample_size;
-
- unsigned int sample_data_offset;
- unsigned int sample_size;
- unsigned int last_interdive_offset;
- unsigned int last_entry_offset;
-
- unsigned char *current_fingerprint;
- unsigned char *current_log;
- unsigned char *current_sample;
- time_t current_dive_start_time;
-
- // Config items
- int log_size;
- int sample_memory_start_address;
- int sample_memory_end_address;
- int dive_num_ptr;
- int dive_count_ptr;
- int dive_count_endian;
- int sample_end_ptr;
- int log_pre_dive_ptr;
- int log_end_dive_ptr;
- int last_interdive_ptr;
- int last_entry_ptr;
- int date_format;
- int address_length;
- int high_baud; // baud rate to switch to for log/sample download
-
- unsigned char corrupt_dive;
-} cochran_data_t;
-
-typedef struct cochran_device_t {
- dc_device_t base;
- const char *name; // serial port name
- serial_t *port;
- cochran_data_t data; // dive data used in parsing
- dc_event_progress_t *progress; // for progress in the _read function
-} cochran_device_t;
-
-
-// Commander log fields
-#define CMD_SEC 1
-#define CMD_MIN 0
-#define CMD_HOUR 3
-#define CMD_DAY 2
-#define CMD_MON 5
-#define CMD_YEAR 4
-#define CME_START_OFFSET 6 // 4 bytes
-#define CMD_WATER_CONDUCTIVITY 24 // 1 byte, 0=low, 2=high
-#define CMD_START_TEMP 45 // 1 byte, F
-#define CMD_START_DEPTH 56 // 2 byte, /4=ft
-#define CMD_ALTITUDE 73 // 1 byte, /4=Kilofeet
-#define CMD_END_OFFSET 128 // 4 bytes
-#define CMD_MIN_TEMP 153 // 1 byte, F
-#define CMD_BT 166 // 2 bytes, minutes
-#define CMD_MAX_DEPTH 168 // 2 bytes, /4=ft
-#define CMD_AVG_DEPTH 170 // 2 bytes, /4=ft
-#define CMD_O2_PERCENT 210 // 8 bytes, 4 x 2 byte, /256=%
-
-// EMC log fields
-#define EMC_SEC 0
-#define EMC_MIN 1
-#define EMC_HOUR 2
-#define EMC_DAY 3
-#define EMC_MON 4
-#define EMC_YEAR 5
-#define EMC_START_OFFSET 6 // 4 bytes
-#define EMC_WATER_CONDUCTIVITY 25 // 1 byte, 0=low, 2=high
-#define EMC_START_DEPTH 42 // 2 byte, /256=ft
-#define EMC_START_TEMP 55 // 1 byte, F
-#define EMC_ALTITUDE 89 // 1 byte, /4=Kilofeet
-#define EMC_O2_PERCENT 144 // 20 bytes, 10 x 2 bytes, /256=%
-#define EMC_HE_PERCENT 164 // 20 bytes, 10 x 2 bytes, /256=%
-#define EMC_END_OFFSET 256 // 4 bytes
-#define EMC_MIN_TEMP 293 // 1 byte, F
-#define EMC_BT 304 // 2 bytes, minutes
-#define EMC_MAX_DEPTH 306 // 2 bytes, /4=ft
-#define EMC_AVG_DEPTH 310 // 2 bytes, /4=ft
-
-
-dc_status_t cochran_packet (cochran_device_t *device,
- const unsigned char command[], unsigned int csize,
- unsigned char answer[], unsigned int asize, int high_speed);
-dc_status_t cochran_common_device_open (dc_device_t **out,
- dc_context_t *context, const char *name);
-dc_status_t cochran_common_device_close (dc_device_t *abstract);
-dc_status_t cochran_common_device_set_fingerprint (dc_device_t *abstract,
- const unsigned char data[], unsigned int size);
-dc_status_t cochran_common_device_read (dc_device_t *abstract,
- unsigned int address, unsigned char data[], unsigned int size);
-static dc_status_t cochran_read_id (dc_device_t *abstract);
-dc_status_t cochran_common_device_foreach (dc_device_t *abstract,
- dc_dive_callback_t callback, void *userdata);
-dc_status_t cochran_common_device_dump (dc_device_t *abstract,
- dc_buffer_t *data);
diff --git a/src/cochran_common_parser.c b/src/cochran_common_parser.c
deleted file mode 100644
index fefbc98..0000000
--- a/src/cochran_common_parser.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * libdivecomputer
- *
- * Copyright (C) 2014 John Van Ostrand
- *
- * 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 <stdlib.h>
-#include <time.h>
-
-#include <libdivecomputer/units.h>
-#include <libdivecomputer/cochran.h>
-
-#include "context-private.h"
-#include "device-private.h"
-#include "parser-private.h"
-#include "serial.h"
-#include "array.h"
-
-#include "cochran_common.h"
-#include "cochran_common_parser.h"
-
-
-dc_status_t cochran_common_parser_set_data (dc_parser_t *abstract,
- const unsigned char *data, unsigned int size);
-dc_status_t cochran_common_parser_get_datetime (dc_parser_t *abstract,
- dc_datetime_t *datetime);
-static dc_status_t cochran_common_parser_get_field (dc_parser_t *abstract,
- dc_field_type_t type, unsigned int flags, void *value);
-dc_status_t cochran_common_parser_destroy (dc_parser_t *abstract);
-static dc_status_t cochran_common_parser_samples_foreach
- (dc_parser_t *abstract, dc_sample_callback_t callback,
- void *userdata);
-int cochran_common_handle_event (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata, unsigned char code,
- unsigned int offset, unsigned int time);
-
-
-static dc_parser_vtable_t cochran_common_parser_vtable = {
- DC_FAMILY_COCHRAN,
- cochran_common_parser_set_data, /* set_data */
- cochran_common_parser_get_datetime, /* datetime */
- cochran_common_parser_get_field, /* fields */
- cochran_common_parser_samples_foreach, /* samples_foreach */
- cochran_common_parser_destroy /* destroy */
-};
-
-
-
-dc_status_t
-cochran_common_parser_create (dc_parser_t **out, dc_context_t *context)
-{
- if (out == NULL)
- return DC_STATUS_INVALIDARGS;
-
- // Allocate memory.
- dc_parser_t *parser = (dc_parser_t *) malloc (sizeof (dc_parser_t));
- if (parser == NULL) {
- ERROR (context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
- parser_init (parser, context, &cochran_common_parser_vtable);
-
- *out = parser;
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_parser_destroy (dc_parser_t *abstract)
-{
- // Free memory.
- free (abstract);
-
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_common_parser_set_data (dc_parser_t *abstract,
- const unsigned char *data, unsigned int size)
-{
- abstract->data = data;
- abstract->size = size;
-
- return DC_STATUS_SUCCESS;
-}
-
-
-// There are two date formats used by Cochran
-dc_status_t
-cochran_common_parser_get_datetime (dc_parser_t *abstract,
- dc_datetime_t *datetime)
-{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
- const unsigned char *log = data->current_log;
-
- if (data->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
- datetime->second = log[0];
- datetime->minute = log[1];
- datetime->hour = log[2];
- datetime->day = log[3];
- datetime->month = log[4];
- datetime->year = log[5] + (log[5] > 91 ? 1900 : 2000);
- } else {
- datetime->second = log[1];
- datetime->minute = log[0];
- datetime->hour = log[3];
- datetime->day = log[2];
- datetime->month = log[5];
- datetime->year = log[4] + (log[5] > 91 ? 1900 : 2000);
- }
-
- return DC_STATUS_SUCCESS;
-}
-
-static dc_status_t
-cochran_common_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
- unsigned int flags, void *value)
-{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
-
- switch (data->model & 0xFF0000)
- {
- case COCHRAN_MODEL_COMMANDER_FAMILY:
- return cochran_cmdr_parser_get_field(abstract, type, flags, value);
- break;
- case COCHRAN_MODEL_EMC_FAMILY:
- return cochran_emc_parser_get_field(abstract, type, flags, value);
- break;
- }
-}
-
-static dc_status_t
-cochran_common_parser_samples_foreach (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata)
-{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
-
- switch (data->model & 0xFF0000)
- {
- case COCHRAN_MODEL_COMMANDER_FAMILY:
- return cochran_cmdr_parser_samples_foreach(abstract, callback,
- userdata);
- break;
- case COCHRAN_MODEL_EMC_FAMILY:
- return cochran_emc_parser_samples_foreach(abstract, callback,
- userdata);
- break;
- }
-}
-
-
-
-int
-cochran_common_handle_event (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata, unsigned char code,
- unsigned int offset, unsigned int time)
-{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
- cochran_events_t *e = cochran_events;
-
- dc_sample_value_t sample = {0};
-
- unsigned char event_ptr = 0;
-
- while (e[event_ptr].code && e[event_ptr].code != code)
- event_ptr++;
-
- sample.event.time = 0;
-
- if (e[event_ptr].code) {
- switch (e[event_ptr].code)
- {
- case 0xAB: // Ceiling decrease
- // Indicated to lower ceiling by 10 ft (deeper)
- // Bytes 1-2: first stop duration (min)
- // Bytes 3-4: total stop duration (min)
- // Handled in calling function
- break;
- case 0xAD: // Ceiling increase
- // Indicates to raise ceiling by 10 ft (shallower)
- // Handled in calling function
- break;
- default:
- // Don't send known events of type NONE
- if (! e[event_ptr].type == SAMPLE_EVENT_NONE) {
- sample.event.type = e[event_ptr].type;
- sample.event.flags = e[event_ptr].flag;
- if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
- }
- }
- } else {
- // Unknown event, send it so we know we missed something
- sample.event.type = SAMPLE_EVENT_NONE;
- sample.event.flags = SAMPLE_FLAGS_NONE;
- sample.event.value = code;
- if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
- }
-
- return e[event_ptr].data_bytes;
-}
diff --git a/src/cochran_common_parser.h b/src/cochran_common_parser.h
deleted file mode 100644
index 9c4a67d..0000000
--- a/src/cochran_common_parser.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * libdivecomputer
- *
- * Copyright (C) 2014 John Van Ostrand
- *
- * 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
- */
-
-typedef struct cochran_events_t {
- unsigned char code;
- unsigned char data_bytes;
- char *name;
- parser_sample_event_t type;
- parser_sample_flags_t flag;
-} cochran_events_t;
-
-static cochran_events_t cochran_events[] = {
- { 0xA8, 1, "Entered PDI mode",
- SAMPLE_EVENT_SURFACE, SAMPLE_FLAGS_BEGIN },
- { 0xA9, 1, "Exited PDI mode",
- SAMPLE_EVENT_SURFACE, SAMPLE_FLAGS_END },
- { 0xAB, 5, "Ceiling decrease",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xAD, 5, "Ceiling increase",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xBD, 1, "Switched to nomal PO2 setting",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xC0, 1, "Switched to FO2 21% mode",
- SAMPLE_EVENT_GASCHANGE, SAMPLE_FLAGS_NONE },
- { 0xC1, 1, "Ascent rate greater than limit",
- SAMPLE_EVENT_ASCENT, SAMPLE_FLAGS_BEGIN },
- { 0xC2, 1, "Low battery warning",
- SAMPLE_EVENT_BATTERY, SAMPLE_FLAGS_NONE },
- { 0xC3, 1, "CNS Oxygen toxicity warning",
- SAMPLE_EVENT_OLF, SAMPLE_FLAGS_NONE },
- { 0xC4, 1, "Depth exceeds user set point",
- SAMPLE_EVENT_MAXDEPTH, SAMPLE_FLAGS_NONE },
- { 0xC5, 1, "Entered decompression mode",
- SAMPLE_EVENT_DEEPSTOP, SAMPLE_FLAGS_BEGIN },
- { 0xC8, 1, "PO2 too high",
- SAMPLE_EVENT_FLOOR, SAMPLE_FLAGS_BEGIN },
- { 0xCC, 1, "Low Cylinder 1 pressure",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
- { 0xCE, 1, "Non-decompression warning",
- SAMPLE_EVENT_RBT, SAMPLE_FLAGS_BEGIN },
- { 0xCD, 1, "Switched to deco blend",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
- { 0xD0, 1, "Breathing rate alarm",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_BEGIN },
- { 0xD3, 1, "Low gas 1 flow rate",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xD6, 1, "Depth is less than ceiling",
- SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_BEGIN },
- { 0xD8, 1, "End decompression mode",
- SAMPLE_EVENT_DEEPSTOP, SAMPLE_FLAGS_END },
- { 0xE1, 1, "End ascent rate warning",
- SAMPLE_EVENT_ASCENT, SAMPLE_FLAGS_END },
- { 0xE2, 1, "Low SBAT battery warning",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xE3, 1, "Switched to FO2 mode",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xE5, 1, "Switched to PO2 mode",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE },
- { 0xEE, 1, "End non-decompresison warning",
- SAMPLE_EVENT_RBT, SAMPLE_FLAGS_END },
- { 0xEF, 1, "Switch to blend 2",
- SAMPLE_EVENT_GASCHANGE2, SAMPLE_FLAGS_NONE },
- { 0xF0, 1, "Breathing rate alarm",
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_END },
- { 0xF3, 1, "Switch to blend 1",
- SAMPLE_EVENT_GASCHANGE2, SAMPLE_FLAGS_NONE },
- { 0xF6, 1, "End Depth is less than ceiling",
- SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_END },
- { 0x00, 1, NULL,
- SAMPLE_EVENT_NONE, SAMPLE_FLAGS_NONE }
-};
-
-
-// Common
-dc_status_t cochran_common_parser_create (dc_parser_t **out,
- dc_context_t *context);
-dc_status_t cochran_common_parser_destroy (dc_parser_t *abstract);
-dc_status_t cochran_common_parser_set_data (dc_parser_t *abstract,
- const unsigned char *data, unsigned int size);
-dc_status_t cochran_common_parser_get_datetime (dc_parser_t *abstract,
- dc_datetime_t *datetime);
-int cochran_common_handle_event (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata, unsigned char code,
- unsigned int offset, unsigned int time);
-
-// EMC FAMILY
-dc_status_t cochran_emc_parser_get_field (dc_parser_t *abstract,
- dc_field_type_t type, unsigned int flags, void *value);
-dc_status_t cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata);
-
-// COMMANDER FAMILY
-dc_status_t cochran_cmdr_parser_get_field(dc_parser_t *abstract,
- dc_field_type_t type, unsigned int flags, void *value);
-dc_status_t cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
- dc_sample_callback_t callback, void *userdata);
-
diff --git a/src/cochran_emc_parser.c b/src/cochran_emc_parser.c
index e1f28ac..37089a7 100644
--- a/src/cochran_emc_parser.c
+++ b/src/cochran_emc_parser.c
@@ -32,8 +32,8 @@
#include "serial.h"
#include "array.h"
-#include "cochran_common.h"
-#include "cochran_common_parser.h"
+#include "cochran_commander.h"
+#include "cochran_commander_parser.h"
struct dive_stats {
@@ -230,7 +230,7 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
// Check for event
if (s[0] & 0x80) {
- offset += cochran_common_handle_event(abstract, callback, userdata,
+ offset += cochran_commander_handle_event(abstract, callback, userdata,
s[0], offset, time);
switch (s[0])
{
diff --git a/src/descriptor.c b/src/descriptor.c
index 8836709..d4c2852 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -223,9 +223,9 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3},
/* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
- {"Cochran", "Commander", DC_FAMILY_COCHRAN, 0},
- {"Cochran", "EMC-16", DC_FAMILY_COCHRAN, 1},
- {"Cochran", "EMC-20H", DC_FAMILY_COCHRAN, 2},
+ {"Cochran", "Commander", DC_FAMILY_COCHRAN_COMMANDER, 0},
+ {"Cochran", "EMC-16", DC_FAMILY_COCHRAN_COMMANDER, 1},
+ {"Cochran", "EMC-20H", DC_FAMILY_COCHRAN_COMMANDER, 2},
};
typedef struct dc_descriptor_iterator_t {
diff --git a/src/device.c b/src/device.c
index cdd41ab..abbd6ec 100644
--- a/src/device.c
+++ b/src/device.c
@@ -155,8 +155,8 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_device_open (&device, context, name);
break;
- case DC_FAMILY_COCHRAN:
- rc = cochran_common_device_open (&device, context, name);
+ case DC_FAMILY_COCHRAN_COMMANDER:
+ rc = cochran_commander_device_open (&device, context, name);
break;
default:
return DC_STATUS_INVALIDARGS;
diff --git a/src/parser.c b/src/parser.c
index 07e9d2d..1759c81 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -132,8 +132,8 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_parser_create (&parser, context);
break;
- case DC_FAMILY_COCHRAN:
- rc = cochran_common_parser_create (&parser, context);
+ case DC_FAMILY_COCHRAN_COMMANDER:
+ rc = cochran_commander_parser_create (&parser, context);
break;
default:
return DC_STATUS_INVALIDARGS;
--
1.8.3.1
More information about the devel
mailing list