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.
This commit is contained in:
Jef Driesen 2016-10-30 00:01:30 +02:00
parent 39aa859d19
commit c3dc368163

View File

@ -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)
{