diff --git a/include/libdivecomputer/oceanic_atom2.h b/include/libdivecomputer/oceanic_atom2.h index 4c52420..4cae707 100644 --- a/include/libdivecomputer/oceanic_atom2.h +++ b/include/libdivecomputer/oceanic_atom2.h @@ -33,6 +33,9 @@ extern "C" { dc_status_t oceanic_atom2_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +oceanic_atom2_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model); + dc_status_t oceanic_atom2_device_version (dc_device_t *device, unsigned char data[], unsigned int size); diff --git a/src/descriptor.c b/src/descriptor.c index d6d75d4..85f6622 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -178,6 +178,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549}, {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B}, {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C}, + {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0}, {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0}, diff --git a/src/device.c b/src/device.c index 1bac4f4..d95585d 100644 --- a/src/device.c +++ b/src/device.c @@ -115,7 +115,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr rc = oceanic_veo250_device_open (&device, context, name); break; case DC_FAMILY_OCEANIC_ATOM2: - rc = oceanic_atom2_device_open (&device, context, name); + rc = oceanic_atom2_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor)); break; case DC_FAMILY_MARES_NEMO: rc = mares_nemo_device_open (&device, context, name); diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 8109f96..f27f6fd 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -92,6 +92,7 @@ mares_darwin_extract_dives mares_iconhd_device_open mares_iconhd_extract_dives oceanic_atom2_device_open +oceanic_atom2_device_open2 oceanic_atom2_device_version oceanic_atom2_device_keepalive oceanic_veo250_device_open diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 2301c35..25e9d9f 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -34,6 +34,8 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable) +#define VTX 0x4557 + #define MAXRETRIES 2 #define MAXDELAY 16 #define INVALID 0xFFFFFFFF @@ -43,6 +45,15 @@ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ ) +#define CMD_INIT 0xA8 +#define CMD_VERSION 0x84 +#define CMD_READ1 0xB1 +#define CMD_READ8 0xB4 +#define CMD_READ16 0xB8 +#define CMD_WRITE 0xB2 +#define CMD_KEEPALIVE 0x91 +#define CMD_QUIT 0x6A + #define ACK 0x5A #define NAK 0xA5 @@ -159,6 +170,7 @@ static const oceanic_common_version_t oceanic_reactpro_version[] = { static const oceanic_common_version_t aeris_a300cs_version[] = { {"AER300CS \0\0 2048"}, + {"OCEANVTX \0\0 2048"}, }; static const oceanic_common_layout_t aeris_f10_layout = { @@ -369,8 +381,9 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { 1 /* pt_mode_logbook */ }; + static dc_status_t -oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char ack) +oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) { dc_device_t *abstract = (dc_device_t *) device; @@ -388,6 +401,12 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[ return EXITCODE (n); } + // Get the correct ACK byte. + unsigned int ack = ACK; + if (command[0] == CMD_INIT || command[0] == CMD_QUIT) { + ack = NAK; + } + // Receive the response (ACK/NAK) of the dive computer. unsigned char response = 0; n = serial_read (device->port, &response, 1); @@ -402,40 +421,6 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[ return DC_STATUS_PROTOCOL; } - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) -{ - dc_device_t *abstract = (dc_device_t *) device; - - // Send the command to the device. If the device responds with an - // ACK byte, the command was received successfully and the answer - // (if any) follows after the ACK byte. If the device responds with - // a NAK byte, we try to resend the command a number of times before - // returning an error. - - unsigned int nretries = 0; - dc_status_t rc = DC_STATUS_SUCCESS; - while ((rc = oceanic_atom2_send (device, command, csize, ACK)) != DC_STATUS_SUCCESS) { - if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) - return rc; - - // Abort if the maximum number of retries is reached. - if (nretries++ >= MAXRETRIES) - return rc; - - // Increase the inter packet delay. - if (device->delay < MAXDELAY) - device->delay++; - - // Delay the next attempt. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_INPUT); - } - if (asize) { // Receive the answer of the dive computer. int n = serial_read (device->port, answer, asize); @@ -463,12 +448,44 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm } +static dc_status_t +oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) +{ + // Send the command to the device. If the device responds with an + // ACK byte, the command was received successfully and the answer + // (if any) follows after the ACK byte. If the device responds with + // a NAK byte, we try to resend the command a number of times before + // returning an error. + + unsigned int nretries = 0; + dc_status_t rc = DC_STATUS_SUCCESS; + while ((rc = oceanic_atom2_packet (device, command, csize, answer, asize, crc_size)) != DC_STATUS_SUCCESS) { + if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) + return rc; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + return rc; + + // Increase the inter packet delay. + if (device->delay < MAXDELAY) + device->delay++; + + // Delay the next attempt. + serial_sleep (device->port, 100); + serial_flush (device->port, SERIAL_QUEUE_INPUT); + } + + return DC_STATUS_SUCCESS; +} + + static dc_status_t oceanic_atom2_quit (oceanic_atom2_device_t *device) { // Send the command to the dive computer. - unsigned char command[4] = {0x6A, 0x05, 0xA5, 0x00}; - dc_status_t rc = oceanic_atom2_send (device, command, sizeof (command), NAK); + unsigned char command[4] = {CMD_QUIT, 0x05, 0xA5, 0x00}; + dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc; @@ -478,6 +495,14 @@ oceanic_atom2_quit (oceanic_atom2_device_t *device) dc_status_t oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char *name) +{ + return oceanic_atom2_device_open2 (out, context, name, 0); +} + + +dc_status_t +oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) + { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -507,8 +532,14 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_IO; } + // Get the correct baudrate. + unsigned int baudrate = 38400; + if (model == VTX) { + baudrate = 115200; + } + // Set the serial communication protocol (38400 8N1). - rc = serial_configure (device->port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + rc = serial_configure (device->port, baudrate, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); serial_close (device->port); @@ -623,7 +654,7 @@ oceanic_atom2_device_keepalive (dc_device_t *abstract) return DC_STATUS_INVALIDARGS; // Send the command to the dive computer. - unsigned char command[4] = {0x91, 0x05, 0xA5, 0x00}; + unsigned char command[4] = {CMD_KEEPALIVE, 0x05, 0xA5, 0x00}; dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc; @@ -644,7 +675,7 @@ oceanic_atom2_device_version (dc_device_t *abstract, unsigned char data[], unsig return DC_STATUS_INVALIDARGS; unsigned char answer[PAGESIZE + 1] = {0}; - unsigned char command[2] = {0x84, 0x00}; + unsigned char command[2] = {CMD_VERSION, 0x00}; dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, sizeof (answer), 1); if (rc != DC_STATUS_SUCCESS) return rc; @@ -669,15 +700,15 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned unsigned int crc_size = 0; switch (device->bigpage) { case 1: - read_cmd = 0xB1; + read_cmd = CMD_READ1; crc_size = 1; break; case 8: - read_cmd = 0xB4; + read_cmd = CMD_READ8; crc_size = 1; break; case 16: - read_cmd = 0xB8; + read_cmd = CMD_READ16; crc_size = 2; break; default: @@ -739,7 +770,7 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u while (nbytes < size) { // Prepare to write the package. unsigned int number = address / PAGESIZE; - unsigned char prepare[4] = {0xB2, + unsigned char prepare[4] = {CMD_WRITE, (number >> 8) & 0xFF, // high (number ) & 0xFF, // low 0x00}; diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index fc68ecb..491e74b 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -72,6 +72,7 @@ #define F11 0x4549 #define OCI 0x454B #define A300CS 0x454C +#define VTX 0x4557 #define NORMAL 0 #define GAUGE 1 @@ -227,6 +228,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim datetime->minute = p[10]; break; case A300CS: + case VTX: datetime->year = (p[10]) + 2000; datetime->month = (p[8]); datetime->day = (p[9]); @@ -381,7 +383,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns *((unsigned int *) value) = 4; } else if (parser->model == TX1) { *((unsigned int *) value) = 6; - } else if (parser->model == A300CS) { + } else if (parser->model == A300CS || parser->model == VTX) { if (data[0x39] & 0x04) { *((unsigned int *) value) = 1; } else if (data[0x39] & 0x08) { @@ -400,7 +402,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns oxygen = data[header + 3]; } else if (parser->model == OCI) { oxygen = data[0x28 + flags]; - } else if (parser->model == A300CS) { + } else if (parser->model == A300CS || parser->model == VTX) { oxygen = data[0x2A + flags]; } else if (parser->model == TX1) { oxygen = data[0x3E + flags]; @@ -413,7 +415,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_SALINITY: - if (parser->model == A300CS) { + if (parser->model == A300CS || parser->model == VTX) { if (data[0x18] & 0x80) { water->type = DC_WATER_FRESH; } else { @@ -478,7 +480,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } else if (parser->model == F11) { headersize = 5 * PAGESIZE; footersize = PAGESIZE / 2; - } else if (parser->model == A300CS) { + } else if (parser->model == A300CS || parser->model == VTX) { headersize = 5 * PAGESIZE; } @@ -504,7 +506,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int interval = 1; if (mode != FREEDIVE) { unsigned int idx = 0x17; - if (parser->model == A300CS) + if (parser->model == A300CS || parser->model == VTX) idx = 0x1f; switch (data[idx] & 0x03) { case 0: @@ -531,7 +533,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } } else if (parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || parser->model == OCI || - parser->model == TX1 || parser->model == A300CS) { + parser->model == TX1 || parser->model == A300CS || + parser->model == VTX) { samplesize = PAGESIZE; } @@ -557,7 +560,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int pressure = 0; if (have_pressure) { unsigned int idx = 2; - if (parser->model == A300CS) + if (parser->model == A300CS || parser->model == VTX) idx = 16; pressure = data[header + idx] + (data[header + idx + 1] << 8); if (pressure == 10000) @@ -611,7 +614,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Tank pressure (1 psi) and number tank = 0; pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF); - } else if (parser->model == A300CS) { + } else if (parser->model == A300CS || parser->model == VTX) { // Tank pressure (1 psi) and number (one based index) tank = (data[offset + 1] & 0x03) - 1; pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF; @@ -656,7 +659,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ temperature = data[offset + 1]; } else if (parser->model == VT4 || parser->model == VT41 || parser->model == ATOM3 || parser->model == ATOM31 || parser->model == A300AI) { temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4); - } else if (parser->model == A300CS) { + } else if (parser->model == A300CS || parser->model == VTX) { temperature = data[offset + 11]; } else { unsigned int sign; @@ -690,7 +693,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == ZENAIR ||parser->model == A300AI || parser->model == DG03 || parser->model == PROPLUS3) pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5; - else if (parser->model == TX1 || parser->model == A300CS) + else if (parser->model == TX1 || parser->model == A300CS || parser->model == VTX) pressure = array_uint16_le (data + offset + 4); else pressure -= data[offset + 1]; @@ -718,7 +721,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // NDL / Deco // bits 6..4 of byte 15 encode deco state & depth // bytes 6 & 7 encode minutes of NDL / deco - if (parser->model == A300CS) { + if (parser->model == A300CS || parser->model == VTX) { unsigned int deco = (data[offset + 15] & 0x70) >> 4; if (deco) { sample.deco.type = DC_DECO_DECOSTOP;