Add BLE support for the Shearwater devices

The main difference with the serial communication is that the BLE
communication transmits each SLIP encoded data packet as one or more BLE
data packets. The BLE packets have an extra two byte header with the
total number of packets and the current packet number.
This commit is contained in:
Jef Driesen 2018-03-13 23:01:16 +01:00
parent 0978f8c0fa
commit 8f7abc5a2d
2 changed files with 95 additions and 53 deletions

View File

@ -284,11 +284,11 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
/* Shearwater Petrel */
{"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
{"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 3, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
{"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 3, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Nerd", DC_FAMILY_SHEARWATER_PETREL, 4, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
{"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 5, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_shearwater},
{"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 6, DC_TRANSPORT_NONE, dc_filter_shearwater},
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_NONE, dc_filter_shearwater},
{"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 5, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 6, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, 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 */

View File

@ -25,6 +25,7 @@
#include "shearwater_common.h"
#include "context-private.h"
#include "platform.h"
#include "array.h"
#define SZ_PACKET 254
@ -122,19 +123,33 @@ shearwater_common_decompress_xor (unsigned char *data, unsigned int size)
return 0;
}
static dc_status_t
shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned char data[], unsigned int size)
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
unsigned char buffer[32];
unsigned int nbytes = 0;
#if 0
// Send an initial END character to flush out any data that may have
// accumulated in the receiver due to line noise.
buffer[nbytes++] = END;
#endif
if (transport == DC_TRANSPORT_BLE) {
// Calculate the total number of bytes.
unsigned int count = 1;
for (unsigned int i = 0; i < size; ++i) {
unsigned char c = data[i];
if (c == END || c == ESC) {
count += 2;
} else {
count++;
}
}
// Calculate the total number of frames.
unsigned int nframes = (count + sizeof(buffer) - 1) / sizeof(buffer);
buffer[0] = nframes;
buffer[1] = 0;
nbytes = 2;
}
for (unsigned int i = 0; i < size; ++i) {
unsigned char c = data[i];
@ -151,7 +166,12 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
return status;
}
nbytes = 0;
if (transport == DC_TRANSPORT_BLE) {
buffer[1]++;
nbytes = 2;
} else {
nbytes = 0;
}
}
// Escape the character.
@ -173,7 +193,12 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
return status;
}
nbytes = 0;
if (transport == DC_TRANSPORT_BLE) {
buffer[1]++;
nbytes = 2;
} else {
nbytes = 0;
}
}
}
@ -195,70 +220,87 @@ static dc_status_t
shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char data[], unsigned int size, unsigned int *actual)
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
unsigned char buffer[256];
unsigned int escaped = 0;
unsigned int nbytes = 0;
// Get the packet size.
size_t packetsize = (transport == DC_TRANSPORT_BLE) ? sizeof(buffer) : 1;
// Read bytes until a complete packet has been received. If the
// buffer runs out of space, bytes are dropped. The caller can
// detect this condition because the return value will be larger
// than the supplied buffer size.
while (1) {
unsigned char c = 0;
// Get a single character to process.
status = dc_iostream_read (device->iostream, &c, 1, NULL);
size_t transferred = 0;
status = dc_iostream_read (device->iostream, buffer, packetsize, &transferred);
if (status != DC_STATUS_SUCCESS) {
ERROR (device->base.context, "Failed to receive the packet.");
return status;
}
if (c == END || c == ESC) {
if (escaped) {
// If the END or ESC characters are escaped, then we
// have a protocol violation, and an error is reported.
ERROR (device->base.context, "SLIP frame escaped the special character %02x.", c);
size_t offset = 0;
if (transport == DC_TRANSPORT_BLE) {
if (transferred < 2) {
ERROR (device->base.context, "Invalid packet length (" DC_PRINTF_SIZE ").", transferred);
return DC_STATUS_PROTOCOL;
}
if (c == END) {
// If it's an END character then we're done.
// As a minor optimization, empty packets are ignored. This
// is to avoid bothering the upper layers with all the empty
// packets generated by the duplicate END characters which
// are sent to try to detect line noise.
if (nbytes) {
goto done;
offset = 2;
}
for (size_t i = offset; i < transferred; ++i) {
unsigned char c = buffer[i];
if (c == END || c == ESC) {
if (escaped) {
// If the END or ESC characters are escaped, then we
// have a protocol violation, and an error is reported.
ERROR (device->base.context, "SLIP frame escaped the special character %02x.", c);
return DC_STATUS_PROTOCOL;
}
} else {
// If it's an ESC character, get another character and then
// figure out what to store in the packet based on that.
escaped = 1;
if (c == END) {
// If it's an END character then we're done.
// As a minor optimization, empty packets are ignored. This
// is to avoid bothering the upper layers with all the empty
// packets generated by the duplicate END characters which
// are sent to try to detect line noise.
if (nbytes) {
goto done;
}
} else {
// If it's an ESC character, get another character and then
// figure out what to store in the packet based on that.
escaped = 1;
}
continue;
}
continue;
}
if (escaped) {
// If it's not one of the two escaped characters, then we
// have a protocol violation. The best bet seems to be to
// leave the byte alone and just stuff it into the packet.
switch (c) {
case ESC_END:
c = END;
break;
case ESC_ESC:
c = ESC;
break;
default:
break;
}
if (escaped) {
// If it's not one of the two escaped characters, then we
// have a protocol violation. The best bet seems to be to
// leave the byte alone and just stuff it into the packet.
switch (c) {
case ESC_END:
c = END;
break;
case ESC_ESC:
c = ESC;
break;
default:
break;
escaped = 0;
}
escaped = 0;
if (nbytes < size)
data[nbytes] = c;
nbytes++;
}
if (nbytes < size)
data[nbytes] = c;
nbytes++;
}
done: