Add BLE support for the HW OSTC3 devices

The main difference with the serial communication is that the BLE
communication uses data packets (with a maximum size of 20 bytes)
instead of a continuous data stream.
This commit is contained in:
Jef Driesen 2018-03-11 13:50:24 +01:00
parent 3dcf93e26e
commit 0978f8c0fa
2 changed files with 115 additions and 66 deletions

View File

@ -252,18 +252,18 @@ static const dc_descriptor_t g_descriptors[] = {
{"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2, DC_TRANSPORT_SERIAL, NULL},
{"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3, DC_TRANSPORT_SERIAL, NULL},
{"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A, DC_TRANSPORT_SERIAL, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x1A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Plus", DC_FAMILY_HW_OSTC3, 0x1A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05, DC_TRANSPORT_SERIAL, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07, DC_TRANSPORT_SERIAL, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2 TR", DC_FAMILY_HW_OSTC3, 0x33, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
{"Heinrichs Weikamp", "OSTC 2 TR", DC_FAMILY_HW_OSTC3, 0x33, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw},
/* Cressi Edy */
{"Tusa", "IQ-700", DC_FAMILY_CRESSI_EDY, 0x05, DC_TRANSPORT_SERIAL, NULL},
{"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0x08, DC_TRANSPORT_SERIAL, NULL},

View File

@ -96,6 +96,9 @@ typedef struct hw_ostc3_device_t {
unsigned int model;
unsigned char fingerprint[5];
hw_ostc3_state_t state;
unsigned char cache[20];
unsigned int available;
unsigned int offset;
} hw_ostc3_device_t;
typedef struct hw_ostc3_logbook_t {
@ -174,6 +177,89 @@ hw_ostc3_strncpy (unsigned char *data, unsigned int size, const char *text)
return 0;
}
static dc_status_t
hw_ostc3_read (hw_ostc3_device_t *device, dc_event_progress_t *progress, unsigned char data[], size_t size)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
size_t nbytes = 0;
while (nbytes < size) {
if (transport == DC_TRANSPORT_BLE) {
if (device->available == 0) {
// Read a packet into the cache.
size_t len = 0;
rc = dc_iostream_read (device->iostream, device->cache, sizeof(device->cache), &len);
if (rc != DC_STATUS_SUCCESS)
return rc;
device->available = len;
device->offset = 0;
}
}
// Set the minimum packet size.
size_t length = (transport == DC_TRANSPORT_BLE) ? device->available : 1024;
// Limit the packet size to the total size.
if (nbytes + length > size)
length = size - nbytes;
if (transport == DC_TRANSPORT_BLE) {
// Copy the data from the cached packet.
memcpy (data + nbytes, device->cache + device->offset, length);
device->available -= length;
device->offset += length;
} else {
// Read the packet.
rc = dc_iostream_write (device->iostream, data + nbytes, length, NULL);
if (rc != DC_STATUS_SUCCESS)
return rc;
}
// Update and emit a progress event.
if (progress) {
progress->current += length;
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
}
nbytes += length;
}
return rc;
}
static dc_status_t
hw_ostc3_write (hw_ostc3_device_t *device, dc_event_progress_t *progress, const unsigned char data[], size_t size)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
size_t nbytes = 0;
while (nbytes < size) {
// Set the maximum packet size.
size_t length = (transport == DC_TRANSPORT_BLE) ? sizeof(device->cache) : 64;
// Limit the packet size to the total size.
if (nbytes + length > size)
length = size - nbytes;
// Write the packet.
rc = dc_iostream_write (device->iostream, data + nbytes, length, NULL);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Update and emit a progress event.
if (progress) {
progress->current += length;
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
}
nbytes += length;
}
return rc;
}
static dc_status_t
hw_ostc3_transfer (hw_ostc3_device_t *device,
@ -196,7 +282,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
// Send the command.
unsigned char command[1] = {cmd};
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
status = hw_ostc3_write (device, NULL, command, sizeof (command));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command.");
return status;
@ -204,7 +290,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
// Read the echo.
unsigned char echo[1] = {0};
status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL);
status = hw_ostc3_read (device, NULL, echo, sizeof (echo));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo.");
return status;
@ -223,68 +309,28 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
if (input) {
// Send the input data packet.
unsigned int nbytes = 0;
while (nbytes < isize) {
// Set the minimum packet size.
unsigned int len = 64;
// Limit the packet size to the total size.
if (nbytes + len > isize)
len = isize - nbytes;
// Write the packet.
status = dc_iostream_write (device->iostream, input + nbytes, len, NULL);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet.");
return status;
}
// Update and emit a progress event.
if (progress) {
progress->current += len;
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
}
nbytes += len;
status = hw_ostc3_write (device, progress, input, isize);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet.");
return status;
}
}
if (output) {
unsigned int nbytes = 0;
while (nbytes < osize) {
// Set the minimum packet size.
unsigned int len = 1024;
// Increase the packet size if more data is immediately available.
size_t available = 0;
status = dc_iostream_get_available (device->iostream, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available;
// Limit the packet size to the total size.
if (nbytes + len > osize)
len = osize - nbytes;
// Read the packet.
status = dc_iostream_read (device->iostream, output + nbytes, len, NULL);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer.");
return status;
}
// Update and emit a progress event.
if (progress) {
progress->current += len;
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
}
nbytes += len;
// Read the ouput data packet.
status = hw_ostc3_read (device, progress, output, osize);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer.");
return status;
}
}
if (delay) {
unsigned int count = delay / 100;
for (unsigned int i = 0; i < count; ++i) {
if (device->available)
break;
size_t available = 0;
status = dc_iostream_get_available (device->iostream, &available);
if (status == DC_STATUS_SUCCESS && available > 0)
@ -297,7 +343,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
if (cmd != EXIT) {
// Read the ready byte.
unsigned char answer[1] = {0};
status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL);
status = hw_ostc3_read (device, NULL, answer, sizeof (answer));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the ready byte.");
return status;
@ -336,6 +382,9 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
device->feature = 0;
device->model = 0;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
memset (device->cache, 0, sizeof (device->cache));
device->available = 0;
device->offset = 0;
// Set the serial communication protocol (115200 8N1).
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
@ -424,7 +473,7 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
unsigned char output[5];
// We cant use hw_ostc3_transfer here, due to the different echos
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
status = hw_ostc3_write (device, NULL, command, sizeof (command));
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to send the command.");
return status;
@ -434,7 +483,7 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
dc_iostream_sleep (device->iostream, 100);
// Read the response
status = dc_iostream_read (device->iostream, output, sizeof (output), NULL);
status = hw_ostc3_read (device, NULL, output, sizeof (output));
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to receive the echo.");
return status;