23
23
#include <stdlib.h> // malloc, free
24
24
#include <assert.h> // assert
25
25
26
+ #include <libdivecomputer/ble.h>
27
+
26
28
#include "cressi_goa.h"
27
29
#include "context-private.h"
28
30
#include "device-private.h"
36
38
#define CMD_LOGBOOK 0x21
37
39
#define CMD_DIVE 0x22
38
40
41
+ #define CMD_LOGBOOK_BLE 0x02
42
+ #define CMD_DIVE_BLE 0x03
43
+
39
44
#define HEADER 0xAA
40
45
#define TRAILER 0x55
41
46
#define END 0x04
@@ -77,6 +82,7 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
77
82
{
78
83
dc_status_t status = DC_STATUS_SUCCESS ;
79
84
dc_device_t * abstract = (dc_device_t * ) device ;
85
+ dc_transport_t transport = dc_iostream_get_transport (device -> iostream );
80
86
81
87
if (size > SZ_PACKET ) {
82
88
ERROR (abstract -> context , "Unexpected payload size (%u)." , size );
@@ -100,10 +106,15 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
100
106
101
107
// Wait a small amount of time before sending the command. Without
102
108
// this delay, the transfer will fail most of the time.
103
- dc_iostream_sleep (device -> iostream , 100 );
109
+ unsigned int delay = transport == DC_TRANSPORT_BLE ? 2000 : 100 ;
110
+ dc_iostream_sleep (device -> iostream , delay );
104
111
105
112
// Send the command to the device.
106
- status = dc_iostream_write (device -> iostream , packet , size + 8 , NULL );
113
+ if (transport == DC_TRANSPORT_BLE ) {
114
+ status = dc_iostream_write (device -> iostream , packet + 4 , size + 1 , NULL );
115
+ } else {
116
+ status = dc_iostream_write (device -> iostream , packet , size + 8 , NULL );
117
+ }
107
118
if (status != DC_STATUS_SUCCESS ) {
108
119
ERROR (abstract -> context , "Failed to send the command." );
109
120
return status ;
@@ -117,9 +128,18 @@ cressi_goa_device_receive (cressi_goa_device_t *device, unsigned char data[], un
117
128
{
118
129
dc_status_t status = DC_STATUS_SUCCESS ;
119
130
dc_device_t * abstract = (dc_device_t * ) device ;
131
+ dc_transport_t transport = dc_iostream_get_transport (device -> iostream );
120
132
121
133
unsigned char packet [SZ_PACKET + 8 ];
122
134
135
+ if (transport == DC_TRANSPORT_BLE ) {
136
+ if (size ) {
137
+ return DC_STATUS_INVALIDARGS ;
138
+ } else {
139
+ return DC_STATUS_SUCCESS ;
140
+ }
141
+ }
142
+
123
143
// Read the header of the data packet.
124
144
status = dc_iostream_read (device -> iostream , packet , 4 , NULL );
125
145
if (status != DC_STATUS_SUCCESS ) {
@@ -179,6 +199,7 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
179
199
{
180
200
dc_status_t status = DC_STATUS_SUCCESS ;
181
201
dc_device_t * abstract = (dc_device_t * ) device ;
202
+ dc_transport_t transport = dc_iostream_get_transport (device -> iostream );
182
203
183
204
const unsigned char ack [] = {ACK };
184
205
const unsigned int initial = progress ? progress -> current : 0 ;
@@ -193,27 +214,43 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
193
214
unsigned int size = 2 ;
194
215
unsigned int nbytes = 0 ;
195
216
while (nbytes < size ) {
196
- // Read the data packet.
197
217
unsigned char packet [3 + SZ_DATA + 2 ];
198
- status = dc_iostream_read (device -> iostream , packet , sizeof (packet ), NULL );
199
- if (status != DC_STATUS_SUCCESS ) {
200
- ERROR (abstract -> context , "Failed to receive the answer." );
201
- return status ;
202
- }
203
218
204
- // Verify the checksum of the packet.
205
- unsigned short crc = array_uint16_le (packet + sizeof (packet ) - 2 );
206
- unsigned short ccrc = checksum_crc16_ccitt (packet + 3 , sizeof (packet ) - 5 , 0x0000 , 0x0000 );
207
- if (crc != ccrc ) {
208
- ERROR (abstract -> context , "Unexpected answer checksum." );
209
- return DC_STATUS_PROTOCOL ;
210
- }
211
-
212
- // Send the ack byte to the device.
213
- status = dc_iostream_write (device -> iostream , ack , sizeof (ack ), NULL );
214
- if (status != DC_STATUS_SUCCESS ) {
215
- ERROR (abstract -> context , "Failed to send the ack byte." );
216
- return status ;
219
+ if (transport == DC_TRANSPORT_BLE ) {
220
+ // Read the data packet.
221
+ unsigned int packetsize = 0 ;
222
+ while (packetsize < SZ_DATA ) {
223
+ size_t len = 0 ;
224
+ status = dc_iostream_read (device -> iostream , packet + 3 + packetsize , SZ_DATA - packetsize , & len );
225
+ if (status != DC_STATUS_SUCCESS ) {
226
+ ERROR (abstract -> context , "Failed to receive the answer." );
227
+ return status ;
228
+ }
229
+
230
+ packetsize += len ;
231
+ }
232
+ } else {
233
+ // Read the data packet.
234
+ status = dc_iostream_read (device -> iostream , packet , sizeof (packet ), NULL );
235
+ if (status != DC_STATUS_SUCCESS ) {
236
+ ERROR (abstract -> context , "Failed to receive the answer." );
237
+ return status ;
238
+ }
239
+
240
+ // Verify the checksum of the packet.
241
+ unsigned short crc = array_uint16_le (packet + sizeof (packet ) - 2 );
242
+ unsigned short ccrc = checksum_crc16_ccitt (packet + 3 , sizeof (packet ) - 5 , 0x0000 , 0x0000 );
243
+ if (crc != ccrc ) {
244
+ ERROR (abstract -> context , "Unexpected answer checksum." );
245
+ return DC_STATUS_PROTOCOL ;
246
+ }
247
+
248
+ // Send the ack byte to the device.
249
+ status = dc_iostream_write (device -> iostream , ack , sizeof (ack ), NULL );
250
+ if (status != DC_STATUS_SUCCESS ) {
251
+ ERROR (abstract -> context , "Failed to send the ack byte." );
252
+ return status ;
253
+ }
217
254
}
218
255
219
256
// Get the total size from the first data packet.
@@ -243,25 +280,45 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
243
280
}
244
281
}
245
282
246
- // Read the end byte.
247
- unsigned char end = 0 ;
248
- status = dc_iostream_read (device -> iostream , & end , 1 , NULL );
249
- if (status != DC_STATUS_SUCCESS ) {
250
- ERROR (abstract -> context , "Failed to receive the end byte." );
251
- return status ;
252
- }
283
+ if (transport == DC_TRANSPORT_BLE ) {
284
+ // Read the end bytes.
285
+ unsigned char end [16 ] = {0 };
286
+ size_t len = 0 ;
287
+ status = dc_iostream_read (device -> iostream , end , sizeof (end ), & len );
288
+ if (status != DC_STATUS_SUCCESS ) {
289
+ ERROR (abstract -> context , "Failed to receive the end bytes." );
290
+ return status ;
291
+ }
253
292
254
- // Verify the end byte.
255
- if (end != END ) {
256
- ERROR (abstract -> context , "Unexpected end byte (%02x)." , end );
257
- return DC_STATUS_PROTOCOL ;
258
- }
293
+ // Verify the end bytes ("EOT xmodem").
294
+ const unsigned char validate [16 ] = {
295
+ 0x45 , 0x4F , 0x54 , 0x20 , 0x78 , 0x6D , 0x6F , 0x64 ,
296
+ 0x65 , 0x6D , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
297
+ if (memcmp (end , validate , sizeof (validate )) != 0 ) {
298
+ ERROR (abstract -> context , "Unexpected end bytes." );
299
+ return DC_STATUS_PROTOCOL ;
300
+ }
301
+ } else {
302
+ // Read the end byte.
303
+ unsigned char end = 0 ;
304
+ status = dc_iostream_read (device -> iostream , & end , 1 , NULL );
305
+ if (status != DC_STATUS_SUCCESS ) {
306
+ ERROR (abstract -> context , "Failed to receive the end byte." );
307
+ return status ;
308
+ }
259
309
260
- // Send the ack byte to the device.
261
- status = dc_iostream_write (device -> iostream , ack , sizeof (ack ), NULL );
262
- if (status != DC_STATUS_SUCCESS ) {
263
- ERROR (abstract -> context , "Failed to send the ack byte." );
264
- return status ;
310
+ // Verify the end byte.
311
+ if (end != END ) {
312
+ ERROR (abstract -> context , "Unexpected end byte (%02x)." , end );
313
+ return DC_STATUS_PROTOCOL ;
314
+ }
315
+
316
+ // Send the ack byte to the device.
317
+ status = dc_iostream_write (device -> iostream , ack , sizeof (ack ), NULL );
318
+ if (status != DC_STATUS_SUCCESS ) {
319
+ ERROR (abstract -> context , "Failed to send the ack byte." );
320
+ return status ;
321
+ }
265
322
}
266
323
267
324
return status ;
@@ -328,8 +385,10 @@ cressi_goa_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t
328
385
goto error_free ;
329
386
}
330
387
331
- // Set the timeout for receiving data (3000 ms).
332
- status = dc_iostream_set_timeout (device -> iostream , 3000 );
388
+ // Set the timeout for receiving data (3000 - 5000 ms).
389
+ dc_transport_t transport = dc_iostream_get_transport (device -> iostream );
390
+ int timeout = transport == DC_TRANSPORT_BLE ? 5000 : 3000 ;
391
+ status = dc_iostream_set_timeout (device -> iostream , timeout );
333
392
if (status != DC_STATUS_SUCCESS ) {
334
393
ERROR (context , "Failed to set the timeout." );
335
394
goto error_free ;
@@ -382,6 +441,7 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
382
441
{
383
442
dc_status_t status = DC_STATUS_SUCCESS ;
384
443
cressi_goa_device_t * device = (cressi_goa_device_t * ) abstract ;
444
+ dc_transport_t transport = dc_iostream_get_transport (device -> iostream );
385
445
dc_buffer_t * logbook = NULL ;
386
446
dc_buffer_t * dive = NULL ;
387
447
@@ -391,10 +451,49 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
391
451
392
452
// Read the version information.
393
453
unsigned char id [9 ] = {0 };
394
- status = cressi_goa_device_transfer (device , CMD_VERSION , NULL , 0 , id , sizeof (id ), NULL , NULL );
395
- if (status != DC_STATUS_SUCCESS ) {
396
- ERROR (abstract -> context , "Failed to read the version information." );
397
- goto error_exit ;
454
+ if (transport == DC_TRANSPORT_BLE ) {
455
+ /*
456
+ * With the BLE communication, there is no variant of the CMD_VERSION
457
+ * command available. The corresponding information must be obtained by
458
+ * reading some secondary characteristics instead:
459
+ * 6E400003-B5A3-F393-E0A9-E50E24DC10B8 - 5 bytes
460
+ * 6E400004-B5A3-F393-E0A9-E50E24DC10B8 - 2 bytes
461
+ * 6E400005-B5A3-F393-E0A9-E50E24DC10B8 - 2 bytes
462
+ */
463
+ const dc_ble_uuid_t characteristics [] = {
464
+ {0x6E , 0x40 , 0x00 , 0x03 , 0xB5 , 0xA3 , 0xF3 , 0x93 , 0xE0 , 0xA9 , 0xE5 , 0x0E , 0x24 , 0xDC , 0x10 , 0xB8 },
465
+ {0x6E , 0x40 , 0x00 , 0x04 , 0xB5 , 0xA3 , 0xF3 , 0x93 , 0xE0 , 0xA9 , 0xE5 , 0x0E , 0x24 , 0xDC , 0x10 , 0xB8 },
466
+ {0x6E , 0x40 , 0x00 , 0x05 , 0xB5 , 0xA3 , 0xF3 , 0x93 , 0xE0 , 0xA9 , 0xE5 , 0x0E , 0x24 , 0xDC , 0x10 , 0xB8 },
467
+ };
468
+ const size_t sizes [] = {5 , 2 , 2 };
469
+
470
+ unsigned int offset = 0 ;
471
+ for (size_t i = 0 ; i < C_ARRAY_SIZE (characteristics ); ++ i ) {
472
+ unsigned char request [sizeof (dc_ble_uuid_t ) + 5 ] = {0 };
473
+
474
+ // Setup the request.
475
+ memcpy (request , characteristics [i ], sizeof (dc_ble_uuid_t ));
476
+ memset (request + sizeof (dc_ble_uuid_t ), 0 , sizes [i ]);
477
+
478
+ // Read the characteristic.
479
+ status = dc_iostream_ioctl (device -> iostream , DC_IOCTL_BLE_CHARACTERISTIC_READ , request , sizeof (dc_ble_uuid_t ) + sizes [i ]);
480
+ if (status != DC_STATUS_SUCCESS ) {
481
+ char uuidstr [DC_BLE_UUID_SIZE ] = {0 };
482
+ ERROR (abstract -> context , "Failed to read the characteristic '%s'." ,
483
+ dc_ble_uuid2str (characteristics [i ], uuidstr , sizeof (uuidstr )));
484
+ goto error_exit ;
485
+ }
486
+
487
+ // Copy the payload data.
488
+ memcpy (id + offset , request + sizeof (dc_ble_uuid_t ), sizes [i ]);
489
+ offset += sizes [i ];
490
+ }
491
+ } else {
492
+ status = cressi_goa_device_transfer (device , CMD_VERSION , NULL , 0 , id , sizeof (id ), NULL , NULL );
493
+ if (status != DC_STATUS_SUCCESS ) {
494
+ ERROR (abstract -> context , "Failed to read the version information." );
495
+ goto error_exit ;
496
+ }
398
497
}
399
498
400
499
// Emit a vendor event.
@@ -419,7 +518,12 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
419
518
}
420
519
421
520
// Read the logbook data.
422
- status = cressi_goa_device_transfer (device , CMD_LOGBOOK , NULL , 0 , NULL , 0 , logbook , & progress );
521
+ if (transport == DC_TRANSPORT_BLE ) {
522
+ unsigned char args [] = {0x00 };
523
+ status = cressi_goa_device_transfer (device , CMD_LOGBOOK_BLE , args , sizeof (args ), NULL , 0 , logbook , & progress );
524
+ } else {
525
+ status = cressi_goa_device_transfer (device , CMD_LOGBOOK , NULL , 0 , NULL , 0 , logbook , & progress );
526
+ }
423
527
if (status != DC_STATUS_SUCCESS ) {
424
528
ERROR (abstract -> context , "Failed to read the logbook data." );
425
529
goto error_free_logbook ;
@@ -467,7 +571,14 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
467
571
offset -= SZ_HEADER ;
468
572
469
573
// Read the dive data.
470
- status = cressi_goa_device_transfer (device , CMD_DIVE , logbook_data + offset , 2 , NULL , 0 , dive , & progress );
574
+ if (transport == DC_TRANSPORT_BLE ) {
575
+ unsigned char number [2 ] = {
576
+ logbook_data [offset + 1 ],
577
+ logbook_data [offset + 0 ]};
578
+ status = cressi_goa_device_transfer (device , CMD_DIVE_BLE , number , 2 , NULL , 0 , dive , & progress );
579
+ } else {
580
+ status = cressi_goa_device_transfer (device , CMD_DIVE , logbook_data + offset , 2 , NULL , 0 , dive , & progress );
581
+ }
471
582
if (status != DC_STATUS_SUCCESS ) {
472
583
ERROR (abstract -> context , "Failed to read the dive data." );
473
584
goto error_free_dive ;
0 commit comments