<div dir="ltr"><div>Cressi Leonardo computers behave extremely unreliable if the dump is requested right after the connection establishment.</div><div>The computer mostly sends nothing or sends trash, so official Cressi software uses request of small device memory part as a ping until device become stable.<br>And DTR flag should be reset before each request, or device wouldn't send any data in response.<br></div>This patch fixes <a href="https://github.com/Subsurface-divelog/subsurface/issues/391">https://github.com/Subsurface-divelog/subsurface/issues/391</a> and probably all previous mentions of Leonardo problems.<br><div><br>Signed-off-by: Vsevolod Velichko <<a href="mailto:torkvemada@sorokdva.net">torkvemada@sorokdva.net</a>><br>---<br> src/cressi_leonardo.c | 133 +++++++++++++++++++++++++++++++++-----------------<br> 1 file changed, 89 insertions(+), 44 deletions(-)<br><br>diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c<br>index f21a223..14db35f 100644<br>--- a/src/cressi_leonardo.c<br>+++ b/src/cressi_leonardo.c<br>@@ -44,7 +44,10 @@<br> #define RB_PROFILE_END   SZ_MEMORY<br> #define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)<br> <br>-#define MAXRETRIES 4<br>+#define PING_ADDRESS 0x1000<br>+#define PING_LENGTH 19<br>+<br>+#define MAXRETRIES 20<br> #define PACKETSIZE 32<br> <br> typedef struct cressi_leonardo_device_t {<br>@@ -74,6 +77,9 @@ static const dc_device_vtable_t cressi_leonardo_device_vtable = {<br> static dc_status_t<br> cressi_leonardo_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);<br> <br>+static dc_status_t<br>+cressi_leonardo_transfer_prepare (cressi_leonardo_device_t *device, dc_context_t *context);<br>+<br> static void<br> cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned char ascii[], unsigned int asize)<br> {<br>@@ -105,6 +111,13 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co<br>     if (device_is_cancelled (abstract))<br>         return DC_STATUS_CANCELLED;<br> <br>+    // Prepare device for writing.<br>+    status = cressi_leonardo_transfer_prepare (device, abstract->context);<br>+    if (status != DC_STATUS_SUCCESS) {<br>+        ERROR (abstract->context, "Failed to prepare device for transfer.");<br>+        return status;<br>+    }<br>+<br>     // Send the command to the device.<br>     status = dc_serial_write (device->port, command, csize, NULL);<br>     if (status != DC_STATUS_SUCCESS) {<br>@@ -141,6 +154,37 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co<br> }<br> <br> static dc_status_t<br>+cressi_leonardo_transfer_prepare (cressi_leonardo_device_t *device, dc_context_t *context)<br>+{<br>+    // Set the RTS line.<br>+    dc_status_t status = dc_serial_set_rts (device->port, 1);<br>+    if (status != DC_STATUS_SUCCESS) {<br>+        ERROR (context, "Failed to set the RTS line.");<br>+        return status;<br>+    }<br>+<br>+    // Set the DTR line.<br>+    status = dc_serial_set_dtr (device->port, 1);<br>+    if (status != DC_STATUS_SUCCESS) {<br>+        ERROR (context, "Failed to set the DTR line.");<br>+        return status;<br>+    }<br>+<br>+    dc_serial_sleep (device->port, 200);<br>+<br>+    // Clear the DTR line.<br>+    status = dc_serial_set_dtr (device->port, 0);<br>+    if (status != DC_STATUS_SUCCESS) {<br>+        ERROR (context, "Failed to clear the DTR line.");<br>+        return status;<br>+    }<br>+<br>+    dc_serial_sleep (device->port, 100);<br>+    dc_serial_purge (device->port, DC_DIRECTION_ALL);<br>+    return status;<br>+}<br>+<br>+static dc_status_t<br> cressi_leonardo_transfer (cressi_leonardo_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)<br> {<br>     unsigned int nretries = 0;<br>@@ -197,39 +241,13 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha<br>         goto error_close;<br>     }<br> <br>-    // Set the timeout for receiving data (1000 ms).<br>-    status = dc_serial_set_timeout (device->port, 1000);<br>+    // Set the timeout for receiving data (3000 ms).<br>+    status = dc_serial_set_timeout (device->port, 3000);<br>     if (status != DC_STATUS_SUCCESS) {<br>         ERROR (context, "Failed to set the timeout.");<br>         goto error_close;<br>     }<br> <br>-    // Set the RTS line.<br>-    status = dc_serial_set_rts (device->port, 1);<br>-    if (status != DC_STATUS_SUCCESS) {<br>-        ERROR (context, "Failed to set the RTS line.");<br>-        goto error_close;<br>-    }<br>-<br>-    // Set the DTR line.<br>-    status = dc_serial_set_dtr (device->port, 1);<br>-    if (status != DC_STATUS_SUCCESS) {<br>-        ERROR (context, "Failed to set the DTR line.");<br>-        goto error_close;<br>-    }<br>-<br>-    dc_serial_sleep (device->port, 200);<br>-<br>-    // Clear the DTR line.<br>-    status = dc_serial_set_dtr (device->port, 0);<br>-    if (status != DC_STATUS_SUCCESS) {<br>-        ERROR (context, "Failed to clear the DTR line.");<br>-        goto error_close;<br>-    }<br>-<br>-    dc_serial_sleep (device->port, 100);<br>-    dc_serial_purge (device->port, DC_DIRECTION_ALL);<br>-<br>     *out = (dc_device_t *) device;<br> <br>     return DC_STATUS_SUCCESS;<br>@@ -332,29 +350,56 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)<br>     progress.maximum = SZ_MEMORY;<br>     device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);<br> <br>-    // Send the command header to the dive computer.<br>-    const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d};<br>-    status = dc_serial_write (device->port, command, sizeof (command), NULL);<br>-    if (status != DC_STATUS_SUCCESS) {<br>-        ERROR (abstract->context, "Failed to send the command.");<br>-        return status;<br>+    for (int attempt = 0; attempt < MAXRETRIES; ++attempt) {<br>+        // Send the ping command to the dive computer.<br>+        unsigned char tmp[PING_LENGTH] = {0};<br>+        status = cressi_leonardo_device_read(abstract, PING_ADDRESS, tmp, sizeof(tmp));<br>+        if (status == DC_STATUS_SUCCESS)<br>+            break;<br>     }<br> <br>-    // Receive the header packet.<br>-    unsigned char header[7] = {0};<br>-    status = dc_serial_read (device->port, header, sizeof (header), NULL);<br>     if (status != DC_STATUS_SUCCESS) {<br>-        ERROR (abstract->context, "Failed to receive the answer.");<br>+        ERROR (abstract->context, "Failed to ping device.");<br>         return status;<br>     }<br> <br>-    // Verify the header packet.<br>-    const unsigned char expected[] = {0x7B, 0x21, 0x44, 0x35, 0x42, 0x33, 0x7d};<br>-    if (memcmp (header, expected, sizeof (expected)) != 0) {<br>-        ERROR (abstract->context, "Unexpected answer byte.");<br>-        return DC_STATUS_PROTOCOL;<br>+    for (int attempt = 0; attempt < MAXRETRIES; ++attempt) {<br>+        status = cressi_leonardo_transfer_prepare (device, abstract->context);<br>+        if (status != DC_STATUS_SUCCESS) {<br>+            ERROR (abstract->context, "Failed to prepare device for transfer.");<br>+            continue;<br>+        }<br>+<br>+        // Send the command header to the dive computer.<br>+        const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d};<br>+        status = dc_serial_write (device->port, command, sizeof (command), NULL);<br>+        if (status != DC_STATUS_SUCCESS) {<br>+            ERROR (abstract->context, "Failed to send the command.");<br>+            continue;<br>+        }<br>+<br>+        // Receive the header packet.<br>+        unsigned char header[7] = {0};<br>+        status = dc_serial_read (device->port, header, sizeof (header), NULL);<br>+        if (status != DC_STATUS_SUCCESS) {<br>+            ERROR (abstract->context, "Failed to receive the answer.");<br>+            continue;<br>+        }<br>+<br>+        // Verify the header packet.<br>+        const unsigned char expected[] = {0x7B, 0x21, 0x44, 0x35, 0x42, 0x33, 0x7d};<br>+        if (memcmp (header, expected, sizeof (expected)) != 0) {<br>+            ERROR (abstract->context, "Unexpected answer byte.");<br>+            status = DC_STATUS_PROTOCOL;<br>+            continue;<br>+        }<br>+<br>+        break;<br>     }<br> <br>+    if (status != DC_STATUS_SUCCESS)<br>+        return status;<br>+<br>     unsigned char *data = dc_buffer_get_data (buffer);<br> <br>     unsigned int nbytes = 0;<br>-- <br>2.11.0<br clear="all"><br>-- <br><div class="gmail_signature"><div dir="ltr"><div>Best wishes,<br></div>Vsevolod Velichko<br></div></div>
</div></div>