From bdbe95f221b788c754933f6e49c4292bf4c40e18 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 3 Mar 2015 21:33:32 +0100 Subject: [PATCH 1/2] Detect and report unsupported commands. When trying to send an unsupported command, the ostc will simply ignore the command. Instead of echoing the command byte back, the ostc will immediately send the ready byte, to indicate it's ready to receive the next command. We can use this to detect unsupported commands, because the ready byte is a reserved value and guaranteed to never be a valid command byte. Normally we don't send invalid commands. But newer firmware version can always introduce new commands to support new features. To maintain backwards compatibility with older firmware versions, it's important to be able to detect unsupported commands and provide a fallback. --- src/hw_ostc3.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a59fceb..f280eaf 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -151,6 +151,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; + // Get the correct ready byte for the current state. + const unsigned char ready = (device->state == SERVICE ? S_READY : READY); + // Send the command. unsigned char command[1] = {cmd}; int n = serial_write (device->port, command, sizeof (command)); @@ -169,8 +172,13 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Verify the echo. if (memcmp (echo, command, sizeof (command)) != 0) { - ERROR (abstract->context, "Unexpected echo."); - return DC_STATUS_PROTOCOL; + if (echo[0] == ready) { + ERROR (abstract->context, "Unsupported command."); + return DC_STATUS_UNSUPPORTED; + } else { + ERROR (abstract->context, "Unexpected echo."); + return DC_STATUS_PROTOCOL; + } } if (input) { @@ -216,16 +224,15 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, if (cmd != EXIT) { // Read the ready byte. - unsigned char ready[1] = {0}; - unsigned char expected = (device->state == SERVICE ? S_READY : READY); - n = serial_read (device->port, ready, sizeof (ready)); - if (n != sizeof (ready)) { + unsigned char answer[1] = {0}; + n = serial_read (device->port, answer, sizeof (answer)); + if (n != sizeof (answer)) { ERROR (abstract->context, "Failed to receive the ready byte."); return EXITCODE (n); } // Verify the ready byte. - if (ready[0] != expected) { + if (answer[0] != ready) { ERROR (abstract->context, "Unexpected ready byte."); return DC_STATUS_PROTOCOL; } From 3b264d9cfd41324262f296f2d537aaeb4855609e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 3 Mar 2015 19:20:36 +0100 Subject: [PATCH 2/2] Add support for the new hardware descriptor. The latest firmware v1.75 introduced a new hardware descriptor byte to identify the different models based on their hardware features. This new hardware descriptor is now used as the libdivecomputer model number. For older firmware versions, which do not support the descriptor yet, there is an automatic fallback to the previous method based on the serial number. --- include/libdivecomputer/hw_ostc3.h | 3 ++ src/descriptor.c | 6 ++-- src/hw_ostc3.c | 50 +++++++++++++++++++++++++++--- src/libdivecomputer.symbols | 1 + 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index bc56a9d..c60dc63 100644 --- a/include/libdivecomputer/hw_ostc3.h +++ b/include/libdivecomputer/hw_ostc3.h @@ -40,6 +40,9 @@ hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, const char *n dc_status_t hw_ostc3_device_version (dc_device_t *device, unsigned char data[], unsigned int size); +dc_status_t +hw_ostc3_device_hardware (dc_device_t *device, unsigned char data[], unsigned int size); + dc_status_t hw_ostc3_device_clock (dc_device_t *device, const dc_datetime_t *datetime); diff --git a/src/descriptor.c b/src/descriptor.c index c474e35..cf989e2 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -210,9 +210,9 @@ static const dc_descriptor_t g_descriptors[] = { {"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2}, {"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3}, {"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0}, - {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0}, - {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0}, - {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 1}, + {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A}, + {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05}, + {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12}, /* Cressi Edy */ {"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0}, /* Cressi Leonardo */ diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index f280eaf..a5f96bf 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -46,6 +46,7 @@ #define SZ_DISPLAY 16 #define SZ_CUSTOMTEXT 60 #define SZ_VERSION (SZ_CUSTOMTEXT + 4) +#define SZ_HARDWARE 1 #define SZ_MEMORY 0x200000 #define SZ_CONFIG 4 #define SZ_FIRMWARE 0x01E000 // 120KB @@ -66,6 +67,7 @@ #define CUSTOMTEXT 0x63 #define DIVE 0x66 #define IDENTITY 0x69 +#define HARDWARE 0x6A #define DISPLAY 0x6E #define READ 0x72 #define WRITE 0x77 @@ -73,6 +75,10 @@ #define INIT 0xBB #define EXIT 0xFF +#define OSTC3 0x0A +#define SPORT 0x12 +#define CR 0x05 + typedef enum hw_ostc3_state_t { OPEN, DOWNLOAD, @@ -461,6 +467,30 @@ hw_ostc3_device_version (dc_device_t *abstract, unsigned char data[], unsigned i } +dc_status_t +hw_ostc3_device_hardware (dc_device_t *abstract, unsigned char data[], unsigned int size) +{ + hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; + + if (!ISINSTANCE (abstract)) + return DC_STATUS_INVALIDARGS; + + if (size != SZ_HARDWARE) + return DC_STATUS_INVALIDARGS; + + dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD); + if (rc != DC_STATUS_SUCCESS) + return rc; + + // Send the command. + rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, data, size); + if (rc != DC_STATUS_SUCCESS) + return rc; + + return DC_STATUS_SUCCESS; +} + + static dc_status_t hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) { @@ -483,14 +513,26 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi return rc; } + // Download the hardware descriptor. + unsigned char hardware[SZ_HARDWARE] = {0}; + rc = hw_ostc3_device_hardware (abstract, hardware, sizeof (hardware)); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR (abstract->context, "Failed to read the hardware descriptor."); + return rc; + } + // Emit a device info event. dc_event_devinfo_t devinfo; devinfo.firmware = array_uint16_be (id + 2); devinfo.serial = array_uint16_le (id + 0); - if (devinfo.serial > 10000) - devinfo.model = 1; // OSTC Sport - else - devinfo.model = 0; // OSTC3 + devinfo.model = hardware[0]; + if (devinfo.model == 0) { + // Fallback to the serial number. + if (devinfo.serial > 10000) + devinfo.model = SPORT; + else + devinfo.model = OSTC3; + } device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate memory. diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index f27f6fd..732bb85 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -155,6 +155,7 @@ hw_frog_device_display hw_frog_device_customtext hw_ostc3_device_open hw_ostc3_device_version +hw_ostc3_device_hardware hw_ostc3_device_clock hw_ostc3_device_display hw_ostc3_device_customtext