From 474336a587d7ba23362cbeb7766ee6517b9a439e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 1 Nov 2011 22:05:34 +0100 Subject: [PATCH] Move the low-level communication to the common layer. --- src/mares_common.c | 181 ++++++++++++++++++++++++++++++++++++++ src/mares_common.h | 7 ++ src/mares_puck.c | 212 +++------------------------------------------ 3 files changed, 201 insertions(+), 199 deletions(-) diff --git a/src/mares_common.c b/src/mares_common.c index bac990d..f0333c3 100644 --- a/src/mares_common.c +++ b/src/mares_common.c @@ -24,9 +24,17 @@ #include // assert #include "mares_common.h" +#include "checksum.h" #include "utils.h" #include "array.h" +#define EXITCODE(rc) \ +( \ + rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ +) + +#define MAXRETRIES 4 + #define FP_OFFSET 8 #define FP_SIZE 5 @@ -39,6 +47,179 @@ mares_common_device_init (mares_common_device_t *device, const device_backend_t device_init (&device->base, backend); // Set the default values. + device->port = NULL; +} + + +static void +mares_common_convert_binary_to_ascii (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) +{ + assert (osize == 2 * isize); + + const unsigned char ascii[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + for (unsigned int i = 0; i < isize; ++i) { + // Set the most-significant nibble. + unsigned char msn = (input[i] >> 4) & 0x0F; + output[i * 2 + 0] = ascii[msn]; + + // Set the least-significant nibble. + unsigned char lsn = input[i] & 0x0F; + output[i * 2 + 1] = ascii[lsn]; + } +} + + +static void +mares_common_convert_ascii_to_binary (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) +{ + assert (isize == 2 * osize); + + for (unsigned int i = 0; i < osize; ++i) { + unsigned char value = 0; + for (unsigned int j = 0; j < 2; ++j) { + unsigned char number = 0; + unsigned char ascii = input[i * 2 + j]; + if (ascii >= '0' && ascii <= '9') + number = ascii - '0'; + else if (ascii >= 'A' && ascii <= 'F') + number = 10 + ascii - 'A'; + else if (ascii >= 'a' && ascii <= 'f') + number = 10 + ascii - 'a'; + else + WARNING ("Invalid charachter."); + + value <<= 4; + value += number; + } + output[i] = value; + } +} + + +static void +mares_common_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned char ascii[], unsigned int asize) +{ + assert (asize == 2 * (rsize + 2)); + + // Header + ascii[0] = '<'; + + // Data + mares_common_convert_binary_to_ascii (raw, rsize, ascii + 1, 2 * rsize); + + // Checksum + unsigned char checksum = checksum_add_uint8 (ascii + 1, 2 * rsize, 0x00); + mares_common_convert_binary_to_ascii (&checksum, 1, ascii + 1 + 2 * rsize, 2); + + // Trailer + ascii[asize - 1] = '>'; +} + + +static device_status_t +mares_common_packet (mares_common_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +{ + device_t *abstract = (device_t *) device; + + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + + // Send the command to the device. + int n = serial_write (device->port, command, csize); + if (n != csize) { + WARNING ("Failed to send the command."); + return EXITCODE (n); + } + + // Receive the answer of the device. + n = serial_read (device->port, answer, asize); + if (n != asize) { + WARNING ("Failed to receive the answer."); + return EXITCODE (n); + } + + // Verify the header and trailer of the packet. + if (answer[0] != '<' || answer[asize - 1] != '>') { + WARNING ("Unexpected answer header/trailer byte."); + return DEVICE_STATUS_PROTOCOL; + } + + // Verify the checksum of the packet. + unsigned char crc = 0; + unsigned char ccrc = checksum_add_uint8 (answer + 1, asize - 4, 0x00); + mares_common_convert_ascii_to_binary (answer + asize - 3, 2, &crc, 1); + if (crc != ccrc) { + WARNING ("Unexpected answer CRC."); + return DEVICE_STATUS_PROTOCOL; + } + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +mares_common_transfer (mares_common_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +{ + unsigned int nretries = 0; + device_status_t rc = DEVICE_STATUS_SUCCESS; + while ((rc = mares_common_packet (device, command, csize, answer, asize)) != DEVICE_STATUS_SUCCESS) { + // Automatically discard a corrupted packet, + // and request a new one. + if (rc != DEVICE_STATUS_PROTOCOL && rc != DEVICE_STATUS_TIMEOUT) + return rc; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + return rc; + } + + return rc; +} + + +device_status_t +mares_common_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) +{ + mares_common_device_t *device = (mares_common_device_t*) abstract; + + // The data transmission is split in packages + // of maximum $PACKETSIZE bytes. + + unsigned int nbytes = 0; + while (nbytes < size) { + // Calculate the packet size. + unsigned int len = size - nbytes; + if (len > PACKETSIZE) + len = PACKETSIZE; + + // Build the raw command. + unsigned char raw[] = {0x51, + (address ) & 0xFF, // Low + (address >> 8) & 0xFF, // High + len}; // Count + + // Build the ascii command. + unsigned char command[2 * (sizeof (raw) + 2)] = {0}; + mares_common_make_ascii (raw, sizeof (raw), command, sizeof (command)); + + // Send the command and receive the answer. + unsigned char answer[2 * (PACKETSIZE + 2)] = {0}; + device_status_t rc = mares_common_transfer (device, command, sizeof (command), answer, 2 * (len + 2)); + if (rc != DEVICE_STATUS_SUCCESS) + return rc; + + // Extract the raw data from the packet. + mares_common_convert_ascii_to_binary (answer + 1, 2 * len, data, len); + + nbytes += len; + address += len; + data += len; + } + + return DEVICE_STATUS_SUCCESS; } diff --git a/src/mares_common.h b/src/mares_common.h index d928dfb..74b4298 100644 --- a/src/mares_common.h +++ b/src/mares_common.h @@ -23,11 +23,14 @@ #define MARES_COMMON_H #include "device-private.h" +#include "serial.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +#define PACKETSIZE 0x20 + typedef struct mares_common_layout_t { unsigned int memsize; unsigned int rb_profile_begin; @@ -38,11 +41,15 @@ typedef struct mares_common_layout_t { typedef struct mares_common_device_t { device_t base; + serial_t *port; } mares_common_device_t; void mares_common_device_init (mares_common_device_t *device, const device_backend_t *backend); +device_status_t +mares_common_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); + device_status_t mares_common_extract_dives (const mares_common_layout_t *layout, const unsigned char fingerprint[], const unsigned char data[], dive_callback_t callback, void *userdata); diff --git a/src/mares_puck.c b/src/mares_puck.c index 3c158b0..f889112 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -31,14 +31,6 @@ #include "checksum.h" #include "array.h" -#define EXITCODE(rc) \ -( \ - rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ -) - -#define PACKETSIZE 0x20 -#define MAXRETRIES 4 - #define NEMOWIDE 1 #define NEMOAIR 4 #define PUCK 7 @@ -46,13 +38,11 @@ typedef struct mares_puck_device_t { mares_common_device_t base; - serial_t *port; const mares_common_layout_t *layout; unsigned char fingerprint[5]; } mares_puck_device_t; static device_status_t mares_puck_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size); -static device_status_t mares_puck_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static device_status_t mares_puck_device_dump (device_t *abstract, dc_buffer_t *buffer); static device_status_t mares_puck_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata); static device_status_t mares_puck_device_close (device_t *abstract); @@ -61,7 +51,7 @@ static const device_backend_t mares_puck_device_backend = { DEVICE_TYPE_MARES_PUCK, mares_puck_device_set_fingerprint, /* set_fingerprint */ NULL, /* version */ - mares_puck_device_read, /* read */ + mares_common_device_read, /* read */ NULL, /* write */ mares_puck_device_dump, /* dump */ mares_puck_device_foreach, /* foreach */ @@ -119,12 +109,11 @@ mares_puck_device_open (device_t **out, const char* name) mares_common_device_init (&device->base, &mares_puck_device_backend); // Set the default values. - device->port = NULL; device->layout = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, name); + int rc = serial_open (&device->base.port, name); if (rc == -1) { WARNING ("Failed to open the serial port."); free (device); @@ -132,39 +121,39 @@ mares_puck_device_open (device_t **out, const char* name) } // Set the serial communication protocol (38400 8N1). - rc = serial_configure (device->port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + rc = serial_configure (device->base.port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { WARNING ("Failed to set the terminal attributes."); - serial_close (device->port); + serial_close (device->base.port); free (device); return DEVICE_STATUS_IO; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + if (serial_set_timeout (device->base.port, 1000) == -1) { WARNING ("Failed to set the timeout."); - serial_close (device->port); + serial_close (device->base.port); free (device); return DEVICE_STATUS_IO; } // Clear the DTR/RTS lines. - if (serial_set_dtr (device->port, 0) == -1 || - serial_set_rts (device->port, 0) == -1) { + if (serial_set_dtr (device->base.port, 0) == -1 || + serial_set_rts (device->base.port, 0) == -1) { WARNING ("Failed to set the DTR/RTS line."); - serial_close (device->port); + serial_close (device->base.port); free (device); return DEVICE_STATUS_IO; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + serial_flush (device->base.port, SERIAL_QUEUE_BOTH); // Identify the model number. unsigned char header[PACKETSIZE] = {0}; - device_status_t status = mares_puck_device_read ((device_t *) device, 0, header, sizeof (header)); + device_status_t status = mares_common_device_read ((device_t *) device, 0, header, sizeof (header)); if (status != DEVICE_STATUS_SUCCESS) { - serial_close (device->port); + serial_close (device->base.port); free (device); return status; } @@ -201,7 +190,7 @@ mares_puck_device_close (device_t *abstract) return DEVICE_STATUS_TYPE_MISMATCH; // Close the device. - if (serial_close (device->port) == -1) { + if (serial_close (device->base.port) == -1) { free (device); return DEVICE_STATUS_IO; } @@ -230,181 +219,6 @@ mares_puck_device_set_fingerprint (device_t *abstract, const unsigned char data[ } -static void -mares_puck_convert_binary_to_ascii (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) -{ - assert (osize == 2 * isize); - - const unsigned char ascii[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - - for (unsigned int i = 0; i < isize; ++i) { - // Set the most-significant nibble. - unsigned char msn = (input[i] >> 4) & 0x0F; - output[i * 2 + 0] = ascii[msn]; - - // Set the least-significant nibble. - unsigned char lsn = input[i] & 0x0F; - output[i * 2 + 1] = ascii[lsn]; - } -} - - -static void -mares_puck_convert_ascii_to_binary (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize) -{ - assert (isize == 2 * osize); - - for (unsigned int i = 0; i < osize; ++i) { - unsigned char value = 0; - for (unsigned int j = 0; j < 2; ++j) { - unsigned char number = 0; - unsigned char ascii = input[i * 2 + j]; - if (ascii >= '0' && ascii <= '9') - number = ascii - '0'; - else if (ascii >= 'A' && ascii <= 'F') - number = 10 + ascii - 'A'; - else if (ascii >= 'a' && ascii <= 'f') - number = 10 + ascii - 'a'; - else - WARNING ("Invalid charachter."); - - value <<= 4; - value += number; - } - output[i] = value; - } -} - - -static void -mares_puck_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned char ascii[], unsigned int asize) -{ - assert (asize == 2 * (rsize + 2)); - - // Header - ascii[0] = '<'; - - // Data - mares_puck_convert_binary_to_ascii (raw, rsize, ascii + 1, 2 * rsize); - - // Checksum - unsigned char checksum = checksum_add_uint8 (ascii + 1, 2 * rsize, 0x00); - mares_puck_convert_binary_to_ascii (&checksum, 1, ascii + 1 + 2 * rsize, 2); - - // Trailer - ascii[asize - 1] = '>'; -} - - -static device_status_t -mares_puck_packet (mares_puck_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) -{ - device_t *abstract = (device_t *) device; - - if (device_is_cancelled (abstract)) - return DEVICE_STATUS_CANCELLED; - - // Send the command to the device. - int n = serial_write (device->port, command, csize); - if (n != csize) { - WARNING ("Failed to send the command."); - return EXITCODE (n); - } - - // Receive the answer of the device. - n = serial_read (device->port, answer, asize); - if (n != asize) { - WARNING ("Failed to receive the answer."); - return EXITCODE (n); - } - - // Verify the header and trailer of the packet. - if (answer[0] != '<' || answer[asize - 1] != '>') { - WARNING ("Unexpected answer header/trailer byte."); - return DEVICE_STATUS_PROTOCOL; - } - - // Verify the checksum of the packet. - unsigned char crc = 0; - unsigned char ccrc = checksum_add_uint8 (answer + 1, asize - 4, 0x00); - mares_puck_convert_ascii_to_binary (answer + asize - 3, 2, &crc, 1); - if (crc != ccrc) { - WARNING ("Unexpected answer CRC."); - return DEVICE_STATUS_PROTOCOL; - } - - return DEVICE_STATUS_SUCCESS; -} - - -static device_status_t -mares_puck_transfer (mares_puck_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) -{ - unsigned int nretries = 0; - device_status_t rc = DEVICE_STATUS_SUCCESS; - while ((rc = mares_puck_packet (device, command, csize, answer, asize)) != DEVICE_STATUS_SUCCESS) { - // Automatically discard a corrupted packet, - // and request a new one. - if (rc != DEVICE_STATUS_PROTOCOL && rc != DEVICE_STATUS_TIMEOUT) - return rc; - - // Abort if the maximum number of retries is reached. - if (nretries++ >= MAXRETRIES) - return rc; - } - - return rc; -} - - -static device_status_t -mares_puck_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) -{ - mares_puck_device_t *device = (mares_puck_device_t*) abstract; - - if (! device_is_mares_puck (abstract)) - return DEVICE_STATUS_TYPE_MISMATCH; - - // The data transmission is split in packages - // of maximum $PACKETSIZE bytes. - - unsigned int nbytes = 0; - while (nbytes < size) { - // Calculate the packet size. - unsigned int len = size - nbytes; - if (len > PACKETSIZE) - len = PACKETSIZE; - - // Build the raw command. - unsigned char raw[] = {0x51, - (address ) & 0xFF, // Low - (address >> 8) & 0xFF, // High - len}; // Count - - // Build the ascii command. - unsigned char command[2 * (sizeof (raw) + 2)] = {0}; - mares_puck_make_ascii (raw, sizeof (raw), command, sizeof (command)); - - // Send the command and receive the answer. - unsigned char answer[2 * (PACKETSIZE + 2)] = {0}; - device_status_t rc = mares_puck_transfer (device, command, sizeof (command), answer, 2 * (len + 2)); - if (rc != DEVICE_STATUS_SUCCESS) - return rc; - - // Extract the raw data from the packet. - mares_puck_convert_ascii_to_binary (answer + 1, 2 * len, data, len); - - nbytes += len; - address += len; - data += len; - } - - return DEVICE_STATUS_SUCCESS; -} - - static device_status_t mares_puck_device_dump (device_t *abstract, dc_buffer_t *buffer) {