<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>