Merge git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch
Merge upstream libdivecomputer changes as requested by Jan Mulder. "DiveSystem iX3M: - Add support for new iX3M models - Add support for new iX3M APOS4 firmware - Add iX3M firmware version to the devinfo event (ix3m) Shearwater: - Report the ppO2 in external O2 sensor mode only (Shearwater) - Replace the constant offset with a scaling factor (Shearwater) - Apply the calibration correction only for the Predator - Report individual sensor values - Predator: don't report PPO2 unless in CC mode Misc: - Fix Sherwood Wisdom 3 memory layout - Implement read and write functions for OSTC3 - Add support for Mares Quad - Fix uwatec handshaking error handling" * 'master' of git://git.libdivecomputer.org/libdivecomputer: Add support for the new models Add support for the new iX3M APOS4 firmware Add the firmware version to the devinfo event Report the ppO2 in external O2 sensor mode only Replace the constant offset with a scaling factor Apply the calibration correction only for the Predator shearwater: Report individual sensor values Predator: don't report PPO2 unless in CC mode Fix the Sherwood Wisdom 3 memory layout Implement the read and write functions for the OSTC3 Don't ignore handshaking errors Add support for the Mares Quad
This commit is contained in:
commit
a0c5b5b53b
@ -231,6 +231,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18},
|
||||
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19},
|
||||
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F},
|
||||
{"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29},
|
||||
/* Heinrichs Weikamp */
|
||||
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0},
|
||||
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1},
|
||||
@ -290,8 +291,15 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B},
|
||||
{"DiveSystem", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
|
||||
{"DiveSystem", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
|
||||
{"DiveSystem", "iX3M Tec", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
|
||||
{"DiveSystem", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
|
||||
{"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
|
||||
{"DiveSystem", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32},
|
||||
{"DiveSystem", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34},
|
||||
{"DiveSystem", "iX3M Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x35},
|
||||
{"DiveSystem", "iDive2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40},
|
||||
{"DiveSystem", "iDive2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42},
|
||||
{"DiveSystem", "iDive2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44},
|
||||
{"DiveSystem", "iDive2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45},
|
||||
{"Cochran", "Commander", DC_FAMILY_COCHRAN_COMMANDER, 0},
|
||||
{"Cochran", "EMC-14", DC_FAMILY_COCHRAN_COMMANDER, 1},
|
||||
{"Cochran", "EMC-16", DC_FAMILY_COCHRAN_COMMANDER, 2},
|
||||
|
||||
@ -57,6 +57,7 @@ typedef struct divesystem_idive_commands_t {
|
||||
divesystem_idive_command_t range;
|
||||
divesystem_idive_command_t header;
|
||||
divesystem_idive_command_t sample;
|
||||
unsigned int nsamples;
|
||||
} divesystem_idive_commands_t;
|
||||
|
||||
typedef struct divesystem_idive_device_t {
|
||||
@ -86,6 +87,7 @@ static const divesystem_idive_commands_t idive = {
|
||||
{0x98, 0x04},
|
||||
{0xA0, 0x32},
|
||||
{0xA8, 0x2A},
|
||||
1,
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t ix3m = {
|
||||
@ -93,6 +95,15 @@ static const divesystem_idive_commands_t ix3m = {
|
||||
{0x78, 0x04},
|
||||
{0x79, 0x36},
|
||||
{0x7A, 0x36},
|
||||
1,
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t ix3m_apos4 = {
|
||||
{0x11, 0x1A},
|
||||
{0x78, 0x04},
|
||||
{0x79, 0x36},
|
||||
{0x7A, 0x40},
|
||||
3,
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
@ -356,7 +367,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
unsigned char packet[MAXPACKET - 2];
|
||||
|
||||
const divesystem_idive_commands_t *commands = &idive;
|
||||
if (device->model >= IX3M_EASY && device->model <= IX3M_REB) {
|
||||
if (device->model >= IX3M_EASY) {
|
||||
commands = &ix3m;
|
||||
}
|
||||
|
||||
@ -372,7 +383,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = array_uint16_le (packet);
|
||||
devinfo.firmware = 0;
|
||||
devinfo.firmware = array_uint32_le (packet + 2);
|
||||
devinfo.serial = array_uint32_le (packet + 6);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
@ -382,6 +393,14 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
vendor.size = commands->id.size;
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
|
||||
if (device->model >= IX3M_EASY) {
|
||||
// Detect the APOS4 firmware.
|
||||
unsigned int apos4 = (devinfo.firmware / 10000000) >= 4;
|
||||
if (apos4) {
|
||||
commands = &ix3m_apos4;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char cmd_range[] = {commands->range.cmd, 0x8D};
|
||||
rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), packet, commands->range.size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
@ -429,20 +448,28 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
dc_buffer_reserve(buffer, commands->header.size + commands->sample.size * nsamples);
|
||||
dc_buffer_append(buffer, packet, commands->header.size);
|
||||
|
||||
for (unsigned int j = 0; j < nsamples; ++j) {
|
||||
for (unsigned int j = 0; j < nsamples; j += commands->nsamples) {
|
||||
unsigned int idx = j + 1;
|
||||
unsigned char cmd_sample[] = {commands->sample.cmd,
|
||||
(idx ) & 0xFF,
|
||||
(idx >> 8) & 0xFF};
|
||||
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size);
|
||||
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size * commands->nsamples);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// If the number of samples is not an exact multiple of the
|
||||
// number of samples per packet, then the last packet
|
||||
// appears to contain garbage data. Ignore those samples.
|
||||
unsigned int n = commands->nsamples;
|
||||
if (j + n > nsamples) {
|
||||
n = nsamples - j;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = i * NSTEPS + STEP(j + 2, nsamples + 1);
|
||||
progress.current = i * NSTEPS + STEP(j + n + 1, nsamples + 1);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_append(buffer, packet, commands->sample.size);
|
||||
dc_buffer_append(buffer, packet, commands->sample.size * n);
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data(buffer);
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#define SZ_SAMPLE_IDIVE 0x2A
|
||||
#define SZ_HEADER_IX3M 0x36
|
||||
#define SZ_SAMPLE_IX3M 0x36
|
||||
#define SZ_SAMPLE_IX3M_APOS4 0x40
|
||||
|
||||
#define NGASMIXES 8
|
||||
|
||||
@ -53,8 +54,8 @@ typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
||||
|
||||
struct divesystem_idive_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
unsigned int headersize;
|
||||
unsigned int samplesize;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int divemode;
|
||||
@ -97,12 +98,11 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
if (model >= IX3M_EASY && model <= IX3M_REB) {
|
||||
parser->model = model;
|
||||
if (model >= IX3M_EASY) {
|
||||
parser->headersize = SZ_HEADER_IX3M;
|
||||
parser->samplesize = SZ_SAMPLE_IX3M;
|
||||
} else {
|
||||
parser->headersize = SZ_HEADER_IDIVE;
|
||||
parser->samplesize = SZ_SAMPLE_IDIVE;
|
||||
}
|
||||
parser->cached = 0;
|
||||
parser->divemode = INVALID;
|
||||
@ -241,8 +241,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int mode_previous = INVALID;
|
||||
unsigned int divemode = INVALID;
|
||||
|
||||
unsigned int nsamples = array_uint16_le (data + 1);
|
||||
unsigned int samplesize = SZ_SAMPLE_IDIVE;
|
||||
if (parser->model >= IX3M_EASY) {
|
||||
// Detect the APOS4 firmware.
|
||||
unsigned int firmware = array_uint32_le(data + 0x2A);
|
||||
unsigned int apos4 = (firmware / 10000000) >= 4;
|
||||
if (apos4) {
|
||||
// Dive downloaded and recorded with the APOS4 firmware.
|
||||
samplesize = SZ_SAMPLE_IX3M_APOS4;
|
||||
} else if (size == parser->headersize + nsamples * SZ_SAMPLE_IX3M_APOS4) {
|
||||
// Dive downloaded with the APOS4 firmware, but recorded
|
||||
// with an older firmware.
|
||||
samplesize = SZ_SAMPLE_IX3M_APOS4;
|
||||
} else {
|
||||
// Dive downloaded and recorded with an older firmware.
|
||||
samplesize = SZ_SAMPLE_IX3M;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int offset = parser->headersize;
|
||||
while (offset + parser->samplesize <= size) {
|
||||
while (offset + samplesize <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Time (seconds).
|
||||
@ -328,7 +347,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
|
||||
offset += parser->samplesize;
|
||||
offset += samplesize;
|
||||
}
|
||||
|
||||
// Cache the data for later use.
|
||||
|
||||
@ -125,6 +125,8 @@ static const unsigned char ostc3_key[16] = {
|
||||
};
|
||||
|
||||
static dc_status_t hw_ostc3_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t hw_ostc3_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t hw_ostc3_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
|
||||
static dc_status_t hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t hw_ostc3_device_close (dc_device_t *abstract);
|
||||
@ -133,8 +135,8 @@ static const dc_device_vtable_t hw_ostc3_device_vtable = {
|
||||
sizeof(hw_ostc3_device_t),
|
||||
DC_FAMILY_HW_OSTC3,
|
||||
hw_ostc3_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
hw_ostc3_device_read, /* read */
|
||||
hw_ostc3_device_write, /* write */
|
||||
hw_ostc3_device_dump, /* dump */
|
||||
hw_ostc3_device_foreach, /* foreach */
|
||||
hw_ostc3_device_close /* close */
|
||||
@ -1181,7 +1183,7 @@ hw_ostc3_firmware_block_read (hw_ostc3_device_t *device, unsigned int addr, unsi
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int addr, unsigned char block[], unsigned int block_size)
|
||||
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int addr, const unsigned char block[], unsigned int block_size)
|
||||
{
|
||||
unsigned char buffer[3 + SZ_FIRMWARE_BLOCK];
|
||||
|
||||
@ -1446,6 +1448,87 @@ hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
|
||||
if ((address % SZ_FIRMWARE_BLOCK != 0) ||
|
||||
(size % SZ_FIRMWARE_BLOCK != 0)) {
|
||||
ERROR (abstract->context, "Address or size not aligned to the page size!");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Make sure the device is in service mode.
|
||||
status = hw_ostc3_device_init (device, SERVICE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
// Read a memory page.
|
||||
status = hw_ostc3_firmware_block_read (device, address + nbytes, data + nbytes, SZ_FIRMWARE_BLOCK);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read block.");
|
||||
return status;
|
||||
}
|
||||
|
||||
nbytes += SZ_FIRMWARE_BLOCK;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
|
||||
if ((address % SZ_FIRMWARE_BLOCK != 0) ||
|
||||
(size % SZ_FIRMWARE_BLOCK != 0)) {
|
||||
ERROR (abstract->context, "Address or size not aligned to the page size!");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Make sure the device is in service mode.
|
||||
status = hw_ostc3_device_init (device, SERVICE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Erase the memory pages.
|
||||
status = hw_ostc3_firmware_erase (device, address, size);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to erase blocks.");
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
// Write a memory page.
|
||||
status = hw_ostc3_firmware_block_write (device, address + nbytes, data + nbytes, SZ_FIRMWARE_BLOCK);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to write block.");
|
||||
return status;
|
||||
}
|
||||
|
||||
nbytes += SZ_FIRMWARE_BLOCK;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
{
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
#define PUCKPRO 0x18
|
||||
#define NEMOWIDE2 0x19
|
||||
#define PUCK2 0x1F
|
||||
#define QUAD 0x29
|
||||
|
||||
#define ACK 0xAA
|
||||
#define EOF 0xEA
|
||||
@ -125,6 +126,7 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
|
||||
{"Puck Pro", PUCKPRO},
|
||||
{"Nemo Wide 2", NEMOWIDE2},
|
||||
{"Puck 2", PUCK2},
|
||||
{"Quad", QUAD},
|
||||
};
|
||||
|
||||
// Check the product name in the version packet against the list
|
||||
@ -292,6 +294,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
|
||||
case NEMOWIDE2:
|
||||
case SMART:
|
||||
case SMARTAPNEA:
|
||||
case QUAD:
|
||||
device->layout = &mares_nemowide2_layout;
|
||||
device->packetsize = 256;
|
||||
break;
|
||||
|
||||
@ -101,7 +101,6 @@ static const oceanic_common_version_t oceanic_atom2_version[] = {
|
||||
|
||||
static const oceanic_common_version_t oceanic_atom2a_version[] = {
|
||||
{"MANTA R\0\0 512K"},
|
||||
{"WISDOM R\0\0 512K"},
|
||||
{"INSIGHT2 \0\0 512K"},
|
||||
{"OCEVEO30 \0\0 512K"},
|
||||
{"ATMOSAI R\0\0 512K"},
|
||||
@ -132,6 +131,10 @@ static const oceanic_common_version_t oceanic_default_version[] = {
|
||||
{"COMPMASK \0\0 512K"},
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t sherwood_wisdom_version[] = {
|
||||
{"WISDOM R\0\0 512K"},
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t oceanic_proplus3_version[] = {
|
||||
{"PROPLUS3 \0\0 512K"},
|
||||
};
|
||||
@ -288,6 +291,20 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = {
|
||||
0, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t sherwood_wisdom_layout = {
|
||||
0xFFF0, /* memsize */
|
||||
0x0000, /* cf_devinfo */
|
||||
0x0040, /* cf_pointers */
|
||||
0x03D0, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
0, /* pt_mode_logbook */
|
||||
0, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t oceanic_proplus3_layout = {
|
||||
0x10000, /* memsize */
|
||||
0x0000, /* cf_devinfo */
|
||||
@ -645,6 +662,8 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
device->base.layout = &oceanic_atom2b_layout;
|
||||
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2c_version)) {
|
||||
device->base.layout = &oceanic_atom2c_layout;
|
||||
} else if (OCEANIC_COMMON_MATCH (device->base.version, sherwood_wisdom_version)) {
|
||||
device->base.layout = &sherwood_wisdom_layout;
|
||||
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplus3_version)) {
|
||||
device->base.layout = &oceanic_proplus3_layout;
|
||||
} else if (OCEANIC_COMMON_MATCH (device->base.version, tusa_zenair_version)) {
|
||||
|
||||
@ -149,10 +149,10 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
rc = atomics_cobalt_parser_create (&parser, context);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PREDATOR:
|
||||
rc = shearwater_predator_parser_create (&parser, context, serial);
|
||||
rc = shearwater_predator_parser_create (&parser, context, model, serial);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PETREL:
|
||||
rc = shearwater_petrel_parser_create (&parser, context, serial);
|
||||
rc = shearwater_petrel_parser_create (&parser, context, model, serial);
|
||||
break;
|
||||
case DC_FAMILY_DIVERITE_NITEKQ:
|
||||
rc = diverite_nitekq_parser_create (&parser, context);
|
||||
|
||||
@ -34,7 +34,7 @@ dc_status_t
|
||||
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, const char *name);
|
||||
|
||||
dc_status_t
|
||||
shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ dc_status_t
|
||||
shearwater_predator_device_open (dc_device_t **device, dc_context_t *context, const char *name);
|
||||
|
||||
dc_status_t
|
||||
shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -54,10 +54,14 @@
|
||||
|
||||
#define NGASMIXES 10
|
||||
|
||||
#define PREDATOR 2
|
||||
#define PETREL 3
|
||||
|
||||
typedef struct shearwater_predator_parser_t shearwater_predator_parser_t;
|
||||
|
||||
struct shearwater_predator_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
unsigned int petrel;
|
||||
unsigned int samplesize;
|
||||
// Cached fields.
|
||||
@ -67,6 +71,7 @@ struct shearwater_predator_parser_t {
|
||||
unsigned int ngasmixes;
|
||||
unsigned int oxygen[NGASMIXES];
|
||||
unsigned int helium[NGASMIXES];
|
||||
double calibration[3];
|
||||
unsigned int serial;
|
||||
dc_divemode_t mode;
|
||||
};
|
||||
@ -112,7 +117,7 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned
|
||||
|
||||
|
||||
static dc_status_t
|
||||
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int petrel)
|
||||
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial, unsigned int petrel)
|
||||
{
|
||||
shearwater_predator_parser_t *parser = NULL;
|
||||
const dc_parser_vtable_t *vtable = NULL;
|
||||
@ -136,14 +141,11 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Initialize the base class.
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->petrel = petrel;
|
||||
parser->samplesize = samplesize;
|
||||
parser->serial = serial;
|
||||
if (petrel) {
|
||||
parser->samplesize = SZ_SAMPLE_PETREL;
|
||||
} else {
|
||||
parser->samplesize = SZ_SAMPLE_PREDATOR;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->cached = 0;
|
||||
@ -163,16 +165,16 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
|
||||
|
||||
dc_status_t
|
||||
shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
|
||||
{
|
||||
return shearwater_common_parser_create (out, context, serial, 0);
|
||||
return shearwater_common_parser_create (out, context, model, serial, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
|
||||
{
|
||||
return shearwater_common_parser_create (out, context, serial, 1);
|
||||
return shearwater_common_parser_create (out, context, model, serial, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -297,6 +299,20 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
|
||||
offset += parser->samplesize;
|
||||
}
|
||||
|
||||
// Cache sensor calibration for later use
|
||||
parser->calibration[0] = array_uint16_be(data + 87) / 100000.0;
|
||||
parser->calibration[1] = array_uint16_be(data + 89) / 100000.0;
|
||||
parser->calibration[2] = array_uint16_be(data + 91) / 100000.0;
|
||||
// The Predator expects the mV output of the cells to be within 30mV
|
||||
// to 70mV in 100% O2 at 1 atmosphere.
|
||||
// If the calibration value is scaled with a factor 2.2, then the
|
||||
// sensors lines up and matches the average.
|
||||
if (parser->model == PREDATOR) {
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
parser->calibration[i] *= 2.2;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the data for later use.
|
||||
parser->headersize = headersize;
|
||||
parser->footersize = footersize;
|
||||
@ -492,9 +508,22 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
|
||||
unsigned int status = data[offset + 11];
|
||||
|
||||
if ((status & OC) == 0) {
|
||||
// PPO2 -- only return PPO2 if we are in closed circuit mode
|
||||
// PPO2
|
||||
#ifdef SENSOR_AVERAGE
|
||||
sample.ppo2 = data[offset + 6] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
#else
|
||||
if ((status & PPO2_EXTERNAL) == 0) {
|
||||
sample.ppo2 = data[offset + 12] * parser->calibration[0];
|
||||
if (callback && (data[86] & 0x01)) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
|
||||
sample.ppo2 = data[offset + 14] * parser->calibration[1];
|
||||
if (callback && (data[86] & 0x02)) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
|
||||
sample.ppo2 = data[offset + 15] * parser->calibration[2];
|
||||
if (callback && (data[86] & 0x04)) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setpoint
|
||||
if (parser->petrel) {
|
||||
|
||||
@ -228,7 +228,11 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha
|
||||
dc_serial_purge (device->port, DC_DIRECTION_ALL);
|
||||
|
||||
// Perform the handshaking.
|
||||
uwatec_meridian_handshake (device);
|
||||
status = uwatec_meridian_handshake (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to handshake with the device.");
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
*out = (dc_device_t*) device;
|
||||
|
||||
|
||||
@ -191,7 +191,11 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
// Perform the handshaking.
|
||||
uwatec_smart_handshake (device);
|
||||
status = uwatec_smart_handshake (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to handshake with the device.");
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
*out = (dc_device_t*) device;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user