From c3dc368163f857361aeb4052fda8adcd28926bb3 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 30 Oct 2016 00:01:30 +0200 Subject: [PATCH] Implement the read function The read command appears to be limited to the range 0x1000-0x1100. That range seems to correspond with the first 256 bytes of the full memory dump. The packet size of 32 bytes is an arbitrary choice. --- src/cressi_leonardo.c | 136 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index b99f999..faad494 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -45,6 +45,9 @@ #define RB_PROFILE_END SZ_MEMORY #define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END) +#define MAXRETRIES 4 +#define PACKETSIZE 32 + typedef struct cressi_leonardo_device_t { dc_device_t base; dc_serial_t *port; @@ -52,6 +55,7 @@ typedef struct cressi_leonardo_device_t { } cressi_leonardo_device_t; static dc_status_t cressi_leonardo_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); +static dc_status_t cressi_leonardo_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t cressi_leonardo_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); static dc_status_t cressi_leonardo_device_close (dc_device_t *abstract); @@ -60,13 +64,102 @@ static const dc_device_vtable_t cressi_leonardo_device_vtable = { sizeof(cressi_leonardo_device_t), DC_FAMILY_CRESSI_LEONARDO, cressi_leonardo_device_set_fingerprint, /* set_fingerprint */ - NULL, /* read */ + cressi_leonardo_device_read, /* read */ NULL, /* write */ cressi_leonardo_device_dump, /* dump */ cressi_leonardo_device_foreach, /* foreach */ cressi_leonardo_device_close /* close */ }; +static void +cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned char ascii[], unsigned int asize) +{ + assert (asize == 2 * (rsize + 3)); + + // Header + ascii[0] = '{'; + + // Data + array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize); + + // Checksum + unsigned short crc = checksum_crc_ccitt_uint16 (ascii + 1, 2 * rsize); + unsigned char checksum[] = { + (crc >> 8) & 0xFF, // High + (crc ) & 0xFF}; // Low + array_convert_bin2hex (checksum, sizeof(checksum), ascii + 1 + 2 * rsize, 4); + + // Trailer + ascii[asize - 1] = '}'; +} + +static dc_status_t +cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_device_t *abstract = (dc_device_t *) device; + + if (device_is_cancelled (abstract)) + return DC_STATUS_CANCELLED; + + // Send the command to the device. + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the command."); + return status; + } + + // Receive the answer of the device. + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the answer."); + return status; + } + + // Verify the header and trailer of the packet. + if (answer[0] != '{' || answer[asize - 1] != '}') { + ERROR (abstract->context, "Unexpected answer header/trailer byte."); + return DC_STATUS_PROTOCOL; + } + + // Convert the checksum of the packet. + unsigned char checksum[2] = {0}; + array_convert_hex2bin (answer + asize - 5, 4, checksum, sizeof(checksum)); + + // Verify the checksum of the packet. + unsigned short crc = array_uint16_be (checksum); + unsigned short ccrc = checksum_crc_ccitt_uint16 (answer + 1, asize - 6); + if (crc != ccrc) { + ERROR (abstract->context, "Unexpected answer checksum."); + return DC_STATUS_PROTOCOL; + } + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +cressi_leonardo_transfer (cressi_leonardo_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +{ + unsigned int nretries = 0; + dc_status_t rc = DC_STATUS_SUCCESS; + while ((rc = cressi_leonardo_packet (device, command, csize, answer, asize)) != DC_STATUS_SUCCESS) { + // Automatically discard a corrupted packet, + // and request a new one. + if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT) + return rc; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + return rc; + + // Discard any garbage bytes. + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); + } + + return rc; +} + dc_status_t cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const char *name) { @@ -168,6 +261,47 @@ cressi_leonardo_device_set_fingerprint (dc_device_t *abstract, const unsigned ch return DC_STATUS_SUCCESS; } +static dc_status_t +cressi_leonardo_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; + + 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[] = { + (address >> 8) & 0xFF, // High + (address ) & 0xFF, // Low + (len >> 8) & 0xFF, // High + (len ) & 0xFF}; // Low + + // Build the ascii command. + unsigned char command[2 * (sizeof (raw) + 3)] = {0}; + cressi_leonardo_make_ascii (raw, sizeof (raw), command, sizeof (command)); + + // Send the command and receive the answer. + unsigned char answer[2 * (PACKETSIZE + 3)] = {0}; + rc = cressi_leonardo_transfer (device, command, sizeof (command), answer, 2 * (len + 3)); + if (rc != DC_STATUS_SUCCESS) + return rc; + + // Extract the raw data from the packet. + array_convert_hex2bin (answer + 1, 2 * len, data, len); + + nbytes += len; + address += len; + data += len; + } + + return rc; +} + static dc_status_t cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) {