Commander II pointers to profile ringbuffer data was wrong. After seeing the Commander I encoding I realized the Commander II encoding of RB pointers was in a flipped word big endian format. It only appeared to be in normal big endian format because of an adjacent pointer that usually shared the same first two bytes. --- src/cochran_commander.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 27ed67d..3f084d3 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -147,11 +147,11 @@ static const cochran_device_layout_t cochran_cmdr_1_device_layout = { static const cochran_device_layout_t cochran_cmdr_device_layout = { COCHRAN_MODEL_COMMANDER_AIR_NITROX, // model 24, // address_bits - ENDIAN_BE, // endian + ENDIAN_WORD_BE, // endian 115200, // baudrate 0x046, // cf_dive_count - 0x06E, // cf_last_log - 0x200, // cf_last_interdive + 0x070, // cf_last_log + 0x06C, // cf_last_interdive 0x0AA, // cf_serial_number 0x00000000, // rb_logbook_begin 0x00020000, // rb_logbook_end
This function is much more useful if it works like a ringbuffer_distance() function. It assumed the wrong values when calculating profile size and it didn't have easy access to values it needed to properly calculate profile sizes.
It makes sense to keep since it validates pointers. --- src/cochran_commander.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-)
diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 3f084d3..247da81 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -44,11 +44,6 @@ typedef enum cochran_endian_t { ENDIAN_WORD_BE, } cochran_endian_t;
-typedef enum cochran_profile_size_t { - PROFILE_SIZE_FULL, - PROFILE_SIZE_READ, -} cochran_profile_size_t; - typedef struct cochran_commander_model_t { unsigned char id[3 + 1]; unsigned int model; @@ -513,21 +508,8 @@ cochran_commander_guess_sample_end_address(cochran_commander_device_t *device, c
static unsigned int -cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_t *data, int dive_num, cochran_profile_size_t type) +cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_t *data, int dive_num, unsigned int sample_start_address, unsigned int sample_end_address) { - - const unsigned char *log_entry = data->logbook + dive_num * device->layout->rb_logbook_entry_size; - unsigned int sample_start_address = 0xFFFFFFFF; - unsigned int sample_end_address = array_uint32_le (log_entry + device->layout->pt_profile_end); - - if (type == PROFILE_SIZE_FULL) { - // actual size, includes pre-dive events - sample_start_address = array_uint32_le (log_entry + device->layout->pt_profile_pre); - } else if (type == PROFILE_SIZE_READ) { - // read size, only include dive profile - sample_start_address = array_uint32_le (log_entry + device->layout->pt_profile_begin); - } - // Validate addresses if (sample_start_address < device->layout->rb_profile_begin || sample_start_address > device->layout->rb_profile_end || @@ -604,8 +586,12 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d break; }
- unsigned int sample_size = cochran_commander_profile_size(device, data, i, PROFILE_SIZE_FULL); - unsigned int read_size = cochran_commander_profile_size(device, data, i, PROFILE_SIZE_READ); + unsigned int profile_pre = array_uint32_le(log_entry + device->layout->pt_profile_pre); + unsigned int profile_begin = array_uint32_le(log_entry + device->layout->pt_profile_begin); + unsigned int profile_end = array_uint32_le(log_entry + device->layout->pt_profile_end); + + unsigned int sample_size = cochran_commander_profile_size(device, data, i, profile_pre, profile_end); + unsigned int read_size = cochran_commander_profile_size(device, data, i, profile_begin, profile_end);
// Determine if sample exists if (profile_capacity_remaining > 0) { @@ -985,7 +971,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call invalid_profile_flag = 1;
if (!invalid_profile_flag) - sample_size = cochran_commander_profile_size(device, &data, i, PROFILE_SIZE_READ); + sample_size = cochran_commander_profile_size(device, &data, i, sample_start_address, sample_end_address);
// Build dive blob unsigned int dive_size = layout->rb_logbook_entry_size + sample_size;
The method used to calculate the data used by dives (to determine when we run out of ringbuffer) incorrectly didn't include surface sample data. Ten to twenty minute of sample data is recorded at the surface in case the diver re-descends, continuing the dive. The code then thought that older dive profiles were not yet overwritten. The improper data was returned to the user. --- src/cochran_commander.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 247da81..ac4c596 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -145,8 +145,8 @@ static const cochran_device_layout_t cochran_cmdr_device_layout = { ENDIAN_WORD_BE, // endian 115200, // baudrate 0x046, // cf_dive_count - 0x070, // cf_last_log - 0x06C, // cf_last_interdive + 0x06C, // cf_last_log + 0x070, // cf_last_interdive 0x0AA, // cf_serial_number 0x00000000, // rb_logbook_begin 0x00020000, // rb_logbook_end @@ -555,12 +555,9 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d // Remove the pre-dive events that occur after the last dive int rb_head_ptr; if (device->layout->endian == ENDIAN_WORD_BE) - rb_head_ptr = (array_uint32_word_be(data->config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000; + rb_head_ptr = (array_uint32_word_be(data->config + device->layout->cf_last_log) & 0xfffff000) + 0x2000; else - rb_head_ptr = (array_uint32_le(data->config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000; - int last_dive_end_address = array_uint32_le(data->logbook + dive_count * device->layout->rb_logbook_entry_size + device->layout->pt_profile_end); - if (rb_head_ptr > last_dive_end_address) - profile_capacity_remaining -= rb_head_ptr - last_dive_end_address; + rb_head_ptr = (array_uint32_le(data->config + device->layout->cf_last_log) & 0xfffff000) + 0x2000;
unsigned int head_dive = 0, tail_dive = 0;
@@ -573,6 +570,18 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d head_dive = tail_dive; }
+ unsigned int last_profile_idx = (device->layout->rb_logbook_entry_count + head_dive - 1) % device->layout->rb_logbook_entry_count; + unsigned int last_profile_end = array_uint32_le(data->logbook + last_profile_idx * device->layout->rb_logbook_entry_size + device->layout->pt_profile_end); + unsigned int last_profile_pre = 0xFFFFFFFF; + + if (device->layout->endian == ENDIAN_WORD_BE) + last_profile_pre = array_uint32_word_be(data->config + device->layout->cf_last_log); + else + last_profile_pre = array_uint32_le(data->config + device->layout->cf_last_log); + + if (rb_head_ptr > last_profile_end) + profile_capacity_remaining -= rb_head_ptr - last_profile_end; + // Loop through dives to find FP, Accumulate profile data size, // and find the last dive with invalid profile for (int x = dive_count; x >= 0; x--) { @@ -590,7 +599,8 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d unsigned int profile_begin = array_uint32_le(log_entry + device->layout->pt_profile_begin); unsigned int profile_end = array_uint32_le(log_entry + device->layout->pt_profile_end);
- unsigned int sample_size = cochran_commander_profile_size(device, data, i, profile_pre, profile_end); + unsigned int sample_size = cochran_commander_profile_size(device, data, i, profile_pre, last_profile_pre); + last_profile_pre = profile_pre; unsigned int read_size = cochran_commander_profile_size(device, data, i, profile_begin, profile_end);
// Determine if sample exists
I finally found an example of decompression on a Commander II computer and it seems to be identical to the EMC. --- src/cochran_commander_parser.c | 71 ++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 37 deletions(-)
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c index 484b195..9340d01 100644 --- a/src/cochran_commander_parser.c +++ b/src/cochran_commander_parser.c @@ -602,45 +602,42 @@ cochran_commander_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callb if (s[0] & 0x80) { offset += cochran_commander_handle_event(parser, s[0], callback, userdata);
- if (layout->format == SAMPLE_EMC) { - // EMC models have events indicating change in deco status - // Commander may have them but I don't have example data - switch (s[0]) { - case 0xC5: // Deco obligation begins - deco_obligation = 1; - break; - case 0xD8: // Deco obligation ends - deco_obligation = 0; - break; - case 0xAB: // Decrement ceiling (deeper) - deco_ceiling += 10; // feet + // Events indicating change in deco status + switch (s[0]) { + case 0xC5: // Deco obligation begins + deco_obligation = 1; + break; + case 0xD8: // Deco obligation ends + deco_obligation = 0; + break; + case 0xAB: // Decrement ceiling (deeper) + deco_ceiling += 10; // feet
- sample.deco.type = DC_DECO_DECOSTOP; - sample.deco.time = (array_uint16_le(s + layout->samplesize) + 1) * 60; - sample.deco.depth = deco_ceiling * FEET; - if (callback) callback(DC_SAMPLE_DECO, sample, userdata); - break; - case 0xAD: // Increment ceiling (shallower) - deco_ceiling -= 10; // feet + sample.deco.type = DC_DECO_DECOSTOP; + sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; + sample.deco.depth = deco_ceiling * FEET; + if (callback) callback(DC_SAMPLE_DECO, sample, userdata); + break; + case 0xAD: // Increment ceiling (shallower) + deco_ceiling -= 10; // feet
- sample.deco.type = DC_DECO_DECOSTOP; - sample.deco.depth = deco_ceiling * FEET; - sample.deco.time = (array_uint16_le(s + layout->samplesize) + 1) * 60; - if (callback) callback(DC_SAMPLE_DECO, sample, userdata); - break; - case 0xC0: // Switched to FO2 21% mode (surface) - // Event seen upon surfacing - break; - case 0xCD: // Switched to deco blend - case 0xEF: // Switched to gas blend 2 - sample.gasmix = 1; - if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata); - break; - case 0xF3: // Switched to gas blend 1 - sample.gasmix = 0; - if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata); - break; - } + sample.deco.type = DC_DECO_DECOSTOP; + sample.deco.depth = deco_ceiling * FEET; + sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; + if (callback) callback(DC_SAMPLE_DECO, sample, userdata); + break; + case 0xC0: // Switched to FO2 21% mode (surface) + // Event seen upon surfacing + break; + case 0xCD: // Switched to deco blend + case 0xEF: // Switched to gas blend 2 + sample.gasmix = 1; + if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata); + break; + case 0xF3: // Switched to gas blend 1 + sample.gasmix = 0; + if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata); + break; }
continue;