Add back Mares BlueLink Pro bluetooth support tweaks

The Mares BlueLink Pro BLE dongle is the beast from hell, and introduces
lots of extra slowdowns into the Mares communication protocol.

In particular, it turns out that we really can't send the command bytes,
then wait for the ACK byte, and then send the command argument data as a
separate packet.  Because of the delays that the dongle adds, the dive
computer will have given up on the command arguments by the time it sees
them.

At the same time we don't want to always pass the command and arguments
as one single packet in all situations, because at least the Mares
Matrix really seems to want that "wait for ACK before sending
arguments".  See commit 59bfb0f3189b ("Add support for the Mares
Matrix") for details.

So introduce a new "splitcommand" flag, which is set by default, but
gets disabled for the BLE transport case.

Also, because bluetooth is slow, we don't want to ask for big packets of
data.  It seems to cause a buffer overflow on the BlueLink Pro when the
serial data from the dive computer arrives faster than the bluetooth
data can be sent to the downloading side.

So when using the BLE transport, we also limit the packet size to 128
bytes in addition to disabling the command splitting.

With this, I can download hundreds of kB of data from the Mares Quad Air
successfully over BLE.  It's *slow*, but it works.

This is a re-application of commit 5be8c17ea1 ("Mares bluetooth support
tweaks"), with small changes for how the libdivecomputer IO interfaces
have changed in the meantime.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2018-09-27 10:36:00 -07:00
parent 3c25c78bae
commit 60c98fd75b

View File

@ -97,6 +97,7 @@ typedef struct mares_iconhd_device_t {
unsigned char cache[20];
unsigned int available;
unsigned int offset;
unsigned int splitcommand;
} mares_iconhd_device_t;
static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
@ -250,14 +251,17 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
unsigned int split_csize;
assert (csize >= 2);
if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED;
split_csize = device->splitcommand ? 2 : csize;
// Send the command header to the dive computer.
status = mares_iconhd_write (device, command, 2);
status = mares_iconhd_write (device, command, split_csize);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command.");
return status;
@ -277,9 +281,9 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
return DC_STATUS_PROTOCOL;
}
// Send the command payload to the dive computer.
if (csize > 2) {
status = mares_iconhd_write (device, command + 2, csize - 2);
// Send any remaining command payload to the dive computer.
if (csize > split_csize) {
status = mares_iconhd_write (device, command + split_csize, csize - split_csize);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command.");
return status;
@ -475,6 +479,15 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
device->available = 0;
device->offset = 0;
/*
* At least the Mares Matrix needs the command to be split into
* base and argument, with a wait for the ACK byte in between.
*
* See commit 59bfb0f3189b ("Add support for the Mares Matrix")
* for details.
*/
device->splitcommand = 1;
// Set the serial communication protocol (115200 8E1).
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (status != DC_STATUS_SUCCESS) {
@ -574,6 +587,26 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
break;
}
if (dc_iostream_get_transport(device->iostream) == DC_TRANSPORT_BLE) {
/*
* Don't ask for larger amounts of data with the BLE
* transport - it will fail. I suspect there is a buffer
* overflow in the BlueLink Pro dongle when bluetooth is
* slower than the serial protocol that the dongle talks to
* the dive computer.
*/
if (device->packetsize > 128)
device->packetsize = 128;
/*
* With BLE, don't wait for ACK before sending the arguments
* to a command.
*
* There is some timing issue that makes that take too long
* and causes the command to be aborted.
*/
device->splitcommand = 0;
}
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;