devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2014
- 11 participants
- 16 discussions
This changes the data passed back by the foreach function and the data
that is passed to the parser. It creates a structure containing everything
needed to parse the dive. Pointers were removed so that the data can be
stored and parsed later.
Fixed a typo in COCHRAN_TIMESTAMP_OFFSET.
Fixed a bug that occured in calculating NDL and Deco time if an event
occurred between samples.
Added start temperature to Commander parse.
Made corrupt dive recovery cleaner.
Cleaned up many compiler warnings (-Wall)
Cleaned up some whitespace
Re-wrapped some lines.
Removed extraneous parenthesis not needed with & operator.
Seperated device configuration from device handle (more or less)
Cleaned up sample buffer wrap-around logic and used better var naming.
Fixed typo in CMD_START_OFFSET
---
src/cochran_cmdr_parser.c | 66 +++++-----
src/cochran_commander.c | 288 ++++++++++++++++++++++++-----------------
src/cochran_commander.h | 59 +++++----
src/cochran_commander_parser.c | 57 +++++---
src/cochran_commander_parser.h | 2 +
src/cochran_emc_parser.c | 182 ++++++++++++--------------
6 files changed, 353 insertions(+), 301 deletions(-)
diff --git a/src/cochran_cmdr_parser.c b/src/cochran_cmdr_parser.c
index de25912..b2b9748 100644
--- a/src/cochran_cmdr_parser.c
+++ b/src/cochran_cmdr_parser.c
@@ -35,15 +35,12 @@
#include "cochran_commander_parser.h"
-#define SZ_SAMPLE 2
-
-
dc_status_t
cochran_cmdr_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;
- unsigned char *log = data->current_log;
+ const unsigned char *data = abstract->data;
+ const unsigned char *log = data + COCHRAN_MODEL_SIZE;
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_salinity_t *water = (dc_salinity_t *) value;
@@ -53,31 +50,35 @@ cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
case DC_FIELD_TEMPERATURE_SURFACE:
*((unsigned int*) value) = ((float) log[CMD_START_TEMP] - 32) / 1.8;
case DC_FIELD_TEMPERATURE_MINIMUM:
- *((unsigned int*) value) = ((float) log[CMD_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+ *((unsigned int*) value) = ((float) log[CMD_MIN_TEMP] / 2
+ + 20 - 32) / 1.8;
case DC_FIELD_TEMPERATURE_MAXIMUM:
- *((unsigned int*) value) = ((float) log[CMD_MAX_TEMP] / 2 + 20 - 32) / 1.8;
+ *((unsigned int*) value) = ((float) log[CMD_MAX_TEMP] / 2
+ + 20 - 32) / 1.8;
case DC_FIELD_DIVETIME:
*((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60;
break;
case DC_FIELD_MAXDEPTH:
- *((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH) / 4 * FEET;
+ *((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH)
+ / 4 * FEET;
break;
case DC_FIELD_AVGDEPTH:
- *((double *) value) = (float) array_uint16_le (log + CMD_AVG_DEPTH) / 4 * FEET;
+ *((double *) value) = (float) array_uint16_le (log + CMD_AVG_DEPTH)
+ / 4 * FEET;
break;
case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = 2;
break;
case DC_FIELD_GASMIX:
- gasmix->oxygen = (double) array_uint16_le ((char *)log
+ gasmix->oxygen = (double) array_uint16_le (log
+ CMD_O2_PERCENT + 2 * flags) / 256 / 100;
gasmix->helium = 0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
case DC_FIELD_SALINITY:
// 0 = low conductivity, 1 = high, maybe there's a 2?
- water->type = ( (log[CMD_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
- : DC_WATER_SALT );
+ water->type = ( (log[CMD_WATER_CONDUCTIVITY] & 0x3) == 0
+ ? DC_WATER_FRESH : DC_WATER_SALT );
water->density = 1000 + 12.5 * (log[CMD_WATER_CONDUCTIVITY] & 0x3);
break;
case DC_FIELD_ATMOSPHERIC:
@@ -97,11 +98,12 @@ dc_status_t
cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
dc_sample_callback_t callback, void *userdata)
{
- cochran_data_t *data = (cochran_data_t *)abstract->data;
- unsigned char *sdata = data->current_sample;
- unsigned char *log = data->current_log;
- unsigned int size = data->current_sample_size;
- unsigned char *s;
+ const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+ const unsigned char *samples = log + COCHRAN_CMDR_LOG_SIZE;
+
+ unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+ - COCHRAN_CMDR_LOG_SIZE;
+ const unsigned char *s;
dc_sample_value_t sample = {0}, empty_sample = {0};
unsigned int time = 0, last_sample_time;
@@ -109,8 +111,10 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
double temperature;
double depth;
double ascent_rate;
- unsigned char deco_obligation = 0;
- unsigned int deco_time = 0;
+ unsigned char corrupt_dive = 0;
+
+ if (array_uint32_le(log + COCHRAN_CMDR_LOG_SIZE / 2) == 0xFFFFFFFF)
+ corrupt_dive = 1;
// Cochran samples depth every second and varies between ascent rate
// and temp ever other second.
@@ -124,8 +128,8 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
sample.depth = depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
- // TODO: sample.temperature = (log + CMD_START_TEMP - 32) / 1.8;
- // TODO: if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
+ sample.temperature = (float) *(log + CMD_START_TEMP) - 32 / 1.8;
+ if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
while (offset < size) {
sample = empty_sample;
@@ -137,13 +141,10 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
callback (DC_SAMPLE_TIME, sample, userdata);
}
- if (offset > data->sample_memory_end_address)
- s = sdata + offset - data->sample_memory_end_address - 1;
- else
- s = sdata + offset;
+ s = samples + offset;
// If corrupt_dive end before offset
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
if ( s[0] == 0x10
|| s[0] == 0xFF
|| s[0] == 0xA8) {
@@ -155,17 +156,12 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
// Check for event
if (s[0] & 0x80) {
- offset += cochran_commander_handle_event(abstract, callback, userdata,
- s[0], offset, time);
- if (s[0] == 0xC5)
- deco_obligation = 1; // Deco obligation begins
- else if (s[0] == 0xC8)
- deco_obligation = 0; // Deco obligation ends
-
+ offset += cochran_commander_handle_event(abstract, callback,
+ userdata, s[0], offset, time);
continue;
}
-
+
// Depth is logged as change in feet, bit 0x40 means negative depth
depth += (float) (s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
sample.depth = depth * FEET;
@@ -186,7 +182,7 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
}
time ++;
- offset += SZ_SAMPLE;
+ offset += COCHRAN_CMDR_SAMPLE_SIZE;
}
return DC_STATUS_SUCCESS;
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index e8884c1..fdcac67 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -42,13 +42,17 @@ 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 */
+ NULL, /* write */
cochran_commander_device_dump, /* dump */
cochran_commander_device_foreach, /* foreach */
cochran_commander_device_close /* close */
};
+static dc_status_t
+cochran_read_id(dc_device_t *device);
+
+
dc_status_t
cochran_packet (cochran_device_t *device, const unsigned char command[],
unsigned int csize, unsigned char answer[], unsigned int asize,
@@ -76,9 +80,9 @@ cochran_packet (cochran_device_t *device, const unsigned char command[],
// 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_configure(device->port, device->data.conf.high_baud, 8,
SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
- serial_configure(device->port, device->data.high_baud, 8,
+ serial_configure(device->port, device->data.conf.high_baud, 8,
SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
}
@@ -202,7 +206,8 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
device->progress = NULL;
device->data.logbook = NULL;
device->data.sample = NULL;
- cochran_commander_device_set_fingerprint((dc_device_t *) device, "", 0);
+ cochran_commander_device_set_fingerprint((dc_device_t *) device,
+ NULL, 0);
rc = cochran_commander_serial_open(device, context);
if (rc != DC_STATUS_SUCCESS)
@@ -219,8 +224,13 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
}
// Check ID
- if ((device->data.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
- ERROR (context, "Device not recognized.");
+ if ((device->data.conf.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
+ ERROR (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));
serial_close (device->port);
free (device);
return DC_STATUS_UNSUPPORTED;
@@ -257,15 +267,15 @@ 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);
+ 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));
+ memcpy (&d->fingerprint, data, sizeof (d->fingerprint));
else
- memset (&(d->fingerprint), 0xFF, sizeof (d->fingerprint));
+ memset (&d->fingerprint, 0xFF, sizeof (d->fingerprint));
return DC_STATUS_SUCCESS;
}
@@ -281,7 +291,7 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address,
unsigned char command[10];
unsigned char command_size;
- switch (device->data.address_length)
+ switch (device->data.conf.address_length)
{
case COCHRAN_ADDRESS_LENGTH_32:
// EMC uses 32 bit addressing
@@ -322,71 +332,65 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address,
}
-static void
-cochran_set_device_config (cochran_device_t *device)
+void
+cochran_commander_get_config (const unsigned char *model,
+ cochran_config_t *conf)
{
- dc_device_t *abstract = (dc_device_t *) device;
// Determine model
- if (memcmp(device->data.id + 0x3B, "AM2315\xA3\x71", 8) == 0)
+ if (memcmp(model, "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)
+ conf->model = COCHRAN_MODEL_EMC_20;
+ conf->log_size = 512;
+ conf->sample_memory_start_address = 0x94000;
+ conf->dive_num_ptr = 0x56;
+ conf->dive_count_ptr = 0xD2;
+ conf->dive_count_endian = COCHRAN_LE_TYPE;
+ conf->sample_end_ptr = 256;
+ conf->log_pre_dive_ptr = 30;
+ conf->log_end_dive_ptr = 256;
+ conf->last_interdive_ptr = 233;
+ conf->last_entry_ptr = 194;
+ conf->date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+ conf->address_length = COCHRAN_ADDRESS_LENGTH_32;
+ conf->high_baud = 825600;
+ }
+ else if (memcmp(model, "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)
+ conf->model = COCHRAN_MODEL_EMC_16;
+ conf->log_size = 512;
+ conf->sample_memory_start_address = 0x94000;
+ conf->dive_num_ptr = 0x56;
+ conf->dive_count_ptr = 0xD2;
+ conf->dive_count_endian = COCHRAN_LE_TYPE;
+ conf->sample_end_ptr = 256;
+ conf->log_pre_dive_ptr = 30;
+ conf->log_end_dive_ptr = 256;
+ conf->last_interdive_ptr = 233;
+ conf->last_entry_ptr = 194;
+ conf->date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+ conf->address_length = COCHRAN_ADDRESS_LENGTH_32;
+ conf->high_baud = 825600;
+ }
+ else if (memcmp(model, "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;
+ conf->model = COCHRAN_MODEL_COMMANDER_AIR_NITROX;
+ conf->log_size = 256;
+ conf->sample_memory_start_address = 0x20000;
+ conf->dive_num_ptr = 0x46;
+ conf->dive_count_ptr = 0x46;
+ conf->dive_count_endian = COCHRAN_BE_TYPE;
+ conf->sample_end_ptr = 256;
+ conf->log_pre_dive_ptr = 30;
+ conf->log_end_dive_ptr = 128;
+ conf->last_interdive_ptr = 167;
+ conf->last_entry_ptr = -1;
+ conf->date_format = COCHRAN_DATE_FORMAT_MSDHYM;
+ conf->address_length = COCHRAN_ADDRESS_LENGTH_24;
+ conf->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));
+ conf->model = 0;
}
return;
@@ -404,7 +408,7 @@ cochran_read_id (dc_device_t *abstract)
if (rc != DC_STATUS_SUCCESS)
return rc;
- if (strncmp(device->data.id, "(C)", 3) != 0) {
+ if (strncmp((const char *)device->data.id, "(C)", 3) != 0) {
// It's a Commander, read again
memcpy(device->data.id0, device->data.id, 67);
@@ -416,7 +420,8 @@ cochran_read_id (dc_device_t *abstract)
return rc;
}
- cochran_set_device_config(device);
+ cochran_commander_get_config(device->data.id + 0x3B, &device->data.conf);
+
return DC_STATUS_SUCCESS;
}
@@ -427,10 +432,11 @@ 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)
+ if ((data->conf.model & 0xFF0000) == COCHRAN_MODEL_EMC_FAMILY)
data->config_count = 2;
else
data->config_count = 4;
@@ -454,7 +460,7 @@ cochran_read_misc (dc_device_t *abstract)
unsigned char command[7] = { 0x89, 0x05, 0x00, 0x00, 0x00, 0xDC, 0x05 };
- switch (device->data.model & 0xFF0000)
+ switch (device->data.conf.model & 0xFF0000)
{
case COCHRAN_MODEL_COMMANDER_FAMILY:
command[2] = 0xCA;
@@ -486,7 +492,7 @@ 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);
+ cochran_data_t *d = &device->data;
dc_status_t rc;
if (d->logbook)
@@ -516,7 +522,8 @@ cochran_read_logbook (dc_device_t *abstract)
cochran_commander_serial_setup(device, abstract->context);
// Request log book
- rc = cochran_commander_device_read(abstract, 0, d->logbook, d->logbook_size);
+ 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);
@@ -530,14 +537,15 @@ 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);
+ cochran_data_t *d = (cochran_data_t *) &device->data;
+ cochran_config_t *conf = &d->conf;
// 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,
+ while (d->fp_dive_num >= 0 && memcmp(&d->fingerprint,
+ d->logbook + d->fp_dive_num * conf->log_size
+ + conf->dive_num_ptr,
sizeof(d->fingerprint)))
d->fp_dive_num--;
}
@@ -547,8 +555,9 @@ 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;
+ cochran_data_t *d = (cochran_data_t *) &device->data;
+ cochran_config_t *conf = &d->conf;
+ unsigned int pre_dive_offset = 0, end_dive_offset = 0;
unsigned int low_offset, high_offset;
// Find lowest and highest offsets into sample data
@@ -557,10 +566,10 @@ cochran_get_sample_parms(dc_device_t *abstract)
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]));
+ pre_dive_offset = array_uint32_le (&(d->logbook[i * conf->log_size
+ + conf->log_pre_dive_ptr]));
+ end_dive_offset = array_uint32_le (&(d->logbook[i * conf->log_size
+ + conf->log_end_dive_ptr]));
// Check for ring buffer wrap-around.
if (pre_dive_offset > end_dive_offset)
@@ -577,8 +586,8 @@ cochran_get_sample_parms(dc_device_t *abstract)
// 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;
+ conf->sample_memory_end_address = high_offset;
+ low_offset = conf->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) {
@@ -597,7 +606,7 @@ 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);
+ cochran_data_t *d = (cochran_data_t *) &device->data;
dc_status_t rc;
@@ -649,7 +658,8 @@ 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);
+ cochran_data_t *d = (cochran_data_t *) &device->data;
+ cochran_config_t *conf = &d->conf;
dc_status_t rc;
@@ -663,12 +673,12 @@ cochran_commander_device_read_all (dc_device_t *abstract)
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);
+ if (conf->dive_count_endian == COCHRAN_LE_TYPE)
+ d->dive_count = array_uint16_le (d->config[0] + conf->dive_count_ptr);
else
- d->dive_count = array_uint16_be (d->config[0] + d->dive_count_ptr);
+ d->dive_count = array_uint16_be (d->config[0] + conf->dive_count_ptr);
- d->logbook_size = ((d->dive_count * d->log_size) & 0xFFFFC000)
+ d->logbook_size = ((d->dive_count * conf->log_size) & 0xFFFFC000)
+ 0x4000;
rc = cochran_read_logbook(abstract);
@@ -696,11 +706,11 @@ 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);
+ cochran_data_t *d = (cochran_data_t *) &device->data;
int ptr = 0;
dc_status_t rc;
- char *b;
+ unsigned char *b;
int size;
rc = cochran_commander_device_read_all (abstract);
@@ -816,16 +826,42 @@ cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
}
+/*
+* For corrupt dives the end-of-samples pointer is 0xFFFFFFFF
+* search for a reasonable size, e.g. using next dive start sample
+* or end-of-samples to limit searching for recoverable samples
+*/
+
+static unsigned int
+cochran_guess_sample_end_address(cochran_data_t *data, unsigned int log_num)
+{
+ cochran_config_t *conf = &data->conf;
+ const unsigned char *log = data->logbook + data->conf.log_size * log_num;
+
+ if (log_num == data->dive_count)
+ // Return next usable address from config0 page
+ return array_uint32_le(data->config[0]
+ + conf->sample_memory_end_address);
+
+ // Next log's start address
+ return array_uint32_le(log + conf->log_size + 6);
+}
+
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;
+ cochran_data_t *data = &device->data;
+ cochran_config_t *conf = &data->conf;
+
+ unsigned int sample_start_address, sample_end_address;
dc_status_t rc;
+ unsigned char *log, *fingerprint, *sample, *dive;
+ int sample_size, dive_size;
+
rc = cochran_commander_device_read_all (abstract);
if (rc != DC_STATUS_SUCCESS)
@@ -833,36 +869,54 @@ cochran_commander_device_foreach (dc_device_t *abstract,
// Loop through each dive
int i;
- for (i = d->dive_count - 1; i > d->fp_dive_num; i--) {
+ for (i = data->dive_count - 1; i > data->fp_dive_num; i--) {
+ log = data->logbook + i * conf->log_size;
- d->current_log = d->logbook + i * d->log_size;
+ sample_start_address = array_uint32_le (log + 6);
+ sample_end_address = array_uint32_le (log + conf->log_size / 2);
- sample_start_offset = array_uint32_le (d->current_log + 6);
- sample_end_offset = array_uint32_le (d->current_log
- + d->log_size/2);
+ if (sample_end_address == 0xFFFFFFFF)
+ // Corrupt dive, guess the end address
+ sample_end_address = cochran_guess_sample_end_address(data, i);
- d->current_sample = d->sample + sample_start_offset
- - d->sample_data_offset;
+ sample = data->sample + sample_start_address - data->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;
+ // Determine size of sample
+ sample_size = sample_end_address - sample_start_address;
+ if (sample_size < 0)
+ // Adjust for ring buffer wrap-around
+ sample_size += conf->sample_memory_end_address
+ - conf->sample_memory_start_address;
- // 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;
+ fingerprint = log + conf->dive_num_ptr;
+
+ // Build dive blob
+ dive_size = COCHRAN_MODEL_SIZE + conf->log_size + sample_size;
+ dive = malloc(dive_size);
+ if (dive == NULL)
+ return DC_STATUS_NOMEMORY;
- d->current_fingerprint = d->current_log + d->dive_num_ptr;
+ memcpy(dive, data->id + 0x3B, 8); // model string
+ memcpy(dive + COCHRAN_MODEL_SIZE, log, conf->log_size);
+ if (sample_start_address <= sample_end_address) {
+ memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size, sample,
+ sample_size);
+ } else {
+ // It wrapped the buffer, copy two sections
+ unsigned int size = conf->sample_memory_end_address
+ - sample_start_address;
+ memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size, sample, size);
+ memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size + size,
+ data->sample, sample_size - size);
+ }
- if (callback && !callback ((unsigned char *) d, sizeof(device->data),
- d->current_fingerprint, sizeof (d->fingerprint), userdata))
+ if (callback && !callback ((unsigned char *) dive, dive_size,
+ fingerprint, COCHRAN_FINGERPRINT_SIZE, userdata)) {
+ free(dive);
return DC_STATUS_SUCCESS;
+ }
+
+ free(dive);
}
return DC_STATUS_SUCCESS;
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index e259977..8fa6228 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -21,7 +21,16 @@
// 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_TIMESTAMP_OFFSET 694242000
+
+#define COCHRAN_MODEL_SIZE 8
+#define COCHRAN_FINGERPRINT_SIZE 2
+
+#define COCHRAN_EMC_LOG_SIZE 512
+#define COCHRAN_EMC_SAMPLE_SIZE 3
+
+#define COCHRAN_CMDR_LOG_SIZE 256
+#define COCHRAN_CMDR_SAMPLE_SIZE 2
#define COCHRAN_LE_TYPE 0
#define COCHRAN_BE_TYPE 1
@@ -42,9 +51,26 @@ typedef enum cochran_model_t {
COCHRAN_MODEL_COMMANDER_AIR_NITROX,
} cochran_model_t;
-typedef struct cochran_data_t {
+// Device configuration items
+typedef struct cochran_config_t {
cochran_model_t model;
+ 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
+} cochran_config_t;
+typedef struct cochran_data_t {
unsigned char id0[67];
unsigned char id[67];
unsigned char config[4][512];
@@ -56,38 +82,17 @@ typedef struct cochran_data_t {
unsigned int config_count;
unsigned short int dive_count;
- unsigned char fingerprint[2];
+ unsigned char fingerprint[COCHRAN_FINGERPRINT_SIZE];
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;
-
- // 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_config_t conf;
} cochran_data_t;
typedef struct cochran_device_t {
@@ -106,7 +111,7 @@ typedef struct cochran_device_t {
#define CMD_DAY 2
#define CMD_MON 5
#define CMD_YEAR 4
-#define CME_START_OFFSET 6 // 4 bytes
+#define CMD_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
@@ -153,8 +158,8 @@ 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);
+void cochran_commander_get_config(const unsigned char *model, cochran_config_t *conf);
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c
index 547dad4..8db87cf 100644
--- a/src/cochran_commander_parser.c
+++ b/src/cochran_commander_parser.c
@@ -107,10 +107,13 @@ 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;
+ const unsigned char *data = abstract->data;
+ const unsigned char *log = data + COCHRAN_MODEL_SIZE;
+ cochran_config_t conf;
- if (data->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
+ cochran_commander_get_config(data, &conf);
+
+ if (conf.date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
datetime->second = log[0];
datetime->minute = log[1];
datetime->hour = log[2];
@@ -133,9 +136,11 @@ 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;
+ cochran_config_t conf;
+
+ cochran_commander_get_config(abstract->data, &conf);
- switch (data->model & 0xFF0000)
+ switch (conf.model & 0xFF0000)
{
case COCHRAN_MODEL_COMMANDER_FAMILY:
return cochran_cmdr_parser_get_field(abstract, type, flags, value);
@@ -144,15 +149,19 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
return cochran_emc_parser_get_field(abstract, type, flags, value);
break;
}
+
+ return DC_STATUS_UNSUPPORTED;
}
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;
+ cochran_config_t conf;
- switch (data->model & 0xFF0000)
+ cochran_commander_get_config(abstract->data, &conf);
+
+ switch (conf.model & 0xFF0000)
{
case COCHRAN_MODEL_COMMANDER_FAMILY:
return cochran_cmdr_parser_samples_foreach(abstract, callback,
@@ -163,29 +172,37 @@ cochran_commander_parser_samples_foreach (dc_parser_t *abstract,
userdata);
break;
}
+
+ return DC_STATUS_UNSUPPORTED;
}
+void
+cochran_commander_get_event_info(const unsigned char code,
+ cochran_events_t *event)
+{
+ cochran_events_t *events = cochran_events;
+ unsigned char i = 0;
+
+ while (events[i].code && events[i].code != code)
+ i++;
+ *event = events[i];
+}
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};
+ cochran_events_t event;
- unsigned char event_ptr = 0;
-
- while (e[event_ptr].code && e[event_ptr].code != code)
- event_ptr++;
+ cochran_commander_get_event_info(code, &event);
sample.event.time = 0;
- if (e[event_ptr].code) {
- switch (e[event_ptr].code)
+ if (event.code) {
+ switch (code)
{
case 0xAB: // Ceiling decrease
// Indicated to lower ceiling by 10 ft (deeper)
@@ -199,9 +216,9 @@ cochran_commander_handle_event (dc_parser_t *abstract,
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 (! event.type == SAMPLE_EVENT_NONE) {
+ sample.event.type = event.type;
+ sample.event.flags = event.flag;
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
}
}
@@ -213,5 +230,5 @@ cochran_commander_handle_event (dc_parser_t *abstract,
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
}
- return e[event_ptr].data_bytes;
+ return event.data_bytes;
}
diff --git a/src/cochran_commander_parser.h b/src/cochran_commander_parser.h
index 314d538..44340b5 100644
--- a/src/cochran_commander_parser.h
+++ b/src/cochran_commander_parser.h
@@ -97,6 +97,8 @@ 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);
+void cochran_commander_get_event_info(const unsigned char code,
+ cochran_events_t *event);
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);
diff --git a/src/cochran_emc_parser.c b/src/cochran_emc_parser.c
index 8a554cb..5b4af81 100644
--- a/src/cochran_emc_parser.c
+++ b/src/cochran_emc_parser.c
@@ -52,13 +52,15 @@ dc_status_t
cochran_emc_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;
- unsigned char *log = data->current_log;
+ const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+ unsigned char corrupt_dive = 0;
+
+ if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+ corrupt_dive = 1;
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_salinity_t *water = (dc_salinity_t *) value;
- unsigned int dive_time;
struct dive_stats stats;
if (value) {
@@ -67,28 +69,30 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int*) value) = ((float) log[EMC_START_TEMP] - 32) / 1.8;
break;
case DC_FIELD_TEMPERATURE_MINIMUM:
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
*((unsigned int*) value) = stats.min_temp;
} else
- *((unsigned int*) value) = ((float) log[EMC_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+ *((unsigned int*) value) = ((float) log[EMC_MIN_TEMP] / 2
+ + 20 - 32) / 1.8;
break;
case DC_FIELD_TEMPERATURE_MAXIMUM:
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
*((unsigned int*) value) = stats.max_temp;
} else
- *((unsigned int*) value) = ((float) log[EMC_MAX_TEMP] / 2 + 20 - 32) / 1.8;
+ *((unsigned int*) value) = ((float) log[EMC_MAX_TEMP] / 2
+ + 20 - 32) / 1.8;
break;
case DC_FIELD_DIVETIME:
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
*((unsigned int*) value) = stats.dive_time;
} else
*((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60;
break;
case DC_FIELD_MAXDEPTH:
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
*((unsigned int*) value) = stats.max_depth;
} else
@@ -96,7 +100,7 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
* FEET;
break;
case DC_FIELD_AVGDEPTH:
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
*((unsigned int*) value) = stats.avg_depth;
} else
@@ -107,16 +111,16 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = 10;
break;
case DC_FIELD_GASMIX:
- gasmix->oxygen = (double) array_uint16_le ((char *) log
+ gasmix->oxygen = (double) array_uint16_le (log
+ EMC_O2_PERCENT + 2 * flags) / 256 / 100;
- gasmix->helium = (double) array_uint16_le ((char *) log
+ gasmix->helium = (double) array_uint16_le (log
+ EMC_HE_PERCENT + 2 * flags) / 256 / 100;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
case DC_FIELD_SALINITY:
// 0 = low conductivity, 2 = high, maybe there's a 1?
- water->type = ( (log[EMC_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
- : DC_WATER_SALT );
+ water->type = ( (log[EMC_WATER_CONDUCTIVITY] & 0x3) == 0
+ ? DC_WATER_FRESH : DC_WATER_SALT );
water->density = 1000 + 12.5 * (log[EMC_WATER_CONDUCTIVITY] & 0x3);
break;
case DC_FIELD_ATMOSPHERIC:
@@ -131,54 +135,17 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
return DC_STATUS_SUCCESS;
}
-/*
-* For corrupt dives the end-of-samples pointer is 0xFFFFFFFF
-* search for a reasonable size, e.g. using next dive start sample
-* or end-of-samples to limit searching for recoverable samples
-*/
-static unsigned int
-cochran_emc_guess_sample_size(cochran_data_t *data)
-{
- unsigned int size = 0;
- unsigned int offset, next_offset, memory_start_offset, memory_end_offset;
-
- // Get memory boundries
- memory_start_offset = array_uint32_le(data->config[0]
- + data->sample_memory_start_address);
- memory_end_offset = array_uint32_le(data->config[0]
- + data->sample_memory_end_address);
-
- // see if there is a next sample
- if (data->current_log - data->logbook + 512 >= data->logbook_size) {
- // we are the last log entry, use maximum data
- size = memory_end_offset - offset + 1;
- } else {
- offset = array_uint32_le(data->current_log + 6);
- next_offset = array_uint32_le(data->current_log + 512 + 30);
-
- if (next_offset >= offset) {
- size = next_offset - offset + 1;
- } else {
- // samples wrap to begin of memory
- size = memory_end_offset - offset + next_offset
- - memory_start_offset + 2;
- }
- }
-
- return (size);
-}
-
-
dc_status_t
cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
dc_sample_callback_t callback, void *userdata)
{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
- unsigned char *sdata = data->current_sample;
- unsigned char *log = data->current_log;
- unsigned int size = data->current_sample_size;
- unsigned char *s;
+ const unsigned char *data = abstract->data;
+ const unsigned char *log = data + COCHRAN_MODEL_SIZE;
+ const unsigned char *samples = log + COCHRAN_EMC_LOG_SIZE;
+ unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+ - COCHRAN_EMC_LOG_SIZE;
+ const unsigned char *s;
dc_sample_value_t sample = {0}, empty_sample = {0};
unsigned int time = 0, last_sample_time;
@@ -188,18 +155,18 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
double ascent_rate;
unsigned char deco_obligation = 0;
unsigned int deco_ceiling = 0;
- unsigned int deco_time = 0;
+ unsigned int deco_time;
+ unsigned char corrupt_dive = 0;
- if (data->corrupt_dive) {
- // Size of sample data is wrong, make a guess
- size = cochran_emc_guess_sample_size(data);
- }
+
+ if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+ corrupt_dive = 1;
/*
* Cochran samples depth every second and varies between ascent rate
* and temp ever other second.
* In the 21st, 22nd, 23rd, 24th samples are NDL remaining,
- *deco time and ceiling
+ * deco time and ceiling
*/
// Prime with values from the dive log section
@@ -224,10 +191,10 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
callback (DC_SAMPLE_TIME, sample, userdata);
}
- s = sdata + offset;
+ s = samples + offset;
// If corrupt_dive end before offset
- if (data->corrupt_dive) {
+ if (corrupt_dive) {
if ( s[0] == 0x10
|| s[0] == 0xFF
|| s[0] == 0xA8) {
@@ -239,8 +206,8 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
// Check for event
if (s[0] & 0x80) {
- offset += cochran_commander_handle_event(abstract, callback, userdata,
- s[0], offset, time);
+ offset += cochran_commander_handle_event(abstract, callback,
+ userdata, s[0], offset, time);
switch (s[0])
{
case 0xC5: // Deco obligation begins
@@ -262,7 +229,7 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET;
- deco_time = (array_uint16_le(s + 3) + 1) * 60;
+ sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
break;
}
@@ -270,7 +237,7 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
continue;
}
-
+
// Depth is logged as change in feet, bit 0x40 means negative depth
depth += (float) (s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
sample.depth = depth * FEET;
@@ -290,6 +257,17 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
}
+
+ // Some samples are split over two seconds
+ // Skip over event bytes to find the next sample
+ const unsigned char *n = s + COCHRAN_EMC_SAMPLE_SIZE;
+ cochran_events_t event;
+
+ while ((*n & 0x80) && n < s + size) {
+ cochran_commander_get_event_info(*n, &event);
+ n += event.data_bytes;
+ }
+
// Tissue load is in 20 samples, then 2 samples for RBT,
// and 2 for ceiling
switch (time % 24)
@@ -297,13 +275,14 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
case 20:
if (deco_obligation) {
/* Deco time for deepest stop, unused */
- deco_time = (s[2] + s[5] * 256 + 1) * 60;
+ deco_time = (s[2] + n[2] * 256 + 1) * 60;
} else {
/* Get RBT */
- sample.rbt = s[2] + s[5] * 256 + 1;
+ sample.rbt = s[2] + n[2] * 256 + 1;
if (callback) callback (DC_SAMPLE_RBT, sample, userdata);
/* Send deco NDL sample */
- sample.deco.time = sample.rbt * 60; // seconds
+ sample.deco.type = DC_DECO_NDL;
+ sample.deco.time = (s[2] + n[2] * 256 + 1) * 60; // seconds
sample.deco.depth = 0;
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
}
@@ -313,14 +292,14 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
if (deco_obligation) {
sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET;
- sample.deco.time = (s[2] + s[5] * 256 + 1) * 60; // minutes
+ sample.deco.time = (s[2] + n[2] * 256 + 1) * 60; // minutes
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
}
break;
}
time ++;
- offset += 3;
+ offset += COCHRAN_EMC_SAMPLE_SIZE;
}
return DC_STATUS_SUCCESS;
@@ -329,51 +308,50 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
struct dive_stats *stats)
{
- cochran_data_t *data = (cochran_data_t *) abstract->data;
- unsigned char *sdata = data->current_sample;
- unsigned char *log = data->current_log;
- unsigned int size = data->current_sample_size;
- unsigned char *s;
+ const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+ const unsigned char *samples = log + COCHRAN_EMC_LOG_SIZE;
+ unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+ - COCHRAN_EMC_LOG_SIZE;
+ const unsigned char *s;
+
unsigned int offset = 0;
- cochran_events_t *e = cochran_events;
- unsigned char event_ptr;
float depth_m = 0, depth, temp;
unsigned int time = 0;
+ unsigned char corrupt_dive = 0;
- // Check for corrupt dive
- if (data->corrupt_dive)
- {
- // It's corrupt, guess at the sample size
- size = cochran_emc_guess_sample_size(data);
- }
+ if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+ corrupt_dive = 1;
+
+ // Prime with values from the dive log section
+ depth = array_uint16_le (log + EMC_START_DEPTH) / 256;
- stats->max_depth = 0;
+ stats->max_depth = depth;
stats->min_temp = 999;
stats->avg_depth = 0;
stats->max_temp = 0;
while (offset < size) {
- s = sdata + offset;
+ s = samples + offset;
- if ( s[0] == 0x10
- || s[0] == 0xFF
- || s[0] == 0xA8) {
+ if (corrupt_dive) {
+ if (s[0] == 0x10
+ || s[0] == 0xFF
+ || s[0] == 0xA8) {
// End corrupted dive
break;
+ }
+ if (time > 1 && (s[0] == 0xE3 || s[0] == 0xF3))
+ break;
}
- if (time > 1 && (s[0] == 0xE3 || s[0] == 0xF3))
- break;
-
// Check for event
if (s[0] & 0x80) {
- event_ptr = 0;
- while (e[event_ptr].code && e[event_ptr].code != s[0])
- event_ptr++;
+ cochran_events_t event;
+ cochran_commander_get_event_info(s[0], &event);
// Advance some bytes
- if (e[event_ptr].code)
- offset += e[event_ptr].data_bytes;
+ if (event.code)
+ offset += event.data_bytes;
else
offset ++;
@@ -390,7 +368,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
if (time % 2 != 0) {
// Temperature logged in half degrees F above 20
- temp = s[1] / 2 + 20;
+ temp = (float) s[1] / 2 + 20;
temp = (temp - 32.0) / 1.8;
if (temp < stats->min_temp) stats->min_temp = temp;
@@ -398,7 +376,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
}
time ++;
- offset += 3;
+ offset += COCHRAN_EMC_SAMPLE_SIZE;
}
stats->dive_time = time - 1;
--
1.8.3.1
2
11
This imports Tiny AES128 from https://github.com/kokke/tiny-AES128-C for
use in the decoding of OSTC3 firmwares.
This aes-code is released into the public domain.
Signed-off-by: Anton Lundin <glance(a)acc.umu.se>
---
msvc/libdivecomputer.vcproj | 6 +
src/Makefile.am | 1 +
src/aes.c | 486 ++++++++++++++++++++++++++++++++++++++++++++
src/aes.h | 16 ++
4 files changed, 509 insertions(+)
create mode 100644 src/aes.c
create mode 100644 src/aes.h
diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index 78a8190..10a4cf7 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -247,6 +247,9 @@
>
</File>
<File
+ RelativePath="..\src\aes.c"
+ >
+ <File
RelativePath="..\src\hw_ostc3.c"
>
</File>
@@ -537,6 +540,9 @@
>
</File>
<File
+ RelativePath="..\src\aes.h"
+ >
+ <File
RelativePath="..\include\libdivecomputer\hw_ostc3.h"
>
</File>
diff --git a/src/Makefile.am b/src/Makefile.am
index 595f0c7..eb39a4b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,7 @@ libdivecomputer_la_SOURCES = \
ihex.h ihex.c \
hw_ostc.c hw_ostc_parser.c \
hw_frog.c \
+ aes.h aes.c \
hw_ostc3.c \
cressi_edy.c cressi_edy_parser.c \
cressi_leonardo.c cressi_leonardo_parser.c \
diff --git a/src/aes.c b/src/aes.c
new file mode 100644
index 0000000..000a067
--- /dev/null
+++ b/src/aes.c
@@ -0,0 +1,486 @@
+/*
+
+This is an implementation of the AES128 algorithm, specifically ECB mode.
+
+The implementation is verified against the test vectors in:
+ National Institute of Standards and Technology Special Publication 800-38A 2001 ED
+
+ECB-AES128
+----------
+
+ plain-text:
+ 6bc1bee22e409f96e93d7e117393172a
+ ae2d8a571e03ac9c9eb76fac45af8e51
+ 30c81c46a35ce411e5fbc1191a0a52ef
+ f69f2445df4f9b17ad2b417be66c3710
+
+ key:
+ 2b7e151628aed2a6abf7158809cf4f3c
+
+ resulting cipher
+ 50fe67cc996d32b6da0937e99bafec60
+ d9a4dada0892239f6b8b3d7680e15674
+ a78819583f0308e7a6bf36b1386abf23
+ c6d3416d29165c6fcb8e51a227ba994e
+
+
+NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
+ You should pad the end of the string with zeros if this is not the case.
+
+*/
+
+#ifndef _AES_C_
+#define _AES_C_
+
+
+/*****************************************************************************/
+/* Includes: */
+/*****************************************************************************/
+#include <stdint.h>
+#include "aes.h"
+
+
+/*****************************************************************************/
+/* Defines: */
+/*****************************************************************************/
+// The number of columns comprising a state in AES. This is a constant in AES. Value=4
+#define Nb 4
+// The number of 32 bit words in a key.
+#define Nk 4
+// Key length in bytes [128 bit]
+#define keyln 16
+// The number of rounds in AES Cipher.
+#define Nr 10
+
+
+/*****************************************************************************/
+/* Private variables: */
+/*****************************************************************************/
+// in - pointer to the CipherText to be decrypted.
+// out - pointer to buffer to hold output of the decryption.
+// state - array holding the intermediate results during decryption.
+static uint8_t* in, *out, state[4][4];
+
+// The array that stores the round keys.
+static uint8_t RoundKey[176];
+
+// The Key input to the AES Program
+static uint8_t* Key;
+
+// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
+// The numbers below can be computed dynamically trading ROM for RAM -
+// This can be useful in (embedded) bootloader applications, where ROM is often limited.
+static const uint8_t sbox[256] = {
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
+
+static const uint8_t rsbox[256] =
+{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
+, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
+, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
+, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
+, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
+, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
+, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
+, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
+, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
+, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
+, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
+, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
+, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
+, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
+, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
+, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
+
+
+// The round constant word array, Rcon[i], contains the values given by
+// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
+// Note that i starts at 1, not 0).
+static const uint8_t Rcon[255] = {
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
+ 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
+ 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
+ 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
+ 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
+ 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
+ 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb };
+
+
+/*****************************************************************************/
+/* Private functions: */
+/*****************************************************************************/
+static uint8_t getSBoxValue(uint8_t num)
+{
+ return sbox[num];
+}
+
+static uint8_t getSBoxInvert(uint8_t num)
+{
+ return rsbox[num];
+}
+
+
+// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
+static void KeyExpansion()
+{
+ uint32_t i, j, k;
+ uint8_t tempa[4]; // used for the column/row operations
+
+ // The first round key is the key itself.
+ for(i = 0; i < Nk; ++i)
+ {
+ RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
+ RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
+ RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
+ RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
+ }
+
+ // All other round keys are found from the previous round keys.
+ for(; (i < (Nb * (Nr + 1))); ++i)
+ {
+ for(j = 0; j < 4; ++j)
+ {
+ tempa[j]=RoundKey[(i-1) * 4 + j];
+ }
+ if (i % Nk == 0)
+ {
+ // This function rotates the 4 bytes in a word to the left once.
+ // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
+
+ // Function RotWord()
+ {
+ k = tempa[0];
+ tempa[0] = tempa[1];
+ tempa[1] = tempa[2];
+ tempa[2] = tempa[3];
+ tempa[3] = k;
+ }
+
+ // SubWord() is a function that takes a four-byte input word and
+ // applies the S-box to each of the four bytes to produce an output word.
+
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+
+ tempa[0] = tempa[0] ^ Rcon[i/Nk];
+ }
+ else if (Nk > 6 && i % Nk == 4)
+ {
+ // Function Subword()
+ {
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+ }
+ RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0];
+ RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1];
+ RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2];
+ RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3];
+ }
+}
+
+// This function adds the round key to state.
+// The round key is added to the state by an XOR function.
+static void AddRoundKey(uint8_t round)
+{
+ uint8_t i,j;
+ for(i=0;i<4;i++)
+ {
+ for(j = 0; j < 4; ++j)
+ {
+ state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
+ }
+ }
+}
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+static void SubBytes()
+{
+ uint8_t i, j;
+ for(i = 0; i < 4; ++i)
+ {
+ for(j = 0; j < 4; ++j)
+ {
+ state[i][j] = getSBoxValue(state[i][j]);
+ }
+ }
+}
+
+// The ShiftRows() function shifts the rows in the state to the left.
+// Each row is shifted with different offset.
+// Offset = Row number. So the first row is not shifted.
+static void ShiftRows()
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to left
+ temp = state[1][0];
+ state[1][0] = state[1][1];
+ state[1][1] = state[1][2];
+ state[1][2] = state[1][3];
+ state[1][3] = temp;
+
+ // Rotate second row 2 columns to left
+ temp = state[2][0];
+ state[2][0] = state[2][2];
+ state[2][2] = temp;
+
+ temp = state[2][1];
+ state[2][1] = state[2][3];
+ state[2][3] = temp;
+
+ // Rotate third row 3 columns to left
+ temp = state[3][0];
+ state[3][0] = state[3][3];
+ state[3][3] = state[3][2];
+ state[3][2] = state[3][1];
+ state[3][1] = temp;
+}
+
+static uint8_t xtime(uint8_t x)
+{
+ return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
+}
+
+// MixColumns function mixes the columns of the state matrix
+static void MixColumns()
+{
+ uint8_t i;
+ uint8_t Tmp,Tm,t;
+ for(i = 0; i < 4; ++i)
+ {
+ t = state[0][i];
+ Tmp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i] ;
+ Tm = state[0][i] ^ state[1][i] ; Tm = xtime(Tm); state[0][i] ^= Tm ^ Tmp ;
+ Tm = state[1][i] ^ state[2][i] ; Tm = xtime(Tm); state[1][i] ^= Tm ^ Tmp ;
+ Tm = state[2][i] ^ state[3][i] ; Tm = xtime(Tm); state[2][i] ^= Tm ^ Tmp ;
+ Tm = state[3][i] ^ t ; Tm = xtime(Tm); state[3][i] ^= Tm ^ Tmp ;
+ }
+}
+
+// Multiplty is a macro used to multiply numbers in the field GF(2^8)
+#define Multiply(x,y) (((y & 1) * x) ^ ((y>>1 & 1) * xtime(x)) ^ ((y>>2 & 1) * xtime(xtime(x))) ^ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))))
+
+
+// MixColumns function mixes the columns of the state matrix.
+// The method used to multiply may be difficult to understand for the inexperienced.
+// Please use the references to gain more information.
+static void InvMixColumns()
+{
+ int i;
+ uint8_t a,b,c,d;
+ for(i=0;i<4;i++)
+ {
+
+ a = state[0][i];
+ b = state[1][i];
+ c = state[2][i];
+ d = state[3][i];
+
+
+ state[0][i] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
+ state[1][i] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
+ state[2][i] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
+ state[3][i] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
+ }
+}
+
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+static void InvSubBytes()
+{
+ uint8_t i,j;
+ for(i=0;i<4;i++)
+ {
+ for(j=0;j<4;j++)
+ {
+ state[i][j] = getSBoxInvert(state[i][j]);
+ }
+ }
+}
+
+
+static void InvShiftRows()
+{
+ uint8_t temp;
+
+ // Rotate first row 1 columns to right
+ temp=state[1][3];
+ state[1][3]=state[1][2];
+ state[1][2]=state[1][1];
+ state[1][1]=state[1][0];
+ state[1][0]=temp;
+
+ // Rotate second row 2 columns to right
+ temp=state[2][0];
+ state[2][0]=state[2][2];
+ state[2][2]=temp;
+
+ temp=state[2][1];
+ state[2][1]=state[2][3];
+ state[2][3]=temp;
+
+ // Rotate third row 3 columns to right
+ temp=state[3][0];
+ state[3][0]=state[3][1];
+ state[3][1]=state[3][2];
+ state[3][2]=state[3][3];
+ state[3][3]=temp;
+}
+
+
+// Cipher is the main function that encrypts the PlainText.
+static void Cipher()
+{
+ uint8_t i, j, round = 0;
+
+ //Copy the input PlainText to state array.
+ for(i = 0; i < 4; ++i)
+ {
+ for(j = 0; j < 4 ; ++j)
+ {
+ state[j][i] = in[(i * 4) + j];
+ }
+ }
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(0);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for(round = 1; round < Nr; ++round)
+ {
+ SubBytes();
+ ShiftRows();
+ MixColumns();
+ AddRoundKey(round);
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ SubBytes();
+ ShiftRows();
+ AddRoundKey(Nr);
+
+ // The encryption process is over.
+ // Copy the state array to output array.
+ for(i = 0; i < 4; ++i)
+ {
+ for(j = 0; j < 4; ++j)
+ {
+ out[(i * 4) + j] = state[j][i];
+ }
+ }
+}
+
+static void InvCipher()
+{
+ uint8_t i,j,round=0;
+
+ //Copy the input CipherText to state array.
+ for(i=0;i<4;i++)
+ {
+ for(j=0;j<4;j++)
+ {
+ state[j][i] = in[i*4 + j];
+ }
+ }
+
+ // Add the First round key to the state before starting the rounds.
+ AddRoundKey(Nr);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for(round=Nr-1;round>0;round--)
+ {
+ InvShiftRows();
+ InvSubBytes();
+ AddRoundKey(round);
+ InvMixColumns();
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ InvShiftRows();
+ InvSubBytes();
+ AddRoundKey(0);
+
+ // The decryption process is over.
+ // Copy the state array to output array.
+ for(i=0;i<4;i++)
+ {
+ for(j=0;j<4;j++)
+ {
+ out[i*4+j]=state[j][i];
+ }
+ }
+}
+
+
+/*****************************************************************************/
+/* Public functions: */
+/*****************************************************************************/
+
+void AES128_ECB_encrypt(uint8_t* input, uint8_t* key, uint8_t *output)
+{
+ // Copy the Key and CipherText
+ Key = key;
+ in = input;
+ out = output;
+
+ // The KeyExpansion routine must be called before encryption.
+ KeyExpansion();
+
+ // The next function call encrypts the PlainText with the Key using AES algorithm.
+ Cipher();
+}
+
+void AES128_ECB_decrypt(uint8_t* input, uint8_t* key, uint8_t *output)
+{
+ Key = key;
+ in = input;
+ out = output;
+
+ KeyExpansion();
+
+ InvCipher();
+}
+
+#endif //_AES_C_
+
+
diff --git a/src/aes.h b/src/aes.h
new file mode 100644
index 0000000..5fb2176
--- /dev/null
+++ b/src/aes.h
@@ -0,0 +1,16 @@
+#ifndef _AES_H_
+#define _AES_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void AES128_ECB_encrypt(uint8_t* input, uint8_t* key, uint8_t *output);
+void AES128_ECB_decrypt(uint8_t* input, uint8_t* key, uint8_t *output);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif //_AES_H_
--
1.9.1
2
41
loicmichel wrote:
>
> Dear Anton Lundin,
>
> I'm used to program in C# and have zaro experience with C.
>
> Are you aware of any c# code to link to the libdivecomputer ?
>
> I can't figure out from the example how to download and use data from
> a VEO2 computer.
>
> Thanks for help,
>
There's a libdivecomputer DLL here:
http://www.libdivecomputer.org/builds/divinglog/
Maybe that's useful?
Cheers,
Henrik
4
9
Linus,
According to Dirk the plan is to have a subsurface beta ready before the
eonsteel is available on the market. And thus is would be convenient to have a
first version included in libdivecomputer. I'll do my best to meet that deadline.
There has been quite some discussion on the new string based api for
libdivecomputer. I'll need some more time to go through this whole discussion
and give its some more thoughts. Therefore, I propose we target for a first
version of the eonsteel backend without any of those string based api changes.
So that's basically your 0001 patch. Those are not critical features, and trying
to rush things is always a bad idea.
So what I consider mandatory to fix before I'll commit your patches are:
Naming conventions for entry point functions and the private device and parser
structures. I know you don't like these long names, but that's the convention in
the libdivecomputer codebase, and I'll insist on following existing practice.
See the 0001 patch.
Working build on Windows. I have attached a patch that does the necessary casts
(and a few other things) to get the mingw and msvc builds to work. In most
places, I simply added casts wherever the compiler complained, without checking
whether that was the right thing to do. Many of those casts can probably avoided
by using the correct type (unsigned instead of signed). Even the gcc compilers
spits out tons of warnings, so you don't even need msvc to locate the type
mismatches.
BTW, if the goal is to demo a build to Suunto, then I think we should not only
compile test on Windows, but actually try a Windows build too. They are probably
using Windows.
Proper integration with the libdivecomputer logging functions.
The other ones I can live with and/or fix later.
(more inline comments below)
On 28-10-14 17:51, Linus Torvalds wrote:
> On Tue, Oct 28, 2014 at 8:43 AM, Jef Driesen <jef(a)libdivecomputer.org> wrote:
>>
>> There are also some header files like unistd.h which don't exist on windows.
>
> Hmm. I wonder why I included them.
>
> Part of it is probably that the whole back-end started out as this
> "suunto hacking tool" that did a lot of "print hex information of the
> packets". That's also why there was no libdivecomputer infrastructure,
> this thing was entirely stand-alone for just trying to gather traces
> and recreate them, and figure out what the things did.
No idea why you needed sys/types.h, fcntl.h, etc. Most of the other ones are
also no longer necessary if the custom logging is removed.
> I got no actual information from Suunto, but the fact that many things
> are just text helped. Seeing filenames etc in the dumps etc.. And the
> actual dive dumps have this interesting "each data has its type
> associated with it, and each type has a human-readable type
> descriptor". Which meant that I never needed to guess what the actual
> data means - the problem was figuring out the odd marshaling of the
> data, and the odd packet protocol.
I guess everyone does printf logging at some point. Me too :-)
>> Libdivecomputer doesn't log anything on its own. The actual logging is done
>> by the application. That's on purpose. That's for example how subsurface is
>> able to generate a libdivecomputer log directly from the GUI. I believe
>> that's a very useful feature, which certainly doesn't sucks :-)
>
> So the logging I have is for protocol errors, or surprising things.
> Not useful to users. It's more of a protocol verification, I would
> *not* want it to show up in applications.
The logged info doesn't need to be useful for the user. The user only needs some
super easy way to get the log and then send it back to someone that does
understand what's inside.
There are also multiple loglevels, which the application can control. ERROR and
WARNING are self explanatory. INFO is used for logging the communication
protocol (e.g. raw data packets), and DEBUG is for whatever else you would like
to log.
>> Why do you need void pointers here? You're parsing a byte array, which is by
>> definition an unsigned char array. So where do you get void pointers from?
>
> "void *" is the "random byte area" type. It's one of the things C++
> completely screwed up. It's very useful when you use the helper
> function on random data (that may be embedded in structures etc, or
> give pointers to "uint32_t" etc when you convert from little-endian to
> big-endian etc.
>
> But if there are no cases of that left over, maybe you can convert
> them all to "unsigned char *" ..
I very rarely need void pointers. Probably only for very generic functions like
memcpy and friends. For byte arrays unsigned char's are perfect, and they also
avoid the whole void pointer arithmetic problem.
>> I know it doesn't support a standard memory dump. But a dump of one dive is
>> fine too. I can use the parser standalone.
>
> I hacked up subsurface to just dump the per-dive data to a
> "dive-%08x.log" file. That's *fairly* close to what the computer does
> internally, although this dumped data contains the date in the first
> 32-bit word, which is what the parser expects. On the dive computer,
> the date is encoded in the filename - see the
>
> dc_buffer_append(file, buf, 4);
>
> in eon_steel_device_foreach() where I append it to the data buffer
> instead, since the parser doesn't have access to the filename.
That looks very reasonable. Is it always a 32bit number? If it could be a 64bit
timestamp, then it might be safer to reserve 8 bytes here. One Y2038 problem
less :-)
This timestamp is also a good candidate for use as the libdivecomputer fingerprint!
> (The dive date is *also* encoded in the dive data, but in a very
> inconvenient format with a dynamic type, so I wanted the data from the
> filename for simplicity).
>
> So here are the dumps of the dives I have on that dive computer so
> far, in that "parser format".
>
> That first dive is just me lowering the dive computer into the
> neighbors pool. The other 21 dives are the ones we did in Bonaire.
Your data files where too large for the list. I got them, but if you want I can
still manually approve your mail.
> Dirk has one of the Intel engineers create a contraption to lower the
> thing into the pool multiple times, so that I can see what happens to
> the directory listing when it no longer fits in one "readdir" reply
> (the packets may be 64 bytes each, but they are chained up to be
> replies that can apparently be up to 1kB in size - at least I haven't
> seen anything bigger than that yet. And I don't know what happens when
> the directory listing is bigger than that, because the 22 dives I have
> so far create only about 460 bytes of "readdir reply").
A small pressure chamber might be even more convenient: no need to have a pool
around.
Jef
3
17
On 23-11-14 16:25, Dirk Hohndel wrote:
> On Sun, Nov 23, 2014 at 11:39:55AM +0100, Henrik Brautaset Aronsen
> wrote:
>>>
>>> I did a new fresh import from my Petrel on the latest master and
>>> saved it.
>>> This time the saved petrel2.xml [1] does not contain the empty
>>> <cylinder
>>> /> statements. But id does contain cylinders with something in them,
>>> even
>>> on gauge dives:
>>>
>>> <cylinder o2='52.0%' />
>>> <cylinder o2='18.0%' he='45.0%' />
>
> I haven't used my Petrel in gauge mode (that's one heck of an expensive
> gauge...). It would make sense that it doesn't support any gases in
> that
> mode, but libdivecomputer doesn't know that the Petrel was in gauge
> mode
> so it tells us about those gases as they are present in the dive
> header.
> I am making a lot of assumptions here - but since I know a little bit
> about the Petrel data format I think these are reasonable assumptions.
>
> Jef, can you confirm this analysis?
Yes, your analysis is correct. I just checked the documentation, and the
gauge mode isn't mentioned anywhere. So either it's just missing in the
documentation, or it's not recorded.
The Petrel (and Predator too) is also one of the devices where the dive
mode is stored in the sample data, and not the dive header. I assume
that's done because you can switch between OC/CC during the dive. But
that makes it also rather difficult to tell whether a dive is OC or CC
(e.g. what should we do if there are mixed samples?). And thus what
libdivecomputer does is just return all gas mixes.
>>> I tried to do a data dump, but both subsurface and the
>>> libdivecomputer
>>> dump app doesn't cooperate:
>
> IIRC, the Petrel doesn't support dumps.
>
>> Result: Unsupported operation
The Petrel protocol doesn't support memory dumps. The Petrel also
supports the older Predator protocol. That one supports memory dumps,
but is only capable of downloading the last 128K of memory.
For protocols without support for memory dumps, I usually dump the
individual dives, using this patch for the universal app:
http://www.libdivecomputer.org/tmp/universal_dump_dives.patch
Jef
1
0
Re: Petrel data problems [was Re: Crash when opening log file]
by Henrik Brautaset Aronsen 23 Nov '14
by Henrik Brautaset Aronsen 23 Nov '14
23 Nov '14
Henrik Brautaset Aronsen wrote:
> Dirk Hohndel wrote:
>>
>> On November 22, 2014 9:52:42 PM Miika Turkia <miika.turkia(a)gmail.com>
>> wrote:
>>
>> > > I'll need to poke at that and figure out what's happening. I'm quite
>> > > pressed for time right now, hopefully I'll get to it after the
>> weekend.
>> > >
>> >
>> > The XML contains po2 values. Isn't that currently enough to make
>> Subsruface
>> > treat the dive as a CCR dive?
>>
>> I believe you are correct
>>
>
> I did a new fresh import from my Petrel on the latest master and saved
> it. This time the saved petrel2.xml [1] does not contain the empty
> <cylinder /> statements. But id does contain cylinders with something
> in them, even on gauge dives:
>
> <cylinder o2='52.0%' />
> <cylinder o2='18.0%' he='45.0%' />
>
> I tried to do a data dump, but both subsurface and the libdivecomputer
> dump app doesn't cooperate:
>
> $ examples/universal -l petrel2.log -m petrel2.bin -v -n "Shearwater
> Petrel" /dev/tty.Petrel-SerialPort
> DATETIME 2014-11-23T10:29:31Z (1416738571)
> VERSION 0.5.0-devel (e307227b808186beccc00461103477156e97f5e4)
> Opening the device (Shearwater Petrel, /dev/tty.Petrel-SerialPort).
> INFO: Open: name=/dev/tty.Petrel-SerialPort
> INFO: Configure: baudrate=115200, databits=8, parity=0, stopbits=1,
> flowcontrol=0
> INFO: Timeout: value=3000
> INFO: Sleep: value=300
> INFO: Flush: queue=3, input=0, output=0
> Registering the event handler.
> Registering the cancellation handler.
> Downloading the memory dump.
> universal.c:793: Error downloading the memory dump.
> INFO: Write: size=9, data=FF0105002E902000C0
> Result: Unsupported operation
>
> (at this point, the Petrel immediately drops out of the upload dive mode)
The same thing happens with the universal app from
http://libdivecomputer.org/builds/macosx/ as well. Any ideas, Jef?
$ ~/Downloads/universal -l petrel2.log -m petrel2.bin -v -n "Shearwater
Petrel" /dev/tty.Petrel-SerialPort
DATETIME 2014-11-23T10:37:18Z (1416739038)
VERSION 0.5.0-devel (5e88cf749475377fe21d2dd2b4d60fce6542127c)
Opening the device (Shearwater Petrel, /dev/tty.Petrel-SerialPort).
INFO: Open: name=/dev/tty.Petrel-SerialPort
INFO: Configure: baudrate=115200, databits=8, parity=0, stopbits=1,
flowcontrol=0
INFO: Timeout: value=3000
INFO: Sleep: value=300
INFO: Flush: queue=3, input=0, output=0
Registering the event handler.
Registering the cancellation handler.
Downloading the memory dump.
../../source/examples/universal.c:802: Error downloading the memory dump.
INFO: Write: size=9, data=FF0105002E902000C0
Result: Unsupported operation
-H
1
0
Hi!
This is is a RFC series of patches to add support for firmware upgrades
on the OSTC3. The code have bin tested both against a "pcb" by HW and
against my OSTC3 so it works and does the right things. JeanDo's
ostc-companion[1] have bin the reference implementation I've looked at
when I wrote this code.
There are still a couple of pain-points that I would like some feedback
on:
How to start the device in service mode:
To get access to the necessary commands for service mode, we can't INIT
the device with INIT(0xBB), we need to INIT it with a special service
mode sequence(0xAA, 0xAB, 0xCD, 0xEF). Now the INIT is sent in
hw_ostc3_device_open, so how do you suggest that we refactor the code to
allow another sequence after open?
The current quite crude hack is to just EXIT(0xFF) the device and
re-init it after a 6s sleep. This won't work against the OSTC Sport.
The timing between command and data in write_block:
The current hw_ostc3_device_write_block is a bit of copy-paste from
hw_ostc3_transfer, to be able to send the data buffer to the device,
without a additional copy.
Library triggered closed state:
The device reboots when it gets the FLASH_FIRM-command so how can we
"not fail" when the application then tries to talk to the device
afterwards, or even call hw_ostc3_device_close?
There are also a couple of other FIXME's in the code, which I plan on
cleaning up, but I thought that I should send out a first RFC patch
series to get some additional feedback going.
Any other ideas about how the code looks?
//Anton
1. https://bitbucket.org/JeanDo/ostc-companion/
--
Anton Lundin +46702-161604
3
15
---
src/cochran_commander.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index 8fa6228..95d4da4 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -89,8 +89,6 @@ typedef struct cochran_data_t {
unsigned int sample_data_offset;
unsigned int sample_size;
- unsigned int last_interdive_offset;
- unsigned int last_entry_offset;
cochran_config_t conf;
} cochran_data_t;
--
1.8.3.1
1
3
Specifically tested with EMC-20H and Commander Air_Nitrox this
commit should support the families for the most part however
there are may be differences in the DC signature, memory size,
and other factors that will prevent opening the device and
obtaining a clean import. Try it with other EMC and Commander
devices and check library ERRORs for the signature information
needed to add support.
Also missing is tank pressure (for Gemini) and support for logbooks
that have rolled old dives off. There is support for dive samples
that have rolled off.
John Van Ostrand (1):
Added support for Cochran EMC and Commander Air import
examples/Makefile.am | 6 +-
examples/cochran_download.c | 299 +++++++++++++
examples/universal.c | 8 +-
include/libdivecomputer/Makefile.am | 3 +-
include/libdivecomputer/cochran.h | 61 +++
include/libdivecomputer/common.h | 3 +
include/libdivecomputer/parser.h | 20 +-
src/Makefile.am | 7 +-
src/cochran_cmdr.c | 66 +++
src/cochran_cmdr.h | 83 ++++
src/cochran_cmdr_parser.c | 202 +++++++++
src/cochran_common.c | 861 ++++++++++++++++++++++++++++++++++++
src/cochran_common.h | 109 +++++
src/cochran_common_parser.c | 157 +++++++
src/cochran_common_parser.h | 80 ++++
src/cochran_emc.c | 67 +++
src/cochran_emc.h | 180 ++++++++
src/cochran_emc_parser.c | 399 +++++++++++++++++
src/descriptor.c | 3 +
src/device.c | 7 +
src/libdivecomputer.symbols | 2 +
src/parser.c | 7 +
22 files changed, 2617 insertions(+), 13 deletions(-)
create mode 100644 examples/cochran_download.c
create mode 100644 include/libdivecomputer/cochran.h
create mode 100644 src/cochran_cmdr.c
create mode 100644 src/cochran_cmdr.h
create mode 100644 src/cochran_cmdr_parser.c
create mode 100644 src/cochran_common.c
create mode 100644 src/cochran_common.h
create mode 100644 src/cochran_common_parser.c
create mode 100644 src/cochran_common_parser.h
create mode 100644 src/cochran_emc.c
create mode 100644 src/cochran_emc.h
create mode 100644 src/cochran_emc_parser.c
--
1.8.3.1
2
12
Also fixed up off-by-one pointers into logbook data.
Signed-off-by: John Van Ostrand <john(a)vanostrand.com>
---
src/cochran_cmdr_parser.c | 16 ++++++++++------
src/cochran_commander.h | 10 +++++++---
src/cochran_emc_parser.c | 28 ++++++++++++++++++++--------
3 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/src/cochran_cmdr_parser.c b/src/cochran_cmdr_parser.c
index 7cfd650..de25912 100644
--- a/src/cochran_cmdr_parser.c
+++ b/src/cochran_cmdr_parser.c
@@ -50,16 +50,20 @@ cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
if (value) {
switch (type) {
- case DC_FIELD_TEMPERATURE:
- *((unsigned int*) value) = log[CMD_START_TEMP];
+ case DC_FIELD_TEMPERATURE_SURFACE:
+ *((unsigned int*) value) = ((float) log[CMD_START_TEMP] - 32) / 1.8;
+ case DC_FIELD_TEMPERATURE_MINIMUM:
+ *((unsigned int*) value) = ((float) log[CMD_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+ case DC_FIELD_TEMPERATURE_MAXIMUM:
+ *((unsigned int*) value) = ((float) log[CMD_MAX_TEMP] / 2 + 20 - 32) / 1.8;
case DC_FIELD_DIVETIME:
*((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60;
break;
case DC_FIELD_MAXDEPTH:
- *((double *) value) = array_uint16_le (log + CMD_MAX_DEPTH) / 4 * FEET;
+ *((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH) / 4 * FEET;
break;
case DC_FIELD_AVGDEPTH:
- *((double *) value) = array_uint16_le (log + CMD_AVG_DEPTH) / 4 * FEET;
+ *((double *) value) = (float) array_uint16_le (log + CMD_AVG_DEPTH) / 4 * FEET;
break;
case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = 2;
@@ -72,9 +76,9 @@ cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
break;
case DC_FIELD_SALINITY:
// 0 = low conductivity, 1 = high, maybe there's a 2?
- water->type = ( log[CMD_WATER_CONDUCTIVITY] == 0 ? DC_WATER_FRESH
+ water->type = ( (log[CMD_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
: DC_WATER_SALT );
- water->density = 1000 + 12.5 * log[CMD_WATER_CONDUCTIVITY];
+ water->density = 1000 + 12.5 * (log[CMD_WATER_CONDUCTIVITY] & 0x3);
break;
case DC_FIELD_ATMOSPHERIC:
*(double *) value = ATM / BAR * pow(1 - 0.0000225577
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index d16de42..1b040de 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -113,11 +113,13 @@ typedef struct cochran_device_t {
#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_END_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=%
+#define CMD_MIN_TEMP 232 // 1 byte, /2+20=F
+#define CMD_MAX_TEMP 233 // 1 byte, /2+20=F
// EMC log fields
#define EMC_SEC 0
@@ -127,17 +129,19 @@ typedef struct cochran_device_t {
#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_WATER_CONDUCTIVITY 24 // 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_END_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
+#define EMC_MIN_TEMP 403 // 1 byte, /2+20=F
+#define EMC_MAX_TEMP 407 // 1 byte, /2+20=F
dc_status_t cochran_packet (cochran_device_t *device,
diff --git a/src/cochran_emc_parser.c b/src/cochran_emc_parser.c
index 37089a7..10d87a0 100644
--- a/src/cochran_emc_parser.c
+++ b/src/cochran_emc_parser.c
@@ -41,6 +41,7 @@ struct dive_stats {
float max_depth;
float avg_depth;
float min_temp;
+ float max_temp;
};
@@ -59,29 +60,38 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
dc_salinity_t *water = (dc_salinity_t *) value;
unsigned int dive_time;
- float max_depth, avg_depth, min_temp;
struct dive_stats stats;
if (value) {
switch (type) {
- case DC_FIELD_TEMPERATURE:
+ case DC_FIELD_TEMPERATURE_SURFACE:
+ *((unsigned int*) value) = ((float) log[EMC_START_TEMP] - 32) / 1.8;
+ break;
+ case DC_FIELD_TEMPERATURE_MINIMUM:
+ if (data->corrupt_dive) {
+ cochran_emc_parse_dive_stats(abstract, &stats);
+ *((unsigned int*) value) = stats.min_temp;
+ } else
+ *((unsigned int*) value) = ((float) log[EMC_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+ break;
+ case DC_FIELD_TEMPERATURE_MAXIMUM:
if (data->corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
- *((unsigned int*) value) = min_temp;
+ *((unsigned int*) value) = stats.max_temp;
} else
- *((unsigned int*) value) = (log[EMC_START_TEMP] - 32) / 1.8;
+ *((unsigned int*) value) = ((float) log[EMC_MAX_TEMP] / 2 + 20 - 32) / 1.8;
break;
case DC_FIELD_DIVETIME:
if (data->corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
- *((unsigned int*) value) = dive_time;
+ *((unsigned int*) value) = stats.dive_time;
} else
*((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60;
break;
case DC_FIELD_MAXDEPTH:
if (data->corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
- *((unsigned int*) value) = max_depth;
+ *((unsigned int*) value) = stats.max_depth;
} else
*((double *) value) = array_uint16_le (log + EMC_MAX_DEPTH) / 4
* FEET;
@@ -89,7 +99,7 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
case DC_FIELD_AVGDEPTH:
if (data->corrupt_dive) {
cochran_emc_parse_dive_stats(abstract, &stats);
- *((unsigned int*) value) = avg_depth;
+ *((unsigned int*) value) = stats.avg_depth;
} else
*((double *) value) = array_uint16_le (log + EMC_AVG_DEPTH) / 4
* FEET;
@@ -106,7 +116,7 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
break;
case DC_FIELD_SALINITY:
// 0 = low conductivity, 2 = high, maybe there's a 1?
- water->type = ( log[EMC_WATER_CONDUCTIVITY] == 0 ? DC_WATER_FRESH
+ water->type = ( (log[EMC_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
: DC_WATER_SALT );
water->density = 1000 + 12.5 * (log[EMC_WATER_CONDUCTIVITY] & 0x3);
break;
@@ -341,6 +351,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
stats->max_depth = 0;
stats->min_temp = 999;
stats->avg_depth = 0;
+ stats->max_temp = 0;
while (offset < size) {
s = sdata + offset;
@@ -384,6 +395,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
temp = (temp - 32.0) / 1.8;
if (temp < stats->min_temp) stats->min_temp = temp;
+ if (temp > stats->max_temp) stats->max_temp = temp;
}
time ++;
--
1.8.3.1
1
0