Integrate the HDLC stream in the eonsteel backend
This commit is contained in:
parent
cee9a2e926
commit
b0e77fd05f
@ -29,6 +29,7 @@
|
|||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "checksum.h"
|
#include "checksum.h"
|
||||||
|
#include "hdlc.h"
|
||||||
|
|
||||||
#define EONSTEEL 0
|
#define EONSTEEL 0
|
||||||
#define EONCORE 1
|
#define EONCORE 1
|
||||||
@ -80,14 +81,10 @@ struct directory_entry {
|
|||||||
#define MAXDATA_SIZE 2048
|
#define MAXDATA_SIZE 2048
|
||||||
#define CRC_SIZE 4
|
#define CRC_SIZE 4
|
||||||
|
|
||||||
// HDLC special characters
|
|
||||||
#define END 0x7E
|
|
||||||
#define ESC 0x7D
|
|
||||||
#define ESC_BIT 0x20
|
|
||||||
|
|
||||||
static dc_status_t suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
static dc_status_t suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||||
static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||||
static dc_status_t suunto_eonsteel_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
static dc_status_t suunto_eonsteel_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||||
|
static dc_status_t suunto_eonsteel_device_close (dc_device_t *abstract);
|
||||||
|
|
||||||
static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
|
static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
|
||||||
sizeof(suunto_eonsteel_device_t),
|
sizeof(suunto_eonsteel_device_t),
|
||||||
@ -98,7 +95,7 @@ static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
|
|||||||
NULL, /* dump */
|
NULL, /* dump */
|
||||||
suunto_eonsteel_device_foreach, /* foreach */
|
suunto_eonsteel_device_foreach, /* foreach */
|
||||||
suunto_eonsteel_device_timesync, /* timesync */
|
suunto_eonsteel_device_timesync, /* timesync */
|
||||||
NULL /* close */
|
suunto_eonsteel_device_close /* close */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char dive_directory[] = "0:/dives";
|
static const char dive_directory[] = "0:/dives";
|
||||||
@ -127,142 +124,6 @@ static struct directory_entry *alloc_dirent(int type, int len, const char *name)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
suunto_eonsteel_hdlc_write (suunto_eonsteel_device_t *device, const unsigned char data[], size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
unsigned char buffer[20];
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
// Start of the packet.
|
|
||||||
buffer[nbytes++] = END;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
unsigned char c = data[i];
|
|
||||||
|
|
||||||
if (c == END || c == ESC) {
|
|
||||||
// Append the escape character.
|
|
||||||
buffer[nbytes++] = ESC;
|
|
||||||
|
|
||||||
// Flush the buffer if necessary.
|
|
||||||
if (nbytes >= sizeof(buffer)) {
|
|
||||||
status = dc_iostream_write(device->iostream, buffer, nbytes, NULL);
|
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
|
||||||
ERROR(device->base.context, "Failed to send the packet.");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape the character.
|
|
||||||
c ^= ESC_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the character.
|
|
||||||
buffer[nbytes++] = c;
|
|
||||||
|
|
||||||
// Flush the buffer if necessary.
|
|
||||||
if (nbytes >= sizeof(buffer)) {
|
|
||||||
status = dc_iostream_write(device->iostream, buffer, nbytes, NULL);
|
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
|
||||||
ERROR(device->base.context, "Failed to send the packet.");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of the packet.
|
|
||||||
buffer[nbytes++] = END;
|
|
||||||
|
|
||||||
// Flush the buffer.
|
|
||||||
status = dc_iostream_write(device->iostream, buffer, nbytes, NULL);
|
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
|
||||||
ERROR(device->base.context, "Failed to send the packet.");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actual)
|
|
||||||
*actual = size;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
suunto_eonsteel_hdlc_read (suunto_eonsteel_device_t *device, unsigned char data[], size_t size, size_t *actual)
|
|
||||||
{
|
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
|
||||||
unsigned char buffer[20];
|
|
||||||
unsigned int initialized = 0;
|
|
||||||
unsigned int escaped = 0;
|
|
||||||
size_t nbytes = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// Read a single data packet.
|
|
||||||
size_t transferred = 0;
|
|
||||||
status = dc_iostream_read(device->iostream, buffer, sizeof(buffer), &transferred);
|
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
|
||||||
ERROR(device->base.context, "Failed to receive the packet.");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transferred; ++i) {
|
|
||||||
unsigned char c = buffer[i];
|
|
||||||
|
|
||||||
if (c == END) {
|
|
||||||
if (escaped) {
|
|
||||||
ERROR (device->base.context, "HDLC frame escaped the special character %02x.", c);
|
|
||||||
return DC_STATUS_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialized) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == ESC) {
|
|
||||||
if (escaped) {
|
|
||||||
ERROR (device->base.context, "HDLC frame escaped the special character %02x.", c);
|
|
||||||
return DC_STATUS_PROTOCOL;
|
|
||||||
}
|
|
||||||
escaped = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (escaped) {
|
|
||||||
c ^= ESC_BIT;
|
|
||||||
escaped = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes < size)
|
|
||||||
data[nbytes] = c;
|
|
||||||
nbytes++;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (nbytes > size) {
|
|
||||||
ERROR(device->base.context, "Insufficient buffer space available.");
|
|
||||||
return DC_STATUS_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actual)
|
|
||||||
*actual = nbytes;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a single 64-byte packet from the dive computer. This handles packet
|
* Get a single 64-byte packet from the dive computer. This handles packet
|
||||||
* logging and any obvious packet-level errors, and returns the payload of
|
* logging and any obvious packet-level errors, and returns the payload of
|
||||||
@ -324,7 +185,7 @@ suunto_eonsteel_receive_ble(suunto_eonsteel_device_t *device, unsigned char data
|
|||||||
unsigned char buffer[HEADER_SIZE + MAXDATA_SIZE + CRC_SIZE];
|
unsigned char buffer[HEADER_SIZE + MAXDATA_SIZE + CRC_SIZE];
|
||||||
size_t transferred = 0;
|
size_t transferred = 0;
|
||||||
|
|
||||||
rc = suunto_eonsteel_hdlc_read(device, buffer, sizeof(buffer), &transferred);
|
rc = dc_iostream_read(device->iostream, buffer, sizeof(buffer), &transferred);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR(device->base.context, "Failed to receive the packet.");
|
ERROR(device->base.context, "Failed to receive the packet.");
|
||||||
return rc;
|
return rc;
|
||||||
@ -401,7 +262,7 @@ suunto_eonsteel_send(suunto_eonsteel_device_t *device,
|
|||||||
array_uint32_le_set(buf + 14 + size, crc);
|
array_uint32_le_set(buf + 14 + size, crc);
|
||||||
|
|
||||||
if (dc_iostream_get_transport(device->iostream) == DC_TRANSPORT_BLE) {
|
if (dc_iostream_get_transport(device->iostream) == DC_TRANSPORT_BLE) {
|
||||||
rc = suunto_eonsteel_hdlc_write(device, buf + 2, size + HEADER_SIZE + CRC_SIZE, NULL);
|
rc = dc_iostream_write(device->iostream, buf + 2, size + HEADER_SIZE + CRC_SIZE, NULL);
|
||||||
} else {
|
} else {
|
||||||
rc = dc_iostream_write(device->iostream, buf, sizeof(buf) - CRC_SIZE, NULL);
|
rc = dc_iostream_write(device->iostream, buf, sizeof(buf) - CRC_SIZE, NULL);
|
||||||
}
|
}
|
||||||
@ -757,6 +618,7 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, dc_iostrea
|
|||||||
{
|
{
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
suunto_eonsteel_device_t *eon = NULL;
|
suunto_eonsteel_device_t *eon = NULL;
|
||||||
|
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||||
|
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -766,17 +628,26 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, dc_iostrea
|
|||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
|
|
||||||
// Set up the magic handshake fields
|
// Set up the magic handshake fields
|
||||||
eon->iostream = iostream;
|
|
||||||
eon->model = model;
|
eon->model = model;
|
||||||
eon->magic = INIT_MAGIC;
|
eon->magic = INIT_MAGIC;
|
||||||
eon->seq = INIT_SEQ;
|
eon->seq = INIT_SEQ;
|
||||||
memset (eon->version, 0, sizeof (eon->version));
|
memset (eon->version, 0, sizeof (eon->version));
|
||||||
memset (eon->fingerprint, 0, sizeof (eon->fingerprint));
|
memset (eon->fingerprint, 0, sizeof (eon->fingerprint));
|
||||||
|
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
status = dc_hdlc_open (&eon->iostream, context, iostream, 20, 20);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (context, "Failed to create the HDLC stream.");
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eon->iostream = iostream;
|
||||||
|
}
|
||||||
|
|
||||||
status = dc_iostream_set_timeout(eon->iostream, 5000);
|
status = dc_iostream_set_timeout(eon->iostream, 5000);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to set the timeout.");
|
ERROR (context, "Failed to set the timeout.");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char init[] = {0x02, 0x00, 0x2a, 0x00};
|
const unsigned char init[] = {0x02, 0x00, 0x2a, 0x00};
|
||||||
@ -784,18 +655,34 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, dc_iostrea
|
|||||||
init, sizeof(init), eon->version, sizeof(eon->version), NULL);
|
init, sizeof(init), eon->version, sizeof(eon->version), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR(context, "unable to initialize device");
|
ERROR(context, "unable to initialize device");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = (dc_device_t *) eon;
|
*out = (dc_device_t *) eon;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error_free_iostream:
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
dc_iostream_close (eon->iostream);
|
||||||
|
}
|
||||||
error_free:
|
error_free:
|
||||||
dc_device_deallocate ((dc_device_t *) eon);
|
dc_device_deallocate ((dc_device_t *) eon);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
suunto_eonsteel_device_close (dc_device_t *abstract)
|
||||||
|
{
|
||||||
|
suunto_eonsteel_device_t *device = (suunto_eonsteel_device_t *) abstract;
|
||||||
|
|
||||||
|
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||||
|
return dc_iostream_close (device->iostream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user