Reduce the number of read operations.

Only the header of the package needs to be read separately (to obtain 
the size of the entire package). Removed the suunto_vyper_recv function.
This commit is contained in:
Jef Driesen 2008-03-26 08:47:14 +00:00
parent fcf11209b7
commit 7dd1d19eab

View File

@ -14,13 +14,6 @@
message ("%s:%d: %s\n", __FILE__, __LINE__, expr); \ message ("%s:%d: %s\n", __FILE__, __LINE__, expr); \
} }
#define EXITCODE(rc, n) \
( \
rc == -1 ? \
SUUNTO_ERROR_IO : \
(rc != n ? SUUNTO_ERROR_TIMEOUT : SUUNTO_ERROR_PROTOCOL) \
)
struct vyper { struct vyper {
struct serial *port; struct serial *port;
@ -255,18 +248,6 @@ suunto_vyper_send (vyper *device, const unsigned char command[], unsigned int cs
} }
static int
suunto_vyper_recv (vyper *device, unsigned char data[], unsigned int size)
{
int rc = serial_read (device->port, data, size);
if (rc != size) {
return EXITCODE (rc, size);
}
return SUUNTO_SUCCESS;
}
static int static int
suunto_vyper_transfer (vyper *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) suunto_vyper_transfer (vyper *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size)
{ {
@ -280,10 +261,12 @@ suunto_vyper_transfer (vyper *device, const unsigned char command[], unsigned in
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
rc = suunto_vyper_recv (device, answer, asize); rc = serial_read (device->port, answer, asize);
if (rc != SUUNTO_SUCCESS) { if (rc != asize) {
WARNING ("Failed to receive the answer."); WARNING ("Failed to receive the answer.");
return rc; if (rc == -1)
return SUUNTO_ERROR_IO;
return SUUNTO_ERROR_TIMEOUT;
} }
// Verify the header of the package. // Verify the header of the package.
@ -410,33 +393,24 @@ suunto_vyper_read_dive (vyper *device, unsigned char data[], unsigned int size,
if (device == NULL) if (device == NULL)
return SUUNTO_ERROR; return SUUNTO_ERROR;
// Prepare the command. // Send the command to the dive computer.
unsigned char command[3] = {init ? 0x08 : 0x09, 0xA5, 0x00}; unsigned char command[3] = {init ? 0x08 : 0x09, 0xA5, 0x00};
command[2] = suunto_vyper_checksum (command, 2, 0x00); command[2] = suunto_vyper_checksum (command, 2, 0x00);
// Send the command to the dive computer.
int rc = suunto_vyper_send (device, command, 3); int rc = suunto_vyper_send (device, command, 3);
if (rc != SUUNTO_SUCCESS) { if (rc != SUUNTO_SUCCESS) {
WARNING ("Failed to send the command."); WARNING ("Failed to send the command.");
return rc; return rc;
} }
// FIXME: Give the DC extra answer time to send its first byte,
// then let the standard timeout apply.
// The data transmission is split in packages // The data transmission is split in packages
// of maximum $SUUNTO_VYPER_PACKET_SIZE bytes. // of maximum $SUUNTO_VYPER_PACKET_SIZE bytes.
unsigned int nbytes = 0; unsigned int nbytes = 0;
for (unsigned int npackages = 0;; ++npackages) { for (unsigned int npackages = 0;; ++npackages) {
// Initial checksum value.
unsigned char ccrc = 0x00;
// Receive the header of the package. // Receive the header of the package.
unsigned char header[2] = {0}; unsigned char answer[SUUNTO_VYPER_PACKET_SIZE + 3] = {0};
rc = serial_read (device->port, header, 2); rc = serial_read (device->port, answer, 2);
if (rc != 2 || memcmp (command, header, 1) != 0 || if (rc != 2) {
header[1] > SUUNTO_VYPER_PACKET_SIZE) {
// If no data is received because a timeout occured, we assume // If no data is received because a timeout occured, we assume
// the last package was already received and the transmission // the last package was already received and the transmission
// can be finished. Unfortunately this is not 100% reliable, // can be finished. Unfortunately this is not 100% reliable,
@ -447,34 +421,40 @@ suunto_vyper_read_dive (vyper *device, unsigned char data[], unsigned int size,
// an error, because the DC always sends at least one package. // an error, because the DC always sends at least one package.
if (rc == 0 && npackages != 0) if (rc == 0 && npackages != 0)
break; break;
WARNING ("Failed to receive the answer.");
if (rc == -1)
return SUUNTO_ERROR_IO;
return SUUNTO_ERROR_TIMEOUT;
}
// Verify the header of the package.
if (answer[0] != command[0] ||
answer[1] > SUUNTO_VYPER_PACKET_SIZE) {
WARNING ("Unexpected answer start byte(s)."); WARNING ("Unexpected answer start byte(s).");
return EXITCODE (rc, 2); return SUUNTO_ERROR_PROTOCOL;
} }
// Update the checksum.
ccrc = suunto_vyper_checksum (header, 2, ccrc);
// Receive the contents of the package. // Receive the remaining part of the package.
unsigned char len = header[1]; unsigned char len = answer[1];
unsigned char package[SUUNTO_VYPER_PACKET_SIZE] = {0}; rc = serial_read (device->port, answer + 2, len + 1);
rc = serial_read (device->port, package, len); if (rc != len + 1) {
if (rc != len) { WARNING ("Failed to receive the answer.");
WARNING ("Unexpected EOF in answer."); if (rc == -1)
return EXITCODE (rc, len); return SUUNTO_ERROR_IO;
return SUUNTO_ERROR_TIMEOUT;
} }
// Update the checksum.
ccrc = suunto_vyper_checksum (package, len, ccrc);
// Receive (and verify) the checksum of the package. // Verify the checksum of the package.
unsigned char crc = 0x00; unsigned char crc = answer[len + 2];
rc = serial_read (device->port, &crc, 1); unsigned char ccrc = suunto_vyper_checksum (answer, len + 2, 0x00);
if (rc != 1 || ccrc != crc) { if (crc != ccrc) {
WARNING ("Unexpected answer CRC."); WARNING ("Unexpected answer CRC.");
return EXITCODE (rc, 1); return SUUNTO_ERROR_PROTOCOL;
} }
// Append the package to the output buffer. // Append the package to the output buffer.
if (nbytes + len <= size) { if (nbytes + len <= size) {
memcpy (data + nbytes, package, len); memcpy (data + nbytes, answer + 2, len);
nbytes += len; nbytes += len;
} else { } else {
WARNING ("Insufficient buffer space available."); WARNING ("Insufficient buffer space available.");