[PATCH] Cochran: Made numerous changes after review
John Van Ostrand
john at vanostrand.com
Mon Mar 7 09:52:10 PST 2016
- More localization of variables
- Variable name changes to be more consistent with other backends
- Removed special PTY serial_setup case
- Avoided potential double-free situations
- Consolidated serial queue flushing
- Verified heartbeat bytes
- Used goto-style error handling on _open
- Bounds checking on pointers
- Removed rounding reads to nearest 8k.
- Issue DEVINFO event in foreach
- Separated dive data from device_t
- switched to date-based fingerprint
- Many other small bugs and style fixes.
---
src/cochran_commander.c | 553 +++++++++++++++++++----------------------
src/cochran_commander.h | 52 ++--
src/cochran_commander_parser.c | 14 +-
3 files changed, 283 insertions(+), 336 deletions(-)
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index c457b3a..127518d 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -49,28 +49,29 @@
*/
// Cochran Commander Nitrox
-cochran_device_info_t cochran_cmdr_device_info = {
+const cochran_device_info_t cochran_cmdr_device_info = {
COCHRAN_MODEL_COMMANDER_AIR_NITROX, // model
- ADDRESS_24_BIT, // address_size
+ 24, // address_bits
ENDIAN_BE, // endian
115200, // high_baud
0x00000000, // rb_logbook_begin
0x00020000, // rb_lobook_end
0x00020000, // rb_profile_begin
0x00100000, // rb_profile_end
- 256, // log_size
- 512, // max_log
+ 256, // logbook_entry_size
+ 512, // logbook_entry_count
2, // max_gas
SAMPLE_CMDR, // sample_format
};
-cochran_conf_offsets_t cochran_cmdr_conf_offsets = {
+const cochran_conf_offsets_t cochran_cmdr_conf_offsets = {
0x046, // dive_count
0x06e, // last_log
0x071, // last_interdive
+ 0x0aa, // serial_number
};
-cochran_log_offsets_t cochran_cmdr_log_offsets = {
+const cochran_log_offsets_t cochran_cmdr_log_offsets = {
1, 0, 3, 2, 5, 4, // sec, min, hour, day, mon, year, 1 byte each
6, // profile_begin_offset, 4 bytes
24, // water_conductivity, 1 byte, 0=low(fresh), 2=high(sea)
@@ -91,7 +92,7 @@ cochran_log_offsets_t cochran_cmdr_log_offsets = {
};
// inter-dive event lengths
-struct event_size cmdr_event_bytes[15] = {
+const struct event_size cmdr_event_bytes[15] = {
{0x00, 17}, {0x01, 21}, {0x02, 18},
{0x03, 17}, {0x06, 19}, {0x07, 19},
{0x08, 19}, {0x09, 19}, {0x0a, 19},
@@ -100,63 +101,64 @@ struct event_size cmdr_event_bytes[15] = {
{ -1, 1} };
// Cochran EMC-14
-cochran_device_info_t cochran_emc14_device_info = {
+const cochran_device_info_t cochran_emc14_device_info = {
COCHRAN_MODEL_EMC_14, // model
- ADDRESS_32_BIT, // address_size
+ 32, // address_bits
ENDIAN_LE, // endian
806400, // high_baud
0x00000000, // rb_logbook_begin
0x00020000, // rb_lobook_end
0x00022000, // rb_profile_begin
0x00200000, // rb_profile_end
- 512, // log_size
- 256, // max_log
+ 512, // logbook_entry_size
+ 256, // logbook_entry_count
2, // max_gas
SAMPLE_EMC, // sample_format
};
// Cochran EMC-16
-cochran_device_info_t cochran_emc16_device_info = {
+const cochran_device_info_t cochran_emc16_device_info = {
COCHRAN_MODEL_EMC_16, // model
- ADDRESS_32_BIT, // address_size
+ 32, // address_bits
ENDIAN_LE, // endian
806400, // high_baud
0x00000000, // rb_logbook_begin
0x00080000, // rb_lobook_end
0x00094000, // rb_profile_begin
0x00800000, // rb_profile_end
- 512, // log_size
- 1024, // max_log
+ 512, // logbook_entry_size
+ 1024, // logbook_entry_count
2, // max_gas
SAMPLE_EMC, // sample_format
};
// Cochran EMC-20
-cochran_device_info_t cochran_emc20_device_info = {
+const cochran_device_info_t cochran_emc20_device_info = {
COCHRAN_MODEL_EMC_20, // model
- ADDRESS_32_BIT, // address_size
+ 32, // address_bits
ENDIAN_LE, // endian
806400, // high_baud
0x00000000, // rb_logbook_begin
0x00080000, // rb_lobook_end
0x00094000, // rb_profile_begin
0x01000000, // rb_profile_end
- 512, // log_size
- 1024, // max_log
+ 512, // logbook_entry_size
+ 1024, // logbook_entry_count
2, // max_gas
SAMPLE_EMC, // sample_format
};
// Common EMC offsets
-cochran_conf_offsets_t cochran_emc_conf_offsets = {
+const cochran_conf_offsets_t cochran_emc_conf_offsets = {
0x0d2, // dive_count
0x13e, // last_log
0x142, // last_interdive
+ 0x1e6, // serial_number
};
-cochran_log_offsets_t cochran_emc_log_offsets = {
+const cochran_log_offsets_t cochran_emc_log_offsets = {
0, 1, 2, 3, 4, 5, // sec, min, hour, day, mon, year, 1 byte each
6, // profile_begin_offset, 4 bytes
24, // water_conductivity, 1 byte 0=low(fresh), 2=high(sea)
@@ -176,7 +178,7 @@ cochran_log_offsets_t cochran_emc_log_offsets = {
407, // max_temp, 1 byte, /2+20=F
};
-struct event_size emc_event_bytes[15] = {
+const struct event_size emc_event_bytes[15] = {
{0x00, 19}, {0x01, 23}, {0x02, 20},
{0x03, 19}, {0x06, 21}, {0x07, 21},
{0x0a, 21}, {0x0b, 21}, {0x0f, 19},
@@ -196,12 +198,12 @@ static const dc_device_vtable_t cochran_commander_device_vtable = {
static dc_status_t
-cochran_read_id(dc_device_t *device);
+cochran_read_id(dc_device_t *device, unsigned char *id, int size);
static dc_status_t
cochran_commander_read (dc_device_t *abstract, dc_event_progress_t *progress,
unsigned int address, unsigned char data[], unsigned int size);
static void
-cochran_check_profiles(dc_device_t *abstract);
+cochran_check_profiles(dc_device_t *abstract, cochran_data_t *data);
static dc_status_t
@@ -210,17 +212,18 @@ cochran_packet (cochran_device_t *device, dc_event_progress_t *progress,
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;
- int rc;
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 sent all at once the command is ignored. It's like the DC
+ // has no buffering.
+ for (int i = 0; i < csize; i++) {
+ // Give the DC time to read the character.
+ if (i) serial_sleep(device->port, 16); // 16 ms
+
+ unsigned int n = serial_write(device->port, command + i, 1);
if (n != 1) {
ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n);
@@ -228,38 +231,40 @@ cochran_packet (cochran_device_t *device, dc_event_progress_t *progress,
}
if (high_speed) {
+ int rc = 0;
+
+ // Give the DC time to process the command.
+ // This is required.
serial_sleep(device->port, 45);
// Rates are odd, like 806400 for the EMC, 115200 for commander
rc = serial_configure(device->port, device->info->high_baud, 8,
SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
- // Assume we are talking to a pty, a simulator
- rc = serial_configure(device->port, 115200, 8, SERIAL_PARITY_NONE,
- 2, SERIAL_FLOWCONTROL_NONE);
- if (rc == -1) {
- ERROR (abstract->context, "Failed to set the high baud rate.");
- return DC_STATUS_IO;
- }
+ ERROR (abstract->context, "Failed to set the high baud rate.");
+ return DC_STATUS_IO;
}
}
// 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;
+ unsigned int nbytes = 0;
+ while (nbytes < asize) {
+ unsigned int len = 0;
+
+ if (asize - nbytes > 1024)
+ len = 1024;
else
- read_size = asize - bytes_read;
+ len = asize - nbytes;
- n = serial_read (device->port, answer + bytes_read, read_size);
- if (n != read_size) {
+ int n = serial_read (device->port, answer + nbytes, len);
+ if (n != len) {
ERROR (abstract->context, "Failed to receive data, expected %u,"
- "read %u.", read_size, n);
+ "read %u.",len, n);
return EXITCODE (n);
}
- bytes_read += n;
+ nbytes += n;
if (progress) {
progress->current += n;
@@ -281,51 +286,39 @@ cochran_commander_serial_setup (cochran_device_t *device)
2, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (device->base.context, "Failed to set the terminal attributes.");
- serial_close (device->port);
return DC_STATUS_IO;
}
- serial_set_queue_size(device->port, 4096, 4096);
-
- // Make sure everything is in a sane state.
- serial_flush (device->port, SERIAL_QUEUE_OUTPUT);
- 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 (device->base.context, "Failed to set the timeout.");
- serial_close (device->port);
return DC_STATUS_IO;
}
+ // Wake up DC and trigger heartbeat
+ serial_set_break(device->port, 1);
+ serial_sleep(device->port, 16);
+ serial_set_break(device->port, 0);
+
+ // Clear old heartbeats
+ serial_flush (device->port, SERIAL_QUEUE_BOTH);
+
// Wait for heartbeat byte before send
- char answer[1];
- int n = serial_read(device->port, answer, 1);
+ unsigned char answer = 0;
+ int n = serial_read(device->port, &answer, 1);
if (n != 1) {
+ serial_close (device->port);
ERROR (device->base.context, "Failed to receive device heartbeat.");
return EXITCODE (n);
}
- return DC_STATUS_SUCCESS;
-}
-
-
-dc_status_t
-cochran_commander_serial_open(cochran_device_t *device)
-{
- // Open the device.
- int rc = serial_open (&device->port, device->base.context, device->name);
- if (rc == -1) {
- ERROR (device->base.context, "Failed to open the serial port.");
- return DC_STATUS_IO;
+ if (answer != 0xAA) {
+ serial_close (device->port);
+ ERROR (device->base.context, "Received bad hearbeat byte (%02x).", answer);
+ return DC_STATUS_PROTOCOL;
}
- return cochran_commander_serial_setup(device);
+ return DC_STATUS_SUCCESS;
}
@@ -334,7 +327,7 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
const char *name)
{
cochran_device_t *device = NULL;
- dc_status_t rc;
+ dc_status_t status;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
@@ -348,29 +341,31 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
// Set the default values.
device->port = NULL;
- device->name = name;
- device->data.logbook = NULL;
- device->data.sample = NULL;
cochran_commander_device_set_fingerprint((dc_device_t *) device,
NULL, 0);
- rc = cochran_commander_serial_open(device);
- if (rc != DC_STATUS_SUCCESS) {
- dc_device_deallocate((dc_device_t *) device);
- return rc;
+ // Open the device.
+ int rc = serial_open (&device->port, device->base.context, name);
+ if (rc == -1) {
+ ERROR (device->base.context, "Failed to open the serial port.");
+ status = DC_STATUS_IO;
+ goto error_free;
}
+ rc = cochran_commander_serial_setup(device);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
// Read ID from the device
- rc = cochran_read_id((dc_device_t *) device);
+ unsigned char id[67];
+ status = cochran_read_id((dc_device_t *) device, id, sizeof(id));
- if (rc != DC_STATUS_SUCCESS) {
+ if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Device not responding.");
- serial_close (device->port);
- dc_device_deallocate((dc_device_t *) device);
- return rc;
+ goto error_close;
}
- memcpy(device->model_string, device->data.id + 0x3b, 8);
+ memcpy(device->model_string, id + 0x3b, 8);
device->model_string[8] = 0;
device->base.devinfo.model = cochran_commander_model_id(device->model_string);
@@ -383,9 +378,8 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
device->model_string[2], device->model_string[3],
device->model_string[4], device->model_string[5],
device->model_string[6], device->model_string[7]);
- serial_close (device->port);
- dc_device_deallocate((dc_device_t *) device);
- return DC_STATUS_UNSUPPORTED;
+ status = DC_STATUS_UNSUPPORTED;
+ goto error_close;
}
// Get model capability, protocol and data format
@@ -395,24 +389,27 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
+
+error_close:
+ serial_close (device->port);
+error_free:
+ dc_device_deallocate ((dc_device_t *) device);
+ return status;
}
dc_status_t
cochran_commander_device_close (dc_device_t *abstract)
{
+ dc_status_t status = DC_STATUS_SUCCESS;
cochran_device_t *device = (cochran_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
- return DC_STATUS_IO;
+ dc_status_set_error( &status, DC_STATUS_IO );
}
- // Free memory.
- free (device->data.logbook);
- free (device->data.sample);
-
- return DC_STATUS_SUCCESS;
+ return status;
}
@@ -421,15 +418,14 @@ 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))
+ if (size && size != sizeof (device->fingerprint))
return DC_STATUS_INVALIDARGS;
if (size)
- memcpy (&d->fingerprint, data, sizeof (d->fingerprint));
+ memcpy (device->fingerprint, data, sizeof (device->fingerprint));
else
- memset (&d->fingerprint, 0xFF, sizeof (d->fingerprint));
+ memset (device->fingerprint, 0xFF, sizeof (device->fingerprint));
return DC_STATUS_SUCCESS;
}
@@ -453,9 +449,9 @@ cochran_commander_read (dc_device_t *abstract, dc_event_progress_t *progress,
unsigned char command[10];
unsigned char command_size;
- switch (device->info->address_size)
+ switch (device->info->address_bits)
{
- case ADDRESS_32_BIT:
+ case 32:
// EMC uses 32 bit addressing
command[0] = 0x15;
command[1] = (address ) & 0xff;
@@ -469,7 +465,7 @@ cochran_commander_read (dc_device_t *abstract, dc_event_progress_t *progress,
command[9] = 0x05;
command_size = 10;
break;
- case ADDRESS_24_BIT:
+ case 24:
// Commander uses 24 byte addressing
command[0] = 0x15;
command[1] = (address ) & 0xff;
@@ -523,7 +519,7 @@ cochran_commander_model_id(const char *model)
// Get device capability, protocol info and data format for a device
dc_status_t
-cochran_commander_info (const int model, cochran_device_info_t **info, cochran_conf_offsets_t **conf_ptr, cochran_log_offsets_t **log_ptr, struct event_size (**event_bytes)[15])
+cochran_commander_info (const int model, const cochran_device_info_t **info, const cochran_conf_offsets_t **conf_ptr, const cochran_log_offsets_t **log_ptr, const struct event_size (**event_bytes)[15])
{
// Determine model
if (model == COCHRAN_MODEL_EMC_20)
@@ -564,99 +560,51 @@ cochran_commander_info (const int model, cochran_device_info_t **info, cochran_c
static dc_status_t
-cochran_read_id (dc_device_t *abstract)
+cochran_read_id (dc_device_t *abstract, unsigned char *id, int size)
{
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, NULL, command, 6, device->data.id, 67, 0);
+ rc = cochran_packet(device, NULL, command, sizeof(command), id, size, 0);
if (rc != DC_STATUS_SUCCESS)
return rc;
- if (strncmp((const char *)device->data.id, "(C)", 3) != 0) {
- // It's a Commander, read again
- memcpy(device->data.id0, device->data.id, 67);
- device->data.extra_id_flag = 1;
-
+ if (strncmp((const char *) id, "(C)", 3) != 0) {
+ // It's a Commander, read a different location
command[1] = 0xBD;
command[2] = 0x7F;
- rc = cochran_packet(device, NULL, command, 6, device->data.id, 67, 0);
+ rc = cochran_packet(device, NULL, command, sizeof(command), id, size, 0);
if (rc != DC_STATUS_SUCCESS)
return rc;
}
- return DC_STATUS_SUCCESS;
-}
-
-
-static dc_status_t
-cochran_read_config (dc_device_t *abstract, dc_event_progress_t *progress)
-{
- cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *data = &device->data;
+ // Emit ID block
dc_event_vendor_t vendor;
-
- dc_status_t rc;
- unsigned char command[2] = { 0x96, 0x00 };
-
- int n;
- for (n = 0; n < 2; n++) {
- command[1] = n;
- rc = cochran_packet(device, progress, command, 2, data->config[n], 512, 0);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- vendor.data = data->config[n];
- vendor.size = 512;
- device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
- }
+ vendor.data = id;
+ vendor.size = size;
+ device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
return DC_STATUS_SUCCESS;
}
static dc_status_t
-cochran_read_misc (dc_device_t *abstract, dc_event_progress_t *progress)
+cochran_read_config (dc_device_t *abstract, cochran_data_t *data, dc_event_progress_t *progress)
{
cochran_device_t *device = (cochran_device_t *) abstract;
- dc_status_t rc;
dc_event_vendor_t vendor;
- unsigned char command[7] = { 0x89, 0x05, 0x00, 0x00, 0x00, 0xDC, 0x05 };
-
- switch (device->info->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);
-
- char answer[1];
- int n = serial_read(device->port, answer, 1);
- if (n != 1) {
- ERROR (abstract->context, "Failed to receive device heartbeat.");
- return EXITCODE (n);
- }
-
- rc = cochran_packet(device, progress, command + 1, 6, device->data.misc, 1500, 0);
+ dc_status_t rc;
+ unsigned char command[2] = { 0x96, 0x00 };
+ rc = cochran_packet(device, progress, command, sizeof(command), data->config, sizeof(data->config), 0);
if (rc != DC_STATUS_SUCCESS)
return rc;
- vendor.data = device->data.misc;
- vendor.size = 1500;
+ vendor.data = data->config;
+ vendor.size = sizeof(data->config);
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
return DC_STATUS_SUCCESS;
@@ -664,18 +612,17 @@ cochran_read_misc (dc_device_t *abstract, dc_event_progress_t *progress)
static dc_status_t
-cochran_read_logbook (dc_device_t *abstract, dc_event_progress_t *progress)
+cochran_read_logbook (dc_device_t *abstract, cochran_data_t *data, dc_event_progress_t *progress)
{
cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = &device->data;
dc_status_t rc;
- if (d->logbook)
- free(d->logbook);
+ if (data->logbook)
+ free(data->logbook);
// Allocate space for log book.
- d->logbook = (unsigned char *) malloc(d->logbook_size);
- if (device == NULL) {
+ data->logbook = (unsigned char *) malloc(data->logbook_size);
+ if (data->logbook == NULL) {
ERROR (abstract->context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
@@ -683,38 +630,38 @@ cochran_read_logbook (dc_device_t *abstract, dc_event_progress_t *progress)
serial_sleep(device->port, 800);
// set back to 9600 baud
- cochran_commander_serial_setup(device);
+ rc = cochran_commander_serial_setup(device);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
// Request log book
- rc = cochran_commander_read(abstract, progress, 0, d->logbook,
- d->logbook_size);
+ rc = cochran_commander_read(abstract, progress, 0, data->logbook,
+ data->logbook_size);
return rc;
}
static void
-cochran_find_fingerprint(dc_device_t *abstract)
+cochran_find_fingerprint(dc_device_t *abstract, cochran_data_t *data)
{
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;
+ data->fp_dive_num = data->dive_count;
+ data->fp_dive_num--;
- while (d->fp_dive_num >= 0 && memcmp(&d->fingerprint,
- d->logbook + d->fp_dive_num * device->info->log_size
- + device->log_ptr->dive_number,
- sizeof(d->fingerprint)))
- d->fp_dive_num--;
+ while (data->fp_dive_num >= 0 && memcmp(device->fingerprint,
+ data->logbook + data->fp_dive_num * device->info->logbook_entry_size,
+ sizeof(device->fingerprint)))
+ data->fp_dive_num--;
}
static void
-cochran_get_sample_parms(dc_device_t *abstract)
+cochran_get_sample_parms(dc_device_t *abstract, cochran_data_t *data)
{
cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &device->data;
unsigned int pre_dive_offset = 0, end_dive_offset = 0;
unsigned int low_offset, high_offset;
@@ -723,12 +670,27 @@ cochran_get_sample_parms(dc_device_t *abstract)
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 * device->info->log_size
- + device->log_ptr->profile_pre_offset]));
- end_dive_offset = array_uint32_le (&(d->logbook[i * device->info->log_size
- + device->log_ptr->profile_end_offset]));
+ for (i = data->fp_dive_num + 1; i < data->dive_count; i++) {
+ pre_dive_offset = array_uint32_le (data->logbook + i * device->info->logbook_entry_size
+ + device->log_ptr->profile_pre_offset);
+ end_dive_offset = array_uint32_le (data->logbook + i * device->info->logbook_entry_size
+ + device->log_ptr->profile_end_offset);
+
+ // Validate offsets, allow 0xFFFFFFF for end_dive_offset
+ // because we handle that as a special case.
+ if (pre_dive_offset < device->info->rb_profile_begin
+ || pre_dive_offset > device->info->rb_profile_end) {
+ ERROR(abstract->context, "Invalid pre-dive offset (%08x) on dive %d.", pre_dive_offset, i);
+ continue;
+ }
+ if (end_dive_offset < device->info->rb_profile_begin
+ || (end_dive_offset > device->info->rb_profile_end
+ && end_dive_offset != 0xFFFFFFFF)) {
+ ERROR(abstract->context, "Invalid end-dive offset (%08x) on dive %d.", end_dive_offset, i);
+ continue;
+ }
+
// Check for ring buffer wrap-around.
if (pre_dive_offset > end_dive_offset)
break;
@@ -740,39 +702,33 @@ cochran_get_sample_parms(dc_device_t *abstract)
}
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;
+ high_offset = device->info->rb_profile_end;
low_offset = device->info->rb_profile_begin;
- d->sample_data_offset = low_offset;
- d->sample_size = high_offset - low_offset;
+ data->sample_data_offset = low_offset;
+ data->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;
+ data->sample_data_offset = low_offset;
+ data->sample_size = high_offset - data->sample_data_offset;
} else {
- d->sample_data_offset = 0;
- d->sample_size = 0;
+ data->sample_data_offset = 0;
+ data->sample_size = 0;
}
}
static dc_status_t
-cochran_read_samples(dc_device_t *abstract, dc_event_progress_t *progress)
+cochran_read_samples(dc_device_t *abstract, cochran_data_t *data, dc_event_progress_t *progress)
{
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);
+ if (data->sample_size > 0) {
+ if (data->sample)
+ free(data->sample);
- d->sample = (unsigned char *) malloc(d->sample_size);
- if (d->sample == NULL) {
+ data->sample = (unsigned char *) malloc(data->sample_size);
+ if (data->sample == NULL) {
ERROR (abstract->context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
@@ -780,11 +736,13 @@ cochran_read_samples(dc_device_t *abstract, dc_event_progress_t *progress)
serial_sleep(device->port, 800);
// set back to 9600 baud
- cochran_commander_serial_setup(device);
+ rc = cochran_commander_serial_setup(device);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
// Read the sample data
- rc = cochran_commander_read (abstract, progress, d->sample_data_offset,
- d->sample, d->sample_size);
+ rc = cochran_commander_read (abstract, progress, data->sample_data_offset,
+ data->sample, data->sample_size);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the sample data.");
return rc;
@@ -796,11 +754,10 @@ cochran_read_samples(dc_device_t *abstract, dc_event_progress_t *progress)
static dc_status_t
-cochran_commander_device_read_all (dc_device_t *abstract)
+cochran_commander_device_read_all (dc_device_t *abstract, cochran_data_t *data)
{
cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &device->data;
- dc_event_progress_t progress = {0};
+ dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
dc_status_t rc;
int max_config, max_logbook, max_sample;
@@ -815,39 +772,42 @@ cochran_commander_device_read_all (dc_device_t *abstract)
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Read config
- rc = cochran_read_config(abstract, &progress);
+ rc = cochran_read_config(abstract, data, &progress);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Determine size of dive list to read. Round up to nearest 16K
if (device->info->endian == ENDIAN_LE)
- d->dive_count = array_uint16_le (d->config[0] + device->conf_ptr->dive_count);
+ data->dive_count = array_uint16_le (data->config + device->conf_ptr->dive_count);
else
- d->dive_count = array_uint16_be (d->config[0] + device->conf_ptr->dive_count);
+ data->dive_count = array_uint16_be (data->config + device->conf_ptr->dive_count);
- d->logbook_size = ((d->dive_count * device->info->log_size) & 0xFFFFC000)
- + 0x4000;
+ if (data->dive_count > device->info->logbook_entry_count) {
+ data->logbook_size = device->info->logbook_entry_count * device->info->logbook_entry_size;
+ } else {
+ data->logbook_size = data->dive_count * device->info->logbook_entry_size;
+ }
- progress.maximum -= max_logbook - d->logbook_size;
+ progress.maximum -= max_logbook - data->logbook_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
- rc = cochran_read_logbook(abstract, &progress);
+ rc = cochran_read_logbook(abstract, data, &progress);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Determine sample memory to read
- cochran_find_fingerprint(abstract);
- cochran_get_sample_parms(abstract);
+ cochran_find_fingerprint(abstract, data);
+ cochran_get_sample_parms(abstract, data);
- progress.maximum -= max_sample - d->sample_size;
+ progress.maximum -= max_sample - data->sample_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
- rc = cochran_read_samples(abstract, &progress);
+ rc = cochran_read_samples(abstract, data, &progress);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Determine logs that haven't had profile data overwritten
- cochran_check_profiles(abstract);
+ cochran_check_profiles(abstract, data);
return DC_STATUS_SUCCESS;
}
@@ -859,64 +819,49 @@ cochran_commander_device_read_all (dc_device_t *abstract)
(d)[3] = ((i) >> 24) & 0xff)
dc_status_t
-cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
+cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *dump)
{
cochran_device_t *device = (cochran_device_t *) abstract;
- cochran_data_t *d = (cochran_data_t *) &device->data;
- dc_event_progress_t progress = {0};
- dc_event_vendor_t vendor;
-
+ dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
dc_status_t rc;
- int size;
+ cochran_data_t data;
+ data.logbook = NULL;
+ data.sample = NULL;
// Make sure buffer is good.
- if (!dc_buffer_clear(data)) {
+ if (!dc_buffer_clear(dump)) {
ERROR (abstract->context, "Uninitialized buffer.");
return DC_STATUS_INVALIDARGS;
}
- // Determine size for progress
- size = 512 + 512 + 1500 + device->info->rb_profile_end;
+ // Reserve space
+ if (!dc_buffer_resize(dump, device->info->rb_profile_end)) {
+ ERROR(abstract->context, "Insufficient buffer space available.");
+ return DC_STATUS_NOMEMORY;
+ }
+ // Determine size for progress
progress.current = 0;
- progress.maximum = size;
+ progress.maximum = 512 + device->info->rb_profile_end;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
- // Emit ID blocks as vendor data
- if (d->extra_id_flag) {
- vendor.data = d->id0;
- vendor.size = 67;
- device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
- }
-
- vendor.data = d->id;
- vendor.size = 67;
- device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
-
- rc = cochran_read_config (abstract, &progress);
- if (rc != DC_STATUS_SUCCESS)
- return rc;
-
- rc = cochran_read_misc (abstract, &progress);
+ rc = cochran_read_config (abstract, &data, &progress);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Read logbook and sample memory
- // Reserve space
- if (!dc_buffer_resize(data, device->info->rb_profile_end)) {
- ERROR(abstract->context, "Insufficient buffer space available.");
- return DC_STATUS_NOMEMORY;
- }
-
serial_sleep(device->port, 800);
// set back to 9600 baud
- cochran_commander_serial_setup(device);
+ rc = cochran_commander_serial_setup(device);
+ if (rc != DC_STATUS_SUCCESS) {
+ return rc;
+ }
// Read the sample data, from 0 to sample end will include logbook
rc = cochran_commander_read (abstract, &progress, 0,
- dc_buffer_get_data(data), device->info->rb_profile_end);
+ dc_buffer_get_data(dump), device->info->rb_profile_end);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the sample data.");
return rc;
@@ -935,15 +880,15 @@ cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
static unsigned int
cochran_guess_sample_end_address(cochran_device_t *device, cochran_data_t *data, unsigned int log_num)
{
- const unsigned char *log_entry = data->logbook + device->info->log_size * log_num;
+ const unsigned char *log_entry = data->logbook + device->info->logbook_entry_size * log_num;
if (log_num == data->dive_count)
- // Return next usable address from config0 page
- return array_uint32_le(data->config[0]
+ // Return next usable address from config page
+ return array_uint32_le(data->config
+ device->info->rb_profile_end);
// Next log's start address
- return array_uint32_le(log_entry + device->info->log_size + 6);
+ return array_uint32_le(log_entry + device->info->logbook_entry_size + 6);
}
@@ -952,7 +897,6 @@ 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 *data = &device->data;
unsigned int sample_start_address, sample_end_address;
dc_status_t rc;
@@ -960,28 +904,47 @@ cochran_commander_device_foreach (dc_device_t *abstract,
unsigned char *log_entry, *fingerprint, *sample, *dive;
int sample_size, dive_size;
- rc = cochran_commander_device_read_all (abstract);
+ cochran_data_t data;
+ data.logbook = NULL;
+ data.sample = NULL;
+ rc = cochran_commander_device_read_all (abstract, &data);
+
+ // Emit a device info event.
+ dc_event_devinfo_t devinfo;
+ devinfo.model = abstract->devinfo.model;
+ devinfo.firmware = 0; // unknown
+ devinfo.serial = array_uint32_le(data.config + device->conf_ptr->serial_number);
+ device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Loop through each dive
int i;
- for (i = data->dive_count - 1; i > data->fp_dive_num; i--) {
- log_entry = data->logbook + i * device->info->log_size;
+ for (i = data.dive_count - 1; i > data.fp_dive_num; i--) {
+ log_entry = data.logbook + i * device->info->logbook_entry_size;
sample_start_address = array_uint32_le (log_entry + 6);
- sample_end_address = array_uint32_le (log_entry + device->info->log_size / 2);
+ sample_end_address = array_uint32_le (log_entry + device->info->logbook_entry_size / 2);
+
+ // Validate
+ if (sample_start_address < device->info->rb_profile_begin
+ || sample_start_address > device->info->rb_profile_end
+ || sample_end_address < device->info->rb_profile_begin
+ || (sample_end_address > device->info->rb_profile_end
+ && sample_end_address != 0xFFFFFFFF)) {
+ continue;
+ }
if (sample_end_address == 0xFFFFFFFF)
// Corrupt dive, guess the end address
- sample_end_address = cochran_guess_sample_end_address(device, data, i);
+ sample_end_address = cochran_guess_sample_end_address(device, &data, i);
- sample = data->sample + sample_start_address - data->sample_data_offset;
+ sample = data.sample + sample_start_address - data.sample_data_offset;
// Determine size of sample
unsigned int dive_num =array_uint16_le(log_entry + device->log_ptr->dive_number);
- if (dive_num >= data->profile_tail)
+ if (dive_num >= data.profile_tail)
sample_size = sample_end_address - sample_start_address;
else
sample_size = 0;
@@ -991,28 +954,28 @@ cochran_commander_device_foreach (dc_device_t *abstract,
sample_size += device->info->rb_profile_end
- device->info->rb_profile_begin;
- fingerprint = log_entry + device->log_ptr->dive_number;
+ fingerprint = log_entry; // Date bytes
// Build dive blob
- dive_size = device->info->log_size + sample_size;
+ dive_size = device->info->logbook_entry_size + sample_size;
dive = (unsigned char *) malloc(dive_size);
if (dive == NULL)
return DC_STATUS_NOMEMORY;
- memcpy(dive, log_entry, device->info->log_size); // log
+ memcpy(dive, log_entry, device->info->logbook_entry_size); // log
// Copy profile data
if (sample_size) {
if (sample_start_address <= sample_end_address) {
- memcpy(dive + device->info->log_size, sample,
+ memcpy(dive + device->info->logbook_entry_size, sample,
sample_size);
} else {
// It wrapped the buffer, copy two sections
unsigned int size = device->info->rb_profile_end - sample_start_address;
- memcpy(dive + device->info->log_size, sample, size);
- memcpy(dive + device->info->log_size + size,
- data->sample, sample_end_address - device->info->rb_profile_begin);
+ memcpy(dive + device->info->logbook_entry_size, sample, size);
+ memcpy(dive + device->info->logbook_entry_size + size,
+ data.sample, sample_end_address - device->info->rb_profile_begin);
}
}
@@ -1038,16 +1001,16 @@ cochran_commander_device_foreach (dc_device_t *abstract,
*/
static void
-cochran_check_profiles(dc_device_t *abstract) {
+cochran_check_profiles(dc_device_t *abstract, cochran_data_t *data) {
cochran_device_t *device = (cochran_device_t *) abstract;
// Find head log entry
// Set handy point to first dive's dive number
- unsigned char *l = device->data.logbook + device->log_ptr->dive_number;
+ unsigned char *l = data->logbook + device->log_ptr->dive_number;
int head;
- for (head = 0; head < device->info->max_log - 1; head ++) {
+ for (head = 0; head < device->info->logbook_entry_count - 1; head ++) {
int this_dive = array_uint16_le(l);
- l += device->info->log_size;
+ l += device->info->logbook_entry_size;
int next_dive = array_uint16_le(l);
if (next_dive < this_dive || next_dive == 0xFFFF)
@@ -1057,9 +1020,9 @@ cochran_check_profiles(dc_device_t *abstract) {
// This is the last piece of data
unsigned int head_ptr;
if (device->info->endian == ENDIAN_LE)
- head_ptr = array_uint32_le(device->data.config[0] + device->conf_ptr->last_log);
+ head_ptr = array_uint32_le(data->config + device->conf_ptr->last_log);
else
- head_ptr = array_uint32_be(device->data.config[0] + device->conf_ptr->last_log);
+ head_ptr = array_uint32_be(data->config + device->conf_ptr->last_log);
// Cochran (commander at least) erases 8k blocks, so round up
head_ptr = (head_ptr & 0xfffff000) + 0x2000;
@@ -1071,16 +1034,16 @@ cochran_check_profiles(dc_device_t *abstract) {
int profile_wrap = 0;
int n = head - 1;
if (n < 0)
- n = MIN(device->info->max_log - 1, head);
+ n = MIN(device->info->logbook_entry_count - 1, head);
while (n != head) {
- unsigned int start_dive_ptr = array_uint32_le(device->data.logbook + device->info->log_size * n + device->log_ptr->profile_begin_offset);
- unsigned int end_dive_ptr = array_uint32_le(device->data.logbook + device->info->log_size * n + device->log_ptr->profile_end_offset);
+ unsigned int start_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_begin_offset);
+ unsigned int end_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_end_offset);
if (start_dive_ptr == 0xFFFFFFFF || start_dive_ptr == 0) {
n--;
if (n < 0)
- n = MIN(device->info->max_log - 1, head);
+ n = MIN(device->info->logbook_entry_count - 1, head);
continue;
}
@@ -1098,11 +1061,11 @@ cochran_check_profiles(dc_device_t *abstract) {
n--;
if (n < 0)
- n = MIN(device->info->max_log - 1, head);
+ n = MIN(device->info->logbook_entry_count - 1, head);
}
- device->data.log_head = head;
- device->data.profile_head = head;
+ data->log_head = head;
+ data->profile_head = head;
- device->data.profile_tail = tail;
+ data->profile_tail = tail;
}
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index 22f17a3..f6e3921 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -24,30 +24,21 @@
#define COCHRAN_TIMESTAMP_OFFSET 694242000
#define COCHRAN_MODEL_SIZE 8
-#define COCHRAN_FINGERPRINT_SIZE 2
+#define COCHRAN_FINGERPRINT_SIZE 6
#define UNSUPPORTED 0xFFFFFFFF
-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;
+#define COCHRAN_MODEL_UNKNOWN = -1,
+#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0
+#define COCHRAN_MODEL_EMC_14 1
+#define COCHRAN_MODEL_EMC_16 2
+#define COCHRAN_MODEL_EMC_20 3
typedef enum cochran_endian_t {
ENDIAN_LE,
ENDIAN_BE,
} cochran_endian_t;
-typedef enum cochran_addresssize_t {
- ADDRESS_24_BIT,
- ADDRESS_32_BIT,
-} cochran_addresssize_t;
-
typedef enum cochran_sample_format_t {
SAMPLE_UNKNOWN,
SAMPLE_CMDR,
@@ -58,8 +49,8 @@ typedef enum cochran_sample_format_t {
// Used in reading the information from the device
// and (in the case of max_*) used when decoding.
typedef struct cochran_device_info_t {
- cochran_model_t model;
- cochran_addresssize_t address_size;
+ int model;
+ int address_bits;
cochran_endian_t endian;
int high_baud;
@@ -68,8 +59,8 @@ typedef struct cochran_device_info_t {
int rb_profile_begin;
int rb_profile_end;
- int log_size;
- int max_log;
+ int logbook_entry_size;
+ int logbook_entry_count;
int max_gas;
cochran_sample_format_t sample_format;
@@ -80,6 +71,7 @@ typedef struct cochran_conf_offsets_t {
int dive_count;
int last_log;
int last_interdive;
+ int serial_number;
} cochran_conf_offsets_t;
// Offsets into each log block
@@ -104,18 +96,11 @@ typedef struct cochran_log_offsets_t {
} cochran_log_offsets_t;
typedef struct cochran_data_t {
- unsigned char id0[67];
- unsigned char id[67];
- unsigned char config[2][512];
- unsigned char misc[1500];
+ unsigned char config[512];
unsigned char *logbook;
unsigned char *sample;
- unsigned int extra_id_flag;
- unsigned int config_count;
-
unsigned short int dive_count;
- unsigned char fingerprint[COCHRAN_FINGERPRINT_SIZE];
int fp_dive_num;
int log_head, log_tail; // head and tail for log ringbuffer
int profile_head, profile_tail; // Entries that have valid profiles
@@ -133,14 +118,13 @@ struct event_size {
typedef struct cochran_device_t {
dc_device_t base;
- const char *name; // serial port name
serial_t *port;
unsigned char model_string[COCHRAN_MODEL_SIZE + 1];
- cochran_device_info_t *info;
- cochran_conf_offsets_t *conf_ptr;
- cochran_log_offsets_t *log_ptr;
- struct event_size (*event_bytes)[15];
- cochran_data_t data; // dive data used in parsing
+ unsigned char fingerprint[COCHRAN_FINGERPRINT_SIZE];
+ const cochran_device_info_t *info;
+ const cochran_conf_offsets_t *conf_ptr;
+ const cochran_log_offsets_t *log_ptr;
+ const struct event_size (*event_bytes)[15];
} cochran_device_t;
@@ -157,4 +141,4 @@ dc_status_t cochran_commander_device_dump (dc_device_t *abstract,
dc_buffer_t *data);
int cochran_commander_model_id(const char *model);
dc_status_t cochran_commander_info(const int model,
- cochran_device_info_t **info, cochran_conf_offsets_t **conf_ptr, cochran_log_offsets_t **log_ptr, struct event_size (**event_bytes)[15]);
+ const cochran_device_info_t **info, const cochran_conf_offsets_t **conf_ptr, const cochran_log_offsets_t **log_ptr, const struct event_size (**event_bytes)[15]);
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c
index 45184fe..0100a94 100644
--- a/src/cochran_commander_parser.c
+++ b/src/cochran_commander_parser.c
@@ -81,9 +81,9 @@ typedef struct cochran_commander_parser_t cochran_commander_parser_t;
struct cochran_commander_parser_t {
dc_parser_t base;
unsigned int model;
- cochran_device_info_t *info;
- cochran_log_offsets_t *log_ptr;
- struct event_size (*event_bytes)[15];
+ const cochran_device_info_t *info;
+ const cochran_log_offsets_t *log_ptr;
+ const struct event_size (*event_bytes)[15];
};
static dc_parser_vtable_t cochran_commander_parser_vtable = {
@@ -136,7 +136,7 @@ cochran_commander_parser_get_datetime (dc_parser_t *abstract,
dc_datetime_t *datetime)
{
cochran_commander_parser_t *parser = (cochran_commander_parser_t *) abstract;
- cochran_log_offsets_t *l = parser->log_ptr;
+ const cochran_log_offsets_t *l = parser->log_ptr;
const unsigned char *log_entry = abstract->data;
datetime->second = log_entry[l->sec];
@@ -220,7 +220,7 @@ cochran_commander_handle_event (dc_parser_t *abstract,
* Used to find the end of a dive that has an incomplete dive-end
* block. It parses backwards past inter-dive events.
*/
-int cochran_backparse(dc_parser_t *abstract, unsigned const char *samples, int size, struct event_size (*event_bytes)[15]) {
+int cochran_backparse(dc_parser_t *abstract, unsigned const char *samples, int size, const struct event_size (*event_bytes)[15]) {
int result = size, best_result = size;
for (int x = 0; (*event_bytes)[x].code != -1; x++) {
@@ -351,9 +351,9 @@ cochran_commander_parser_samples_foreach (dc_parser_t *abstract,
const cochran_commander_parser_t *parser = (cochran_commander_parser_t *) abstract;
const cochran_log_offsets_t *l = parser->log_ptr;
const unsigned char *log_entry = abstract->data;
- const unsigned char *samples = log_entry + parser->info->log_size;
+ const unsigned char *samples = log_entry + parser->info->logbook_entry_size;
- unsigned int size = abstract->size - parser->info->log_size;
+ unsigned int size = abstract->size - parser->info->logbook_entry_size;
int sampling_size;
switch (parser->info->sample_format) {
--
2.4.3
More information about the devel
mailing list