Skip to content

Commit ffb7cab

Browse files
authored
Merge pull request #118 from mikeller/add_perdix_3
Add Support for the Shearwater Perdix 3.
2 parents 8717731 + ab18ece commit ffb7cab

7 files changed

Lines changed: 113 additions & 41 deletions

File tree

src/descriptor.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ static const dc_descriptor_t g_descriptors[] = {
392392
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
393393
{"Shearwater", "Tern TX", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
394394
{"Shearwater", "Peregrine TX", DC_FAMILY_SHEARWATER_PETREL, 13, DC_TRANSPORT_BLE, dc_filter_shearwater},
395+
{"Shearwater", "Perdix 3", DC_FAMILY_SHEARWATER_PETREL, 14, DC_TRANSPORT_BLE, dc_filter_shearwater},
395396
/* Dive Rite NiTek Q */
396397
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
397398
/* Citizen Hyper Aqualand */
@@ -764,6 +765,7 @@ dc_filter_shearwater (const dc_descriptor_t *descriptor, dc_transport_t transpor
764765
"NERD 2",
765766
"Perdix",
766767
"Perdix 2",
768+
"Perdix 3",
767769
"Teric",
768770
"Peregrine",
769771
"Peregrine TX",

src/device.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
210210
rc = shearwater_predator_device_open (&device, context, iostream);
211211
break;
212212
case DC_FAMILY_SHEARWATER_PETREL:
213-
rc = shearwater_petrel_device_open (&device, context, iostream);
213+
rc = shearwater_petrel_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
214214
break;
215215
case DC_FAMILY_DIVERITE_NITEKQ:
216216
rc = diverite_nitekq_device_open (&device, context, iostream);

src/shearwater_common.c

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,22 @@
2828
#include "platform.h"
2929
#include "array.h"
3030

31-
#define SZ_PACKET 254
31+
#define BLE_MTU_MIN 20
32+
#define BLE_MTU_MAX 514
33+
34+
// Protocol variants.
35+
#define V1 1
36+
#define V2 2
37+
38+
// Maximum packet payload size.
39+
// The V1 protocol uses an 8 bit length field, while the V2 protocol
40+
// uses a 16 bit length field. Theoretically the V2 maximum size is
41+
// 2^16-1 bytes, but the largest observed value is much smaller (0x0202
42+
// for the manifest and 0x0902 for the dive). Allow for an extra margin
43+
// for future expansions.
44+
#define SZ_PACKET_V1 254
45+
#define SZ_PACKET_V2 4096
46+
#define SZ_PACKET_MAX SZ_PACKET_V2
3247

3348
// SLIP special character codes
3449
#define END 0xC0
@@ -42,10 +57,19 @@
4257
#define WDBI_REQUEST 0x2E
4358
#define WDBI_RESPONSE 0x6E
4459

60+
#define UPLOAD_INIT_REQUEST 0x35
61+
#define UPLOAD_INIT_RESPONSE 0x75
62+
63+
#define UPLOAD_DATA_REQUEST 0x36
64+
#define UPLOAD_DATA_RESPONSE 0x76
65+
66+
#define UPLOAD_EXIT_REQUEST 0x37
67+
#define UPLOAD_EXIT_RESPONSE 0x77
68+
4569
#define NAK 0x7F
4670

4771
dc_status_t
48-
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream)
72+
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
4973
{
5074
dc_status_t status = DC_STATUS_SUCCESS;
5175

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

96+
device->protocol = (model == PERDIX3) ? V2 : V1;
97+
7298
return DC_STATUS_SUCCESS;
7399
}
74100

@@ -136,10 +162,11 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
136162
{
137163
dc_status_t status = DC_STATUS_SUCCESS;
138164
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
139-
unsigned char buffer[32];
165+
const unsigned int header = transport == DC_TRANSPORT_BLE && device->protocol != V2;
166+
unsigned char buffer[BLE_MTU_MIN];
140167
unsigned int nbytes = 0;
141168

142-
if (transport == DC_TRANSPORT_BLE) {
169+
if (header) {
143170
// Calculate the total number of bytes.
144171
unsigned int count = 1;
145172
for (unsigned int i = 0; i < size; ++i) {
@@ -174,7 +201,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
174201
return status;
175202
}
176203

177-
if (transport == DC_TRANSPORT_BLE) {
204+
if (header) {
178205
buffer[1]++;
179206
nbytes = 2;
180207
} else {
@@ -201,7 +228,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
201228
return status;
202229
}
203230

204-
if (transport == DC_TRANSPORT_BLE) {
231+
if (header) {
205232
buffer[1]++;
206233
nbytes = 2;
207234
} else {
@@ -229,7 +256,8 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d
229256
{
230257
dc_status_t status = DC_STATUS_SUCCESS;
231258
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
232-
unsigned char buffer[256];
259+
const unsigned int header = transport == DC_TRANSPORT_BLE && device->protocol != V2;
260+
unsigned char buffer[BLE_MTU_MAX];
233261
unsigned int escaped = 0;
234262
unsigned int nbytes = 0;
235263

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

251279
size_t offset = 0;
252-
if (transport == DC_TRANSPORT_BLE) {
280+
if (header) {
253281
if (transferred < 2) {
254282
ERROR (device->base.context, "Invalid packet length (" DC_PRINTF_SIZE ").", transferred);
255283
return DC_STATUS_PROTOCOL;
@@ -330,10 +358,12 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
330358
{
331359
dc_status_t status = DC_STATUS_SUCCESS;
332360
dc_device_t *abstract = (dc_device_t *) device;
333-
unsigned char packet[SZ_PACKET + 4];
361+
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
362+
const unsigned int headerlen = (device->protocol == V2) ? 5 : 4;
363+
unsigned char packet[SZ_PACKET_MAX + 5];
334364
unsigned int n = 0;
335365

336-
if (isize > SZ_PACKET || osize > SZ_PACKET)
366+
if (isize > maxpacket || osize > maxpacket)
337367
return DC_STATUS_INVALIDARGS;
338368

339369
if (device_is_cancelled (abstract))
@@ -342,12 +372,19 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
342372
// Setup the request packet.
343373
packet[0] = 0xFF;
344374
packet[1] = 0x01;
345-
packet[2] = isize + 1;
346-
packet[3] = 0x00;
347-
memcpy (packet + 4, input, isize);
375+
if (device->protocol == V2) {
376+
// FF 01 00 [len_hi] [len_lo] <payload>
377+
packet[2] = 0x00;
378+
array_uint16_be_set (packet + 3, isize);
379+
} else {
380+
// FF 01 [len+1] 00 <payload>
381+
packet[2] = isize + 1;
382+
packet[3] = 0x00;
383+
}
384+
memcpy (packet + headerlen, input, isize);
348385

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

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

376414
// Validate the packet length.
377-
unsigned int length = packet[2];
378-
if (length < 1 || length - 1 + 4 != n || length - 1 > osize) {
415+
unsigned int length = 0;
416+
if (device->protocol == V2) {
417+
length = array_uint16_be (packet + 3);
418+
} else {
419+
length = packet[2];
420+
if (length < 1) {
421+
ERROR (abstract->context, "Invalid packet header.");
422+
return DC_STATUS_PROTOCOL;
423+
}
424+
425+
length -= 1;
426+
}
427+
if (length + headerlen != n || length > osize) {
379428
ERROR (abstract->context, "Invalid packet header.");
380429
return DC_STATUS_PROTOCOL;
381430
}
382431

383-
memcpy (output, packet + 4, length - 1);
432+
memcpy (output, packet + headerlen, length);
384433
if (actual)
385-
*actual = length - 1;
434+
*actual = length;
386435

387436
return DC_STATUS_SUCCESS;
388437
}
@@ -393,10 +442,12 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
393442
{
394443
dc_device_t *abstract = (dc_device_t *) device;
395444
dc_status_t rc = DC_STATUS_SUCCESS;
445+
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
446+
unsigned char response[SZ_PACKET_MAX];
396447
unsigned int n = 0;
397448

398449
unsigned char req_init[] = {
399-
0x35,
450+
UPLOAD_INIT_REQUEST,
400451
(compression ? 0x10 : 0x00),
401452
0x34,
402453
(address >> 24) & 0xFF,
@@ -406,9 +457,10 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
406457
(size >> 16) & 0xFF,
407458
(size >> 8) & 0xFF,
408459
(size ) & 0xFF};
409-
unsigned char req_block[] = {0x36, 0x00};
410-
unsigned char req_quit[] = {0x37};
411-
unsigned char response[SZ_PACKET];
460+
unsigned char req_block[] = {UPLOAD_DATA_REQUEST, 0x00, 0x00};
461+
unsigned char req_quit[] = {UPLOAD_EXIT_REQUEST};
462+
unsigned int req_block_len = (device->protocol == V2) ?
463+
sizeof(req_block) : sizeof(req_block) - 1;
412464

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

426478
// Transfer the init request.
427-
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, 3, &n);
479+
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, maxpacket, &n);
428480
if (rc != DC_STATUS_SUCCESS) {
429481
return rc;
430482
}
431483

432484
// Verify the init response.
433-
if (n != 3 || response[0] != 0x75 || response[1] != 0x10 || response[2] > SZ_PACKET) {
485+
if (n < 2 || response[0] != UPLOAD_INIT_RESPONSE) {
486+
ERROR (abstract->context, "Unexpected response packet.");
487+
return DC_STATUS_PROTOCOL;
488+
}
489+
490+
// Verify the init response length.
491+
unsigned int len = (response[1] & 0xF0) >> 4;
492+
if (n < len + 2 || len > 4) {
493+
ERROR (abstract->context, "Unexpected response packet.");
494+
return DC_STATUS_PROTOCOL;
495+
}
496+
497+
// Verify the maximum packet length.
498+
unsigned int maxlength = array_uint_be (response + 2, len);
499+
if (maxlength > maxpacket) {
434500
ERROR (abstract->context, "Unexpected response packet.");
435501
return DC_STATUS_PROTOCOL;
436502
}
@@ -448,13 +514,13 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
448514
while (nbytes < size && !done) {
449515
// Transfer the block request.
450516
req_block[1] = block;
451-
rc = shearwater_common_transfer (device, req_block, sizeof (req_block), response, sizeof (response), &n);
517+
rc = shearwater_common_transfer (device, req_block, req_block_len, response, maxpacket, &n);
452518
if (rc != DC_STATUS_SUCCESS) {
453519
return rc;
454520
}
455521

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

499565
// Transfer the quit request.
500-
rc = shearwater_common_transfer (device, req_quit, sizeof (req_quit), response, 2, &n);
566+
rc = shearwater_common_transfer (device, req_quit, sizeof (req_quit), response, maxpacket, &n);
501567
if (rc != DC_STATUS_SUCCESS) {
502568
return rc;
503569
}
504570

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

528596
// Transfer the request.
529597
unsigned int n = 0;
530598
unsigned char request[] = {
531599
RDBI_REQUEST,
532600
(id >> 8) & 0xFF,
533601
(id ) & 0xFF};
534-
unsigned char response[SZ_PACKET];
535-
status = shearwater_common_transfer (device, request, sizeof (request), response, sizeof (response), &n);
602+
status = shearwater_common_transfer (device, request, sizeof (request), response, maxpacket, &n);
536603
if (status != DC_STATUS_SUCCESS) {
537604
return status;
538605
}
@@ -577,22 +644,23 @@ shearwater_common_wdbi (shearwater_common_device_t *device, unsigned int id, con
577644
{
578645
dc_status_t status = DC_STATUS_SUCCESS;
579646
dc_device_t *abstract = (dc_device_t *) device;
647+
const unsigned int maxpacket = (device->protocol == V2) ? SZ_PACKET_V2 : SZ_PACKET_V1;
648+
unsigned char response[SZ_PACKET_MAX];
580649

581-
if (size + 3 > SZ_PACKET) {
650+
if (size + 3 > maxpacket) {
582651
return DC_STATUS_INVALIDARGS;
583652
}
584653

585654
// Transfer the request.
586655
unsigned int n = 0;
587-
unsigned char request[SZ_PACKET] = {
656+
unsigned char request[SZ_PACKET_MAX] = {
588657
WDBI_REQUEST,
589658
(id >> 8) & 0xFF,
590659
(id ) & 0xFF};
591660
if (size) {
592661
memcpy (request + 3, data, size);
593662
}
594-
unsigned char response[SZ_PACKET];
595-
status = shearwater_common_transfer (device, request, size + 3, response, sizeof (response), &n);
663+
status = shearwater_common_transfer (device, request, size + 3, response, maxpacket, &n);
596664
if (status != DC_STATUS_SUCCESS) {
597665
return status;
598666
}

src/shearwater_common.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,19 @@ extern "C" {
5959
#define PERDIX2 11
6060
#define TERN 12
6161
#define PEREGRINE_TX 13
62+
#define PERDIX3 14
6263

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

6667
typedef struct shearwater_common_device_t {
6768
dc_device_t base;
6869
dc_iostream_t *iostream;
70+
unsigned int protocol;
6971
} shearwater_common_device_t;
7072

7173
dc_status_t
72-
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream);
74+
shearwater_common_setup (shearwater_common_device_t *device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
7375

7476
dc_status_t
7577
shearwater_common_transfer (shearwater_common_device_t *device, const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize, unsigned int *actual);

src/shearwater_petrel.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ str2num (unsigned char data[], unsigned int size, unsigned int offset)
7979

8080

8181
dc_status_t
82-
shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
82+
shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
8383
{
8484
dc_status_t status = DC_STATUS_SUCCESS;
8585
shearwater_petrel_device_t *device = NULL;
@@ -98,7 +98,7 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, dc_iost
9898
memset (device->fingerprint, 0, sizeof (device->fingerprint));
9999

100100
// Setup the device.
101-
status = shearwater_common_setup (&device->base, context, iostream);
101+
status = shearwater_common_setup (&device->base, context, iostream, model);
102102
if (status != DC_STATUS_SUCCESS) {
103103
goto error_free;
104104
}

src/shearwater_petrel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extern "C" {
3232
#endif /* __cplusplus */
3333

3434
dc_status_t
35-
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
35+
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
3636

3737
dc_status_t
3838
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);

0 commit comments

Comments
 (0)