Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Tern TX", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Peregrine TX", DC_FAMILY_SHEARWATER_PETREL, 13, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Perdix 3", DC_FAMILY_SHEARWATER_PETREL, 14, DC_TRANSPORT_BLE, dc_filter_shearwater},
/* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
/* Citizen Hyper Aqualand */
Expand Down Expand Up @@ -764,6 +765,7 @@ dc_filter_shearwater (const dc_descriptor_t *descriptor, dc_transport_t transpor
"NERD 2",
"Perdix",
"Perdix 2",
"Perdix 3",
"Teric",
"Peregrine",
"Peregrine TX",
Expand Down
2 changes: 1 addition & 1 deletion src/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
rc = shearwater_predator_device_open (&device, context, iostream);
break;
case DC_FAMILY_SHEARWATER_PETREL:
rc = shearwater_petrel_device_open (&device, context, iostream);
rc = shearwater_petrel_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break;
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_device_open (&device, context, iostream);
Expand Down
138 changes: 103 additions & 35 deletions src/shearwater_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,22 @@
#include "platform.h"
#include "array.h"

#define SZ_PACKET 254
#define BLE_MTU_MIN 20
#define BLE_MTU_MAX 514

// Protocol variants.
#define V1 1
#define V2 2

// Maximum packet payload size.
// The V1 protocol uses an 8 bit length field, while the V2 protocol
// uses a 16 bit length field. Theoretically the V2 maximum size is
// 2^16-1 bytes, but the largest observed value is much smaller (0x0202
// for the manifest and 0x0902 for the dive). Allow for an extra margin
// for future expansions.
#define SZ_PACKET_V1 254
#define SZ_PACKET_V2 4096
#define SZ_PACKET_MAX SZ_PACKET_V2

// SLIP special character codes
#define END 0xC0
Expand All @@ -42,10 +57,19 @@
#define WDBI_REQUEST 0x2E
#define WDBI_RESPONSE 0x6E

#define UPLOAD_INIT_REQUEST 0x35
#define UPLOAD_INIT_RESPONSE 0x75

#define UPLOAD_DATA_REQUEST 0x36
#define UPLOAD_DATA_RESPONSE 0x76

#define UPLOAD_EXIT_REQUEST 0x37
#define UPLOAD_EXIT_RESPONSE 0x77

#define NAK 0x7F

dc_status_t
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream)
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;

Expand All @@ -69,6 +93,8 @@ shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *conte
dc_iostream_sleep (device->iostream, 300);
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);

device->protocol = (model == PERDIX3) ? V2 : V1;

return DC_STATUS_SUCCESS;
}

Expand Down Expand Up @@ -136,10 +162,11 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
unsigned char buffer[32];
const unsigned int header = transport == DC_TRANSPORT_BLE && device->protocol != V2;
unsigned char buffer[BLE_MTU_MIN];
unsigned int nbytes = 0;
Comment on lines 163 to 167

if (transport == DC_TRANSPORT_BLE) {
if (header) {
// Calculate the total number of bytes.
unsigned int count = 1;
for (unsigned int i = 0; i < size; ++i) {
Expand Down Expand Up @@ -174,7 +201,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
return status;
}

if (transport == DC_TRANSPORT_BLE) {
if (header) {
buffer[1]++;
nbytes = 2;
} else {
Expand All @@ -201,7 +228,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
return status;
}

if (transport == DC_TRANSPORT_BLE) {
if (header) {
buffer[1]++;
nbytes = 2;
} else {
Expand Down Expand Up @@ -229,7 +256,8 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
unsigned char buffer[256];
const unsigned int header = transport == DC_TRANSPORT_BLE && device->protocol != V2;
unsigned char buffer[BLE_MTU_MAX];
unsigned int escaped = 0;
unsigned int nbytes = 0;

Expand All @@ -249,7 +277,7 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d
}

size_t offset = 0;
if (transport == DC_TRANSPORT_BLE) {
if (header) {
if (transferred < 2) {
ERROR (device->base.context, "Invalid packet length (" DC_PRINTF_SIZE ").", transferred);
return DC_STATUS_PROTOCOL;
Expand Down Expand Up @@ -330,10 +358,12 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
unsigned char packet[SZ_PACKET + 4];
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
const unsigned int headerlen = (device->protocol == V2) ? 5 : 4;
unsigned char packet[SZ_PACKET_MAX + 5];
unsigned int n = 0;
Comment on lines +361 to 364

if (isize > SZ_PACKET || osize > SZ_PACKET)
if (isize > maxpacket || osize > maxpacket)
return DC_STATUS_INVALIDARGS;

if (device_is_cancelled (abstract))
Expand All @@ -342,12 +372,19 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
// Setup the request packet.
packet[0] = 0xFF;
packet[1] = 0x01;
packet[2] = isize + 1;
packet[3] = 0x00;
memcpy (packet + 4, input, isize);
if (device->protocol == V2) {
// FF 01 00 [len_hi] [len_lo] <payload>
packet[2] = 0x00;
array_uint16_be_set (packet + 3, isize);
} else {
// FF 01 [len+1] 00 <payload>
packet[2] = isize + 1;
packet[3] = 0x00;
}
memcpy (packet + headerlen, input, isize);

// Send the request packet.
status = shearwater_common_slip_write (device, packet, isize + 4);
status = shearwater_common_slip_write (device, packet, isize + headerlen);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the request packet.");
return status;
Expand All @@ -368,21 +405,33 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
}

// Validate the packet header.
if (n < 4 || packet[0] != 0x01 || packet[1] != 0xFF || packet[3] != 0x00) {
unsigned int idx = (device->protocol == V2) ? 2 : 3;
if (n < headerlen || packet[0] != 0x01 || packet[1] != 0xFF || packet[idx] != 0x00) {
ERROR (abstract->context, "Invalid packet header.");
return DC_STATUS_PROTOCOL;
}

// Validate the packet length.
unsigned int length = packet[2];
if (length < 1 || length - 1 + 4 != n || length - 1 > osize) {
unsigned int length = 0;
if (device->protocol == V2) {
length = array_uint16_be (packet + 3);
} else {
length = packet[2];
if (length < 1) {
ERROR (abstract->context, "Invalid packet header.");
return DC_STATUS_PROTOCOL;
}

length -= 1;
}
if (length + headerlen != n || length > osize) {
ERROR (abstract->context, "Invalid packet header.");
return DC_STATUS_PROTOCOL;
}

memcpy (output, packet + 4, length - 1);
memcpy (output, packet + headerlen, length);
if (actual)
*actual = length - 1;
*actual = length;

return DC_STATUS_SUCCESS;
}
Expand All @@ -393,10 +442,12 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
{
dc_device_t *abstract = (dc_device_t *) device;
dc_status_t rc = DC_STATUS_SUCCESS;
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
unsigned char response[SZ_PACKET_MAX];
unsigned int n = 0;
Comment on lines 442 to 447

unsigned char req_init[] = {
0x35,
UPLOAD_INIT_REQUEST,
(compression ? 0x10 : 0x00),
0x34,
(address >> 24) & 0xFF,
Expand All @@ -406,9 +457,10 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
(size >> 16) & 0xFF,
(size >> 8) & 0xFF,
(size ) & 0xFF};
unsigned char req_block[] = {0x36, 0x00};
unsigned char req_quit[] = {0x37};
unsigned char response[SZ_PACKET];
unsigned char req_block[] = {UPLOAD_DATA_REQUEST, 0x00, 0x00};
unsigned char req_quit[] = {UPLOAD_EXIT_REQUEST};
unsigned int req_block_len = (device->protocol == V2) ?
sizeof(req_block) : sizeof(req_block) - 1;

// Erase the current contents of the buffer.
if (!dc_buffer_clear (buffer)) {
Expand All @@ -424,13 +476,27 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}

// Transfer the init request.
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, 3, &n);
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, maxpacket, &n);
if (rc != DC_STATUS_SUCCESS) {
return rc;
}

// Verify the init response.
if (n != 3 || response[0] != 0x75 || response[1] != 0x10 || response[2] > SZ_PACKET) {
if (n < 2 || response[0] != UPLOAD_INIT_RESPONSE) {
ERROR (abstract->context, "Unexpected response packet.");
return DC_STATUS_PROTOCOL;
}

// Verify the init response length.
unsigned int len = (response[1] & 0xF0) >> 4;
if (n < len + 2 || len > 4) {
ERROR (abstract->context, "Unexpected response packet.");
return DC_STATUS_PROTOCOL;
}

// Verify the maximum packet length.
unsigned int maxlength = array_uint_be (response + 2, len);
if (maxlength > maxpacket) {
ERROR (abstract->context, "Unexpected response packet.");
return DC_STATUS_PROTOCOL;
}
Expand All @@ -448,13 +514,13 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
while (nbytes < size && !done) {
// Transfer the block request.
req_block[1] = block;
rc = shearwater_common_transfer (device, req_block, sizeof (req_block), response, sizeof (response), &n);
rc = shearwater_common_transfer (device, req_block, req_block_len, response, maxpacket, &n);
if (rc != DC_STATUS_SUCCESS) {
return rc;
}

// Verify the block header.
if (n < 2 || response[0] != 0x76 || response[1] != block) {
if (n < 2 || response[0] != UPLOAD_DATA_RESPONSE || response[1] != block) {
ERROR (abstract->context, "Unexpected response packet.");
return DC_STATUS_PROTOCOL;
}
Expand Down Expand Up @@ -497,13 +563,13 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}

// Transfer the quit request.
rc = shearwater_common_transfer (device, req_quit, sizeof (req_quit), response, 2, &n);
rc = shearwater_common_transfer (device, req_quit, sizeof (req_quit), response, maxpacket, &n);
if (rc != DC_STATUS_SUCCESS) {
return rc;
}

// Verify the quit response.
if (n != 2 || response[0] != 0x77 || response[1] != 0x00) {
if (n != 2 || response[0] != UPLOAD_EXIT_RESPONSE || response[1] != 0x00) {
ERROR (abstract->context, "Unexpected response packet.");
return DC_STATUS_PROTOCOL;
}
Expand All @@ -524,15 +590,16 @@ shearwater_common_rdbi (shearwater_common_device_t *device, unsigned int id, uns
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
unsigned char response[SZ_PACKET_MAX];

// Transfer the request.
unsigned int n = 0;
unsigned char request[] = {
RDBI_REQUEST,
(id >> 8) & 0xFF,
(id ) & 0xFF};
unsigned char response[SZ_PACKET];
status = shearwater_common_transfer (device, request, sizeof (request), response, sizeof (response), &n);
status = shearwater_common_transfer (device, request, sizeof (request), response, maxpacket, &n);
if (status != DC_STATUS_SUCCESS) {
return status;
}
Expand Down Expand Up @@ -577,22 +644,23 @@ shearwater_common_wdbi (shearwater_common_device_t *device, unsigned int id, con
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
unsigned char response[SZ_PACKET_MAX];

if (size + 3 > SZ_PACKET) {
if (size + 3 > maxpacket) {
return DC_STATUS_INVALIDARGS;
}

// Transfer the request.
unsigned int n = 0;
unsigned char request[SZ_PACKET] = {
unsigned char request[SZ_PACKET_MAX] = {
WDBI_REQUEST,
(id >> 8) & 0xFF,
(id ) & 0xFF};
if (size) {
memcpy (request + 3, data, size);
}
unsigned char response[SZ_PACKET];
status = shearwater_common_transfer (device, request, size + 3, response, sizeof (response), &n);
status = shearwater_common_transfer (device, request, size + 3, response, maxpacket, &n);
if (status != DC_STATUS_SUCCESS) {
return status;
}
Expand Down
4 changes: 3 additions & 1 deletion src/shearwater_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,19 @@ extern "C" {
#define PERDIX2 11
#define TERN 12
#define PEREGRINE_TX 13
#define PERDIX3 14

#define NSTEPS 10000
#define STEP(i,n) ((NSTEPS * (i) + (n) / 2) / (n))

typedef struct shearwater_common_device_t {
dc_device_t base;
dc_iostream_t *iostream;
unsigned int protocol;
} shearwater_common_device_t;

dc_status_t
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream);
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);

dc_status_t
shearwater_common_transfer (shearwater_common_device_t *device, const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize, unsigned int *actual);
Expand Down
4 changes: 2 additions & 2 deletions src/shearwater_petrel.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ str2num (unsigned char data[], unsigned int size, unsigned int offset)


dc_status_t
shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
shearwater_petrel_device_t *device = NULL;
Expand All @@ -98,7 +98,7 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iost
memset (device->fingerprint, 0, sizeof (device->fingerprint));

// Setup the device.
status = shearwater_common_setup (&device->base, context, iostream);
status = shearwater_common_setup (&device->base, context, iostream, model);
if (status != DC_STATUS_SUCCESS) {
goto error_free;
}
Expand Down
2 changes: 1 addition & 1 deletion src/shearwater_petrel.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extern "C" {
#endif /* __cplusplus */

dc_status_t
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);

dc_status_t
shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial);
Expand Down
Loading
Loading