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
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
4771dc_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 }
0 commit comments