Merge branch 'ostc4'
This commit is contained in:
commit
42e234a0f9
@ -216,6 +216,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11},
|
||||
{"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A},
|
||||
{"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x1A},
|
||||
{"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B},
|
||||
{"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05},
|
||||
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12},
|
||||
/* Cressi Edy */
|
||||
|
||||
338
src/hw_ostc3.c
338
src/hw_ostc3.c
@ -49,6 +49,7 @@
|
||||
#define SZ_HARDWARE 1
|
||||
#define SZ_MEMORY 0x400000
|
||||
#define SZ_CONFIG 4
|
||||
#define SZ_FWINFO 4
|
||||
#define SZ_FIRMWARE 0x01E000 // 120KB
|
||||
#define SZ_FIRMWARE_BLOCK 0x1000 // 4KB
|
||||
#define FIRMWARE_AREA 0x3E0000
|
||||
@ -69,18 +70,25 @@
|
||||
#define DIVE 0x66
|
||||
#define IDENTITY 0x69
|
||||
#define HARDWARE 0x6A
|
||||
#define S_FWINFO 0x6B
|
||||
#define DISPLAY 0x6E
|
||||
#define COMPACT 0x6D
|
||||
#define READ 0x72
|
||||
#define S_UPLOAD 0x73
|
||||
#define WRITE 0x77
|
||||
#define RESET 0x78
|
||||
#define INIT 0xBB
|
||||
#define EXIT 0xFF
|
||||
|
||||
#define INVALID 0xFFFFFFFF
|
||||
#define UNKNOWN 0x00
|
||||
#define OSTC3 0x0A
|
||||
#define OSTC4 0x3B
|
||||
#define SPORT 0x12
|
||||
#define CR 0x05
|
||||
|
||||
#define NODELAY 0
|
||||
|
||||
typedef enum hw_ostc3_state_t {
|
||||
OPEN,
|
||||
DOWNLOAD,
|
||||
@ -91,6 +99,7 @@ typedef enum hw_ostc3_state_t {
|
||||
typedef struct hw_ostc3_device_t {
|
||||
dc_device_t base;
|
||||
serial_t *port;
|
||||
unsigned int hardware;
|
||||
unsigned char fingerprint[5];
|
||||
hw_ostc3_state_t state;
|
||||
} hw_ostc3_device_t;
|
||||
@ -175,7 +184,8 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
const unsigned char input[],
|
||||
unsigned int isize,
|
||||
unsigned char output[],
|
||||
unsigned int osize)
|
||||
unsigned int osize,
|
||||
unsigned int delay)
|
||||
{
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
@ -214,10 +224,29 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
|
||||
if (input) {
|
||||
// Send the input data packet.
|
||||
n = serial_write (device->port, input, isize);
|
||||
if (n != isize) {
|
||||
ERROR (abstract->context, "Failed to send the data packet.");
|
||||
return EXITCODE (n);
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < isize) {
|
||||
// Set the minimum packet size.
|
||||
unsigned int len = 64;
|
||||
|
||||
// Limit the packet size to the total size.
|
||||
if (nbytes + len > isize)
|
||||
len = isize - nbytes;
|
||||
|
||||
// Write the packet.
|
||||
n = serial_write (device->port, input + nbytes, len);
|
||||
if (n != len) {
|
||||
ERROR (abstract->context, "Failed to send the data packet.");
|
||||
return EXITCODE (n);
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += len;
|
||||
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
nbytes += len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,6 +282,16 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
}
|
||||
}
|
||||
|
||||
if (delay) {
|
||||
unsigned int count = delay / 100;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
if (serial_get_received (device->port) > 0)
|
||||
break;
|
||||
|
||||
serial_sleep (device->port, 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd != EXIT) {
|
||||
// Read the ready byte.
|
||||
unsigned char answer[1] = {0};
|
||||
@ -291,6 +330,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name
|
||||
|
||||
// Set the default values.
|
||||
device->port = NULL;
|
||||
device->hardware = INVALID;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
// Open the device.
|
||||
@ -341,7 +381,7 @@ hw_ostc3_device_init_download (hw_ostc3_device_t *device)
|
||||
dc_context_t *context = (abstract ? abstract->context : NULL);
|
||||
|
||||
// Send the init command.
|
||||
dc_status_t status = hw_ostc3_transfer (device, NULL, INIT, NULL, 0, NULL, 0);
|
||||
dc_status_t status = hw_ostc3_transfer (device, NULL, INIT, NULL, 0, NULL, 0, NODELAY);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to send the command.");
|
||||
return status;
|
||||
@ -398,6 +438,7 @@ static dc_status_t
|
||||
hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (device->state == state) {
|
||||
// No change.
|
||||
@ -421,7 +462,24 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state)
|
||||
rc = DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
return rc;
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (device->hardware != INVALID)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
// Read the hardware descriptor.
|
||||
unsigned char hardware[SZ_HARDWARE] = {UNKNOWN};
|
||||
rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, hardware, sizeof(hardware), NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to read the hardware descriptor.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Cache the descriptor.
|
||||
device->hardware = hardware[0];
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -434,7 +492,7 @@ hw_ostc3_device_close (dc_device_t *abstract)
|
||||
|
||||
// Send the exit command
|
||||
if (device->state == DOWNLOAD || device->state == SERVICE) {
|
||||
rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
dc_status_set_error(&status, rc);
|
||||
@ -483,7 +541,7 @@ hw_ostc3_device_version (dc_device_t *abstract, unsigned char data[], unsigned i
|
||||
return rc;
|
||||
|
||||
// Send the command.
|
||||
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, data, size);
|
||||
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, data, size, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -507,7 +565,7 @@ hw_ostc3_device_hardware (dc_device_t *abstract, unsigned char data[], unsigned
|
||||
return rc;
|
||||
|
||||
// Send the command.
|
||||
rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, data, size);
|
||||
rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, data, size, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -537,20 +595,13 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Download the hardware descriptor.
|
||||
unsigned char hardware[SZ_HARDWARE] = {0};
|
||||
rc = hw_ostc3_device_hardware (abstract, hardware, sizeof (hardware));
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to read the hardware descriptor.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.firmware = array_uint16_be (id + 2);
|
||||
devinfo.serial = array_uint16_le (id + 0);
|
||||
devinfo.model = hardware[0];
|
||||
if (devinfo.model == 0) {
|
||||
if (device->hardware != UNKNOWN) {
|
||||
devinfo.model = device->hardware;
|
||||
} else {
|
||||
// Fallback to the serial number.
|
||||
if (devinfo.serial > 10000)
|
||||
devinfo.model = SPORT;
|
||||
@ -571,11 +622,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
// This is slower, but also works for older firmware versions.
|
||||
unsigned int compact = 1;
|
||||
rc = hw_ostc3_transfer (device, &progress, COMPACT,
|
||||
NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT);
|
||||
NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT, NODELAY);
|
||||
if (rc == DC_STATUS_UNSUPPORTED) {
|
||||
compact = 0;
|
||||
rc = hw_ostc3_transfer (device, &progress, HEADER,
|
||||
NULL, 0, header, RB_LOGBOOK_SIZE_FULL * RB_LOGBOOK_COUNT);
|
||||
NULL, 0, header, RB_LOGBOOK_SIZE_FULL * RB_LOGBOOK_COUNT, NODELAY);
|
||||
}
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the header.");
|
||||
@ -651,7 +702,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.maximum = (logbook->size * RB_LOGBOOK_COUNT) + size;
|
||||
progress.maximum = (logbook->size * RB_LOGBOOK_COUNT) + size + ndives;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Finish immediately if there are no dives available.
|
||||
@ -685,7 +736,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
// Download the dive.
|
||||
unsigned char number[1] = {idx};
|
||||
rc = hw_ostc3_transfer (device, &progress, DIVE,
|
||||
number, sizeof (number), profile, length);
|
||||
number, sizeof (number), profile, length, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive.");
|
||||
free (profile);
|
||||
@ -733,7 +784,7 @@ hw_ostc3_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
unsigned char packet[6] = {
|
||||
datetime->hour, datetime->minute, datetime->second,
|
||||
datetime->month, datetime->day, datetime->year - 2000};
|
||||
rc = hw_ostc3_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -761,7 +812,7 @@ hw_ostc3_device_display (dc_device_t *abstract, const char *text)
|
||||
return rc;
|
||||
|
||||
// Send the command.
|
||||
rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -789,7 +840,7 @@ hw_ostc3_device_customtext (dc_device_t *abstract, const char *text)
|
||||
return rc;
|
||||
|
||||
// Send the command.
|
||||
rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -804,18 +855,18 @@ hw_ostc3_device_config_read (dc_device_t *abstract, unsigned int config, unsigne
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size > SZ_CONFIG) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (device->hardware == OSTC4 ? size != SZ_CONFIG : size > SZ_CONFIG) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Send the command.
|
||||
unsigned char command[1] = {config};
|
||||
rc = hw_ostc3_transfer (device, NULL, READ, command, sizeof (command), data, size);
|
||||
rc = hw_ostc3_transfer (device, NULL, READ, command, sizeof (command), data, size, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -830,19 +881,19 @@ hw_ostc3_device_config_write (dc_device_t *abstract, unsigned int config, const
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size > SZ_CONFIG) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (device->hardware == OSTC4 ? size != SZ_CONFIG : size > SZ_CONFIG) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Send the command.
|
||||
unsigned char command[SZ_CONFIG + 1] = {config};
|
||||
memcpy(command + 1, data, size);
|
||||
rc = hw_ostc3_transfer (device, NULL, WRITE, command, size + 1, NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, WRITE, command, size + 1, NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -862,7 +913,7 @@ hw_ostc3_device_config_reset (dc_device_t *abstract)
|
||||
return rc;
|
||||
|
||||
// Send the command.
|
||||
rc = hw_ostc3_transfer (device, NULL, RESET, NULL, 0, NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, RESET, NULL, 0, NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -872,12 +923,12 @@ hw_ostc3_device_config_reset (dc_device_t *abstract)
|
||||
// This is a variant of fletcher16 with a 16 bit sum instead of an 8 bit sum,
|
||||
// and modulo 2^16 instead of 2^16-1
|
||||
static unsigned int
|
||||
hw_ostc3_firmware_checksum (hw_ostc3_firmware_t *firmware)
|
||||
hw_ostc3_firmware_checksum (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned short low = 0;
|
||||
unsigned short high = 0;
|
||||
for (unsigned int i = 0; i < SZ_FIRMWARE; i++) {
|
||||
low += firmware->data[i];
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
low += data[i];
|
||||
high += low;
|
||||
}
|
||||
return (((unsigned int)high) << 16) + low;
|
||||
@ -945,7 +996,7 @@ hw_ostc3_firmware_readline (FILE *fp, dc_context_t *context, unsigned int addr,
|
||||
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_readfile (hw_ostc3_firmware_t *firmware, dc_context_t *context, const char *filename)
|
||||
hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *context, const char *filename)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
FILE *fp = NULL;
|
||||
@ -1007,16 +1058,67 @@ hw_ostc3_firmware_readfile (hw_ostc3_firmware_t *firmware, dc_context_t *context
|
||||
|
||||
fclose (fp);
|
||||
|
||||
firmware->checksum = array_uint32_le (checksum);
|
||||
|
||||
if (firmware->checksum != hw_ostc3_firmware_checksum (firmware)) {
|
||||
unsigned int csum1 = array_uint32_le (checksum);
|
||||
unsigned int csum2 = hw_ostc3_firmware_checksum (firmware->data, sizeof(firmware->data));
|
||||
if (csum1 != csum2) {
|
||||
ERROR (context, "Failed to verify file checksum.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
firmware->checksum = csum1;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_readfile4 (dc_buffer_t *buffer, dc_context_t *context, const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (buffer == NULL) {
|
||||
ERROR (context, "Invalid arguments.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Open the file.
|
||||
fp = fopen (filename, "rb");
|
||||
if (fp == NULL) {
|
||||
ERROR (context, "Failed to open the file.");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
// Read the entire file into the buffer.
|
||||
size_t n = 0;
|
||||
unsigned char block[1024] = {0};
|
||||
while ((n = fread (block, 1, sizeof (block), fp)) > 0) {
|
||||
dc_buffer_append (buffer, block, n);
|
||||
}
|
||||
|
||||
// Close the file.
|
||||
fclose (fp);
|
||||
|
||||
// Verify the minimum size.
|
||||
size_t size = dc_buffer_get_size (buffer);
|
||||
if (size < 4) {
|
||||
ERROR (context, "Invalid file size.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
}
|
||||
|
||||
// Verify the checksum.
|
||||
const unsigned char *data = dc_buffer_get_data (buffer);
|
||||
unsigned int csum1 = array_uint32_le (data + size - 4);
|
||||
unsigned int csum2 = hw_ostc3_firmware_checksum (data, size - 4);
|
||||
if (csum1 != csum2) {
|
||||
ERROR (context, "Failed to verify file checksum.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Remove the checksum.
|
||||
dc_buffer_slice (buffer, 0, size - 4);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_erase (hw_ostc3_device_t *device, unsigned int addr, unsigned int size)
|
||||
@ -1029,7 +1131,7 @@ hw_ostc3_firmware_erase (hw_ostc3_device_t *device, unsigned int addr, unsigned
|
||||
array_uint24_be_set (buffer, addr);
|
||||
buffer[3] = blocks;
|
||||
|
||||
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0);
|
||||
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0, NODELAY);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -1039,7 +1141,7 @@ hw_ostc3_firmware_block_read (hw_ostc3_device_t *device, unsigned int addr, unsi
|
||||
array_uint24_be_set (buffer, addr);
|
||||
array_uint24_be_set (buffer + 3, block_size);
|
||||
|
||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_READ, buffer, sizeof (buffer), block, block_size);
|
||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_READ, buffer, sizeof (buffer), block, block_size, NODELAY);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -1054,7 +1156,7 @@ hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int addr, uns
|
||||
array_uint24_be_set (buffer, addr);
|
||||
memcpy (buffer + 3, block, block_size);
|
||||
|
||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE, buffer, 3 + block_size, NULL, 0);
|
||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE, buffer, 3 + block_size, NULL, 0, NODELAY);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -1073,7 +1175,7 @@ hw_ostc3_firmware_upgrade (dc_device_t *abstract, unsigned int checksum)
|
||||
buffer[4] = (buffer[4]<<1 | buffer[4]>>7);
|
||||
}
|
||||
|
||||
rc = hw_ostc3_transfer (device, NULL, S_UPGRADE, buffer, sizeof (buffer), NULL, 0);
|
||||
rc = hw_ostc3_transfer (device, NULL, S_UPGRADE, buffer, sizeof (buffer), NULL, 0, NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to send flash firmware command");
|
||||
return rc;
|
||||
@ -1086,20 +1188,16 @@ hw_ostc3_firmware_upgrade (dc_device_t *abstract, unsigned int checksum)
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
static dc_status_t
|
||||
hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
dc_context_t *context = (abstract ? abstract->context : NULL);
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// load, erase, upload FZ, verify FZ, reprogram
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = 3 + SZ_FIRMWARE * 2 / SZ_FIRMWARE_BLOCK;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
@ -1111,14 +1209,7 @@ hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
}
|
||||
|
||||
// Read the hex file.
|
||||
rc = hw_ostc3_firmware_readfile (firmware, context, filename);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
free (firmware);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Make sure the device is in service mode
|
||||
rc = hw_ostc3_device_init (device, SERVICE);
|
||||
rc = hw_ostc3_firmware_readfile3 (firmware, context, filename);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
free (firmware);
|
||||
return rc;
|
||||
@ -1203,6 +1294,121 @@ hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
dc_context_t *context = (abstract ? abstract->context : NULL);
|
||||
|
||||
// Allocate memory for the firmware data.
|
||||
dc_buffer_t *buffer = dc_buffer_new (0);
|
||||
if (buffer == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Read the firmware file.
|
||||
status = hw_ostc3_firmware_readfile4 (buffer, context, filename);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = dc_buffer_get_size (buffer);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Cache the pointer and size.
|
||||
const unsigned char *data = dc_buffer_get_data (buffer);
|
||||
unsigned int size = dc_buffer_get_size (buffer);
|
||||
|
||||
unsigned int offset = 0;
|
||||
while (offset + 4 <= size) {
|
||||
// Get the length of the firmware blob.
|
||||
unsigned int length = array_uint32_be(data + offset) + 20;
|
||||
if (offset + length > size) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Get the blob type.
|
||||
unsigned char type = data[offset + 4];
|
||||
|
||||
// Estimate the required delay.
|
||||
// After uploading the firmware blob, the device writes the data
|
||||
// to flash memory. Since this takes a significant amount of
|
||||
// time, the ready byte is delayed. Therefore, the standard
|
||||
// timeout is no longer sufficient. The delays are estimated
|
||||
// based on actual measurements of the delay per byte.
|
||||
unsigned int usecs = length;
|
||||
if (type == 0xFF) {
|
||||
// Firmware
|
||||
usecs *= 50;
|
||||
} else if (type == 0xFE) {
|
||||
// RTE
|
||||
usecs *= 500;
|
||||
} else {
|
||||
// Fonts
|
||||
usecs *= 25;
|
||||
}
|
||||
|
||||
// Read the firmware version info.
|
||||
unsigned char fwinfo[SZ_FWINFO] = {0};
|
||||
status = hw_ostc3_transfer (device, NULL, S_FWINFO,
|
||||
data + offset + 4, 1, fwinfo, sizeof(fwinfo), NODELAY);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the firmware info.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Upload the firmware blob.
|
||||
// The update is skipped if the two versions are already
|
||||
// identical, or if the blob is not present on the device.
|
||||
if (memcmp(data + offset + 12, fwinfo, sizeof(fwinfo)) != 0 &&
|
||||
!array_isequal(fwinfo, sizeof(fwinfo), 0xFF))
|
||||
{
|
||||
status = hw_ostc3_transfer (device, &progress, S_UPLOAD,
|
||||
data + offset, length, NULL, 0, usecs / 1000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
// Update and emit a progress event.
|
||||
progress.current += length;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
}
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
error:
|
||||
dc_buffer_free (buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Make sure the device is in service mode.
|
||||
status = hw_ostc3_device_init (device, SERVICE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return hw_ostc3_device_fwupdate4 (abstract, filename);
|
||||
} else {
|
||||
return hw_ostc3_device_fwupdate3 (abstract, filename);
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user