From f5d96a081c09d2fc515caaf99a299270cfb59ac6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 16 Feb 2015 21:46:21 +0100 Subject: [PATCH] Extend the retry logic to corrupt data packets. At the moment, there is only retry logic for the ACK/NAK byte. Corrupt data packets (e.g. wrong checksum, unexpected length, etc) are treated as a fatal error. By reading the entire packet inside the retry loop, all non-fatal errors are automatically taken care off. This change is necessary for the Oceanic VTX. For some unknown reason, the device always responds with an invalid data packet when sending the version command for the first time: W: 84 00 R: 5A 4F ?? 45 41 4E 56 54 58 20 31 42 20 32 30 34 38 E9 There is always one byte missing (marked with question marks), resulting in a timeout. However, when re-sending the command again, we receive a valid data packet: W: 84 00 R: 5A 4F 43 45 41 4E 56 54 58 20 31 42 20 32 30 34 38 E9 This might be a firmware bug, because we're observing the exact same behaviour with the official Oceanlog application. --- src/oceanic_atom2.c | 77 ++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index d67bde6..ba4fe4f 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -378,8 +378,9 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { 1 /* pt_mode_logbook */ }; + static dc_status_t -oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char ack) +oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) { dc_device_t *abstract = (dc_device_t *) device; @@ -397,6 +398,12 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[ return EXITCODE (n); } + // Get the correct ACK byte. + unsigned int ack = ACK; + if (command[0] == CMD_INIT || command[0] == CMD_QUIT) { + ack = NAK; + } + // Receive the response (ACK/NAK) of the dive computer. unsigned char response = 0; n = serial_read (device->port, &response, 1); @@ -411,40 +418,6 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[ return DC_STATUS_PROTOCOL; } - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) -{ - dc_device_t *abstract = (dc_device_t *) device; - - // Send the command to the device. If the device responds with an - // ACK byte, the command was received successfully and the answer - // (if any) follows after the ACK byte. If the device responds with - // a NAK byte, we try to resend the command a number of times before - // returning an error. - - unsigned int nretries = 0; - dc_status_t rc = DC_STATUS_SUCCESS; - while ((rc = oceanic_atom2_send (device, command, csize, ACK)) != DC_STATUS_SUCCESS) { - if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) - return rc; - - // Abort if the maximum number of retries is reached. - if (nretries++ >= MAXRETRIES) - return rc; - - // Increase the inter packet delay. - if (device->delay < MAXDELAY) - device->delay++; - - // Delay the next attempt. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_INPUT); - } - if (asize) { // Receive the answer of the dive computer. int n = serial_read (device->port, answer, asize); @@ -472,12 +445,44 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm } +static dc_status_t +oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) +{ + // Send the command to the device. If the device responds with an + // ACK byte, the command was received successfully and the answer + // (if any) follows after the ACK byte. If the device responds with + // a NAK byte, we try to resend the command a number of times before + // returning an error. + + unsigned int nretries = 0; + dc_status_t rc = DC_STATUS_SUCCESS; + while ((rc = oceanic_atom2_packet (device, command, csize, answer, asize, crc_size)) != DC_STATUS_SUCCESS) { + if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) + return rc; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + return rc; + + // Increase the inter packet delay. + if (device->delay < MAXDELAY) + device->delay++; + + // Delay the next attempt. + serial_sleep (device->port, 100); + serial_flush (device->port, SERIAL_QUEUE_INPUT); + } + + return DC_STATUS_SUCCESS; +} + + static dc_status_t oceanic_atom2_quit (oceanic_atom2_device_t *device) { // Send the command to the dive computer. unsigned char command[4] = {CMD_QUIT, 0x05, 0xA5, 0x00}; - dc_status_t rc = oceanic_atom2_send (device, command, sizeof (command), NAK); + dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc;