Previously cochran_check_profiles() was called to establish which dive is the earliest one with a profile. Now logic in foreach() counts profile data to detect when dives no longer have valid profile data. --- src/cochran_commander.c | 146 +++++++++++++++--------------------------------- src/cochran_commander.h | 4 +- 2 files changed, 46 insertions(+), 104 deletions(-)
diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 127518d..47ecebb 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -67,7 +67,7 @@ const cochran_device_info_t cochran_cmdr_device_info = { const cochran_conf_offsets_t cochran_cmdr_conf_offsets = { 0x046, // dive_count 0x06e, // last_log - 0x071, // last_interdive + 0x200, // last_interdive 0x0aa, // serial_number };
@@ -202,8 +202,6 @@ cochran_read_id(dc_device_t *device, unsigned char *id, int size); static dc_status_t cochran_commander_read (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int address, unsigned char data[], unsigned int size); -static void -cochran_check_profiles(dc_device_t *abstract, cochran_data_t *data);
static dc_status_t @@ -599,13 +597,17 @@ cochran_read_config (dc_device_t *abstract, cochran_data_t *data, dc_event_progr dc_status_t rc; unsigned char command[2] = { 0x96, 0x00 };
- rc = cochran_packet(device, progress, command, sizeof(command), data->config, sizeof(data->config), 0); - if (rc != DC_STATUS_SUCCESS) - return rc; + // Read two 512 byte blocks into one 1024 byte buffer + for (int i = 0; i < 2; i++) { + command[1] = i; + rc = cochran_packet(device, progress, command, sizeof(command), data->config + i * 512, sizeof(data->config) / 2, 0); + if (rc != DC_STATUS_SUCCESS) + return rc;
- vendor.data = data->config; - vendor.size = sizeof(data->config); - device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + vendor.data = data->config + i * 512; + vendor.size = sizeof(data->config) / 2; + device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + }
return DC_STATUS_SUCCESS; } @@ -806,9 +808,6 @@ cochran_commander_device_read_all (dc_device_t *abstract, cochran_data_t *data) if (rc != DC_STATUS_SUCCESS) return rc;
- // Determine logs that haven't had profile data overwritten - cochran_check_profiles(abstract, data); - return DC_STATUS_SUCCESS; }
@@ -919,6 +918,17 @@ cochran_commander_device_foreach (dc_device_t *abstract, if (rc != DC_STATUS_SUCCESS) return rc;
+ // Calculate profile RB effective head pointer + // Cochran seems to erase 8K chunks so round up. + int last_start_address = (array_uint32_le(data.config + device->conf_ptr->last_interdive) & 0xfffff000) + 0x2000; + if (last_start_address < device->info->rb_profile_begin || last_start_address > device->info->rb_profile_end) { + ERROR(abstract->context, "Invalid profile ringbuffer head pointer in Cochra config block."); + return DC_STATUS_DATAFORMAT; + } + + // We track profile ringbuffer usage to determine which dives have profile data + int profile_capacity_remaining = device->info->rb_profile_end - device->info->rb_profile_begin; + // Loop through each dive int i; for (i = data.dive_count - 1; i > data.fp_dive_num; i--) { @@ -940,19 +950,32 @@ cochran_commander_device_foreach (dc_device_t *abstract, // Corrupt dive, guess the end address sample_end_address = cochran_guess_sample_end_address(device, &data, i);
- sample = data.sample + sample_start_address - data.sample_data_offset; + // Determine if sample exists + if (profile_capacity_remaining > 0) { + // Subtract this dive's profile size including post-dive events + profile_capacity_remaining -= (last_start_address - sample_start_address); + // Adjust for a dive that wraps the buffer + if (sample_start_address > last_start_address) + profile_capacity_remaining -= device->info->rb_profile_end - device->info->rb_profile_begin; + } + last_start_address = sample_start_address;
- // Determine size of sample - unsigned int dive_num =array_uint16_le(log_entry + device->log_ptr->dive_number); - if (dive_num >= data.profile_tail) - sample_size = sample_end_address - sample_start_address; - else + if (profile_capacity_remaining < 0) { + // There is no profile for this dive + sample = NULL; sample_size = 0; + WARNING(abstract->context, "Profile data for dive %d was overwritten by newer dives.", + array_uint16_le(log_entry + device->log_ptr->dive_number)); + } else { + // Calculate the size of the profile only + sample = data.sample + sample_start_address - data.sample_data_offset; + sample_size = sample_end_address - sample_start_address;
- if (sample_size < 0) - // Adjust for ring buffer wrap-around - sample_size += device->info->rb_profile_end - - device->info->rb_profile_begin; + if (sample_size < 0) + // Adjust for ring buffer wrap-around + sample_size += device->info->rb_profile_end + - device->info->rb_profile_begin; + }
fingerprint = log_entry; // Date bytes
@@ -990,82 +1013,3 @@ cochran_commander_device_foreach (dc_device_t *abstract,
return DC_STATUS_SUCCESS; } - - -/* -* cochran_check_profiles(dc_device_t *abstract) -* -* Scan logs to identify which have valid profile data, i.e. the profiles -* have not been overwritten in the ringbuffer. -* -*/ - -static void -cochran_check_profiles(dc_device_t *abstract, cochran_data_t *data) { - cochran_device_t *device = (cochran_device_t *) abstract; - - // Find head log entry - // Set handy point to first dive's dive number - unsigned char *l = data->logbook + device->log_ptr->dive_number; - int head; - for (head = 0; head < device->info->logbook_entry_count - 1; head ++) { - int this_dive = array_uint16_le(l); - l += device->info->logbook_entry_size; - int next_dive = array_uint16_le(l); - - if (next_dive < this_dive || next_dive == 0xFFFF) - break; - } - - // This is the last piece of data - unsigned int head_ptr; - if (device->info->endian == ENDIAN_LE) - head_ptr = array_uint32_le(data->config + device->conf_ptr->last_log); - else - head_ptr = array_uint32_be(data->config + device->conf_ptr->last_log); - - // Cochran (commander at least) erases 8k blocks, so round up - head_ptr = (head_ptr & 0xfffff000) + 0x2000; - - // Now move backwards until we find a profile that overlaps this one. - // Wrap around the ring buffer if needed. - - int tail; - int profile_wrap = 0; - int n = head - 1; - if (n < 0) - n = MIN(device->info->logbook_entry_count - 1, head); - - while (n != head) { - unsigned int start_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_begin_offset); - unsigned int end_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_end_offset); - - if (start_dive_ptr == 0xFFFFFFFF || start_dive_ptr == 0) { - n--; - if (n < 0) - n = MIN(device->info->logbook_entry_count - 1, head); - continue; - } - - tail = n; - - if (profile_wrap) { - if (start_dive_ptr < head_ptr) { - // We've found the last valid dive - break; - } - } else { - if (start_dive_ptr > end_dive_ptr) - profile_wrap = 1; - } - - n--; - if (n < 0) - n = MIN(device->info->logbook_entry_count - 1, head); - } - - data->log_head = head; - data->profile_head = head; - - data->profile_tail = tail; -} diff --git a/src/cochran_commander.h b/src/cochran_commander.h index f6e3921..14cfedf 100644 --- a/src/cochran_commander.h +++ b/src/cochran_commander.h @@ -96,14 +96,12 @@ typedef struct cochran_log_offsets_t { } cochran_log_offsets_t;
typedef struct cochran_data_t { - unsigned char config[512]; + unsigned char config[1024]; unsigned char *logbook; unsigned char *sample;
unsigned short int dive_count; int fp_dive_num; - int log_head, log_tail; // head and tail for log ringbuffer - int profile_head, profile_tail; // Entries that have valid profiles
unsigned int logbook_size;