From 8f7abc5a2d3ca5099c6e261a42ece1b145cac1e3 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 13 Mar 2018 23:01:16 +0100 Subject: [PATCH] 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. --- src/descriptor.c | 8 +-- src/shearwater_common.c | 140 ++++++++++++++++++++++++++-------------- 2 files changed, 95 insertions(+), 53 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 6a31c29..0d0ed66 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -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 */ diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 130ff62..a7f67f6 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -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: