Introduce an adaptive inter packet delay.

On some systems a small delay is required between receiving the response
of a packet and sending the request for the next packet. Without this
delay, almost every request fails with either a NAK or a timeout.
Retrying usually works, but also causes the download to slow down
considerable.

The root of the problem appears to be related to the FTDI low latency
setting. On Windows and Mac OS X systems, the default setting for the
latency is 16ms, while Linux defaults to a low latency setting of only
1ms. This higher latency on Windows and Mac automatically introduces a
small delay while reading the packet, and that probably happens to be
just enough to make the transfer succeed without any problems. But on
Linux, due to the low latency setting, the next request is send almost
immediately, and that causes the transfer to fail. I suspect the dive
computer may still be busy with the previous request and needs a bit
more time before it's ready to accept a new request.

To mitigate this problem, we introduce a adaptive inter packet delay.
Initially this adaptive delay is set to zero. This is to make sure we
don't affect those systems that don't need a delay at all. Now, every
time a packet fails, that's an indication the inter packet delay is too
small, and we slightly increase the value. After a few attempts we'll
automatically reach the minimal required value. To avoid that the delay
grows out of control in the case of serious trouble, it's limited at
16ms.

Note that the fixed 100ms delay before retrying a failed packet remains
in place. That's on purpose, to make sure the next attempt will always
be successful, regardless of whether the adaptive delay has already
reached its minimal value or not.
This commit is contained in:
Jef Driesen 2014-03-28 06:36:04 +01:00
parent bfeab10515
commit f0faebb3a1

View File

@ -35,6 +35,7 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable)
#define MAXRETRIES 2
#define MAXDELAY 16
#define EXITCODE(rc) \
( \
@ -47,6 +48,7 @@
typedef struct oceanic_atom2_device_t {
oceanic_common_device_t base;
serial_t *port;
unsigned int delay;
} oceanic_atom2_device_t;
static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
@ -318,6 +320,10 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[
if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED;
if (device->delay) {
serial_sleep (device->port, device->delay);
}
// Send the command to the dive computer.
int n = serial_write (device->port, command, csize);
if (n != csize) {
@ -364,6 +370,10 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm
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);
@ -421,6 +431,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
// Set the default values.
device->port = NULL;
device->delay = 0;
// Open the device.
int rc = serial_open (&device->port, context, name);