Merge branch 'ostc3-fwupdate-improvements'
This commit is contained in:
commit
82f298febd
148
src/hw_ostc3.c
148
src/hw_ostc3.c
@ -43,6 +43,7 @@
|
||||
#define SZ_FWINFO 4
|
||||
#define SZ_FIRMWARE 0x01E000 // 120KB
|
||||
#define SZ_FIRMWARE_BLOCK 0x1000 // 4KB
|
||||
#define SZ_FIRMWARE_BLOCK2 0x0100 // 256B
|
||||
#define FIRMWARE_AREA 0x3E0000
|
||||
|
||||
#define RB_LOGBOOK_SIZE_COMPACT 16
|
||||
@ -51,6 +52,7 @@
|
||||
|
||||
#define S_BLOCK_READ 0x20
|
||||
#define S_BLOCK_WRITE 0x30
|
||||
#define S_BLOCK_WRITE2 0x31
|
||||
#define S_ERASE 0x42
|
||||
#define S_READY 0x4C
|
||||
#define READY 0x4D
|
||||
@ -69,6 +71,7 @@
|
||||
#define S_UPLOAD 0x73
|
||||
#define WRITE 0x77
|
||||
#define RESET 0x78
|
||||
#define S_INIT 0xAA
|
||||
#define INIT 0xBB
|
||||
#define EXIT 0xFF
|
||||
|
||||
@ -80,6 +83,7 @@
|
||||
#define CR 0x05
|
||||
|
||||
#define NODELAY 0
|
||||
#define TIMEOUT 400
|
||||
|
||||
typedef enum hw_ostc3_state_t {
|
||||
OPEN,
|
||||
@ -94,6 +98,8 @@ typedef struct hw_ostc3_device_t {
|
||||
unsigned int hardware;
|
||||
unsigned int feature;
|
||||
unsigned int model;
|
||||
unsigned int serial;
|
||||
unsigned int firmware;
|
||||
unsigned char fingerprint[5];
|
||||
hw_ostc3_state_t state;
|
||||
unsigned char cache[20];
|
||||
@ -113,8 +119,8 @@ typedef struct hw_ostc3_firmware_t {
|
||||
unsigned int checksum;
|
||||
} hw_ostc3_firmware_t;
|
||||
|
||||
// This key is used both for the Ostc3 and its cousin,
|
||||
// the Ostc Sport.
|
||||
// This key is used both for the OSTC3 and its cousin,
|
||||
// the OSTC Sport.
|
||||
// The Frog uses a similar protocol, and with another key.
|
||||
static const unsigned char ostc3_key[16] = {
|
||||
0xF1, 0xE9, 0xB0, 0x30,
|
||||
@ -317,7 +323,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
}
|
||||
|
||||
if (output) {
|
||||
// Read the ouput data packet.
|
||||
// Read the output data packet.
|
||||
status = hw_ostc3_read (device, progress, output, osize);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
@ -370,6 +376,8 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
||||
device->hardware = INVALID;
|
||||
device->feature = 0;
|
||||
device->model = 0;
|
||||
device->serial = 0;
|
||||
device->firmware = 0;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
memset (device->cache, 0, sizeof (device->cache));
|
||||
device->available = 0;
|
||||
@ -456,33 +464,43 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
dc_context_t *context = (abstract ? abstract->context : NULL);
|
||||
|
||||
unsigned char command[] = {0xAA, 0xAB, 0xCD, 0xEF};
|
||||
unsigned char output[5];
|
||||
const unsigned char command[] = {S_INIT, 0xAB, 0xCD, 0xEF};
|
||||
unsigned char answer[5] = {0};
|
||||
|
||||
// We cant use hw_ostc3_transfer here, due to the different echos
|
||||
status = hw_ostc3_write (device, NULL, command, sizeof (command));
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
// Send the command.
|
||||
status = hw_ostc3_write (device, NULL, command + i, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the answer.
|
||||
status = hw_ostc3_read (device, NULL, answer + i, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the answer.
|
||||
const unsigned char expected = (i == 0 ? 0x4B : command[i]);
|
||||
if (answer[i] != expected) {
|
||||
ERROR (abstract->context, "Unexpected answer byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the ready byte.
|
||||
status = hw_ostc3_read (device, NULL, answer + 4, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to send the command.");
|
||||
ERROR (abstract->context, "Failed to receive the ready byte.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Give the device some time to enter service mode
|
||||
dc_iostream_sleep (device->iostream, 100);
|
||||
|
||||
// Read the response
|
||||
status = hw_ostc3_read (device, NULL, output, sizeof (output));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to receive the echo.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the response to service mode
|
||||
if (output[0] != 0x4B || output[1] != 0xAB ||
|
||||
output[2] != 0xCD || output[3] != 0xEF ||
|
||||
output[4] != S_READY) {
|
||||
ERROR (context, "Failed to verify echo.");
|
||||
// Verify the ready byte.
|
||||
if (answer[4] != S_READY) {
|
||||
ERROR (abstract->context, "Unexpected ready byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
@ -534,10 +552,24 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state)
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Read the version information.
|
||||
unsigned char version[SZ_VERSION] = {0};
|
||||
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, version, sizeof(version), NODELAY);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the version information.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Cache the descriptor.
|
||||
device->hardware = array_uint16_be(hardware + 0);
|
||||
device->feature = array_uint16_be(hardware + 2);
|
||||
device->model = hardware[4];
|
||||
device->serial = array_uint16_le (version + 0);
|
||||
if (device->hardware == OSTC4) {
|
||||
device->firmware = array_uint16_le (version + 2);
|
||||
} else {
|
||||
device->firmware = array_uint16_be (version + 2);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -642,22 +674,10 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Download the version data.
|
||||
unsigned char id[SZ_VERSION] = {0};
|
||||
rc = hw_ostc3_device_version (abstract, id, sizeof (id));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the version.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
if (device->hardware == OSTC4) {
|
||||
devinfo.firmware = array_uint16_le (id + 2);
|
||||
} else {
|
||||
devinfo.firmware = array_uint16_be (id + 2);
|
||||
}
|
||||
devinfo.serial = array_uint16_le (id + 0);
|
||||
devinfo.firmware = device->firmware;
|
||||
devinfo.serial = device->serial;
|
||||
if (device->hardware != UNKNOWN) {
|
||||
devinfo.model = device->hardware;
|
||||
} else {
|
||||
@ -1208,12 +1228,16 @@ hw_ostc3_firmware_erase (hw_ostc3_device_t *device, unsigned int addr, unsigned
|
||||
// Convert size to number of pages, rounded up.
|
||||
unsigned char blocks = ((size + SZ_FIRMWARE_BLOCK - 1) / SZ_FIRMWARE_BLOCK);
|
||||
|
||||
// Estimate the required delay. Erasing a 4K flash memory page
|
||||
// takes around 25 milliseconds.
|
||||
unsigned int delay = blocks * 25;
|
||||
|
||||
// Erase just the needed pages.
|
||||
unsigned char buffer[4];
|
||||
array_uint24_be_set (buffer, addr);
|
||||
buffer[3] = blocks;
|
||||
|
||||
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0, NODELAY);
|
||||
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0, delay);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -1227,18 +1251,56 @@ hw_ostc3_firmware_block_read (hw_ostc3_device_t *device, unsigned int addr, unsi
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int addr, const unsigned char block[], unsigned int block_size)
|
||||
hw_ostc3_firmware_block_write1 (hw_ostc3_device_t *device, unsigned int addr, const unsigned char block[], unsigned int block_size)
|
||||
{
|
||||
unsigned char buffer[3 + SZ_FIRMWARE_BLOCK];
|
||||
|
||||
// We currenty only support writing max SZ_FIRMWARE_BLOCK sized blocks.
|
||||
// We currently only support writing max SZ_FIRMWARE_BLOCK sized blocks.
|
||||
if (block_size > SZ_FIRMWARE_BLOCK)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
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, NODELAY);
|
||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE, buffer, 3 + block_size, NULL, 0, TIMEOUT);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_block_write2 (hw_ostc3_device_t *device, unsigned int address, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
if ((address % SZ_FIRMWARE_BLOCK2 != 0) ||
|
||||
(size % SZ_FIRMWARE_BLOCK2 != 0)) {
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
unsigned char buffer[3 + SZ_FIRMWARE_BLOCK2];
|
||||
array_uint24_be_set (buffer, address);
|
||||
memcpy (buffer + 3, data + nbytes, SZ_FIRMWARE_BLOCK2);
|
||||
|
||||
status = hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE2, buffer, sizeof(buffer), NULL, 0, NODELAY);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
address += SZ_FIRMWARE_BLOCK2;
|
||||
nbytes += SZ_FIRMWARE_BLOCK2;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int address, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
if (device->firmware >= 0x0309) {
|
||||
return hw_ostc3_firmware_block_write2 (device, address, data, size);
|
||||
} else {
|
||||
return hw_ostc3_firmware_block_write1 (device, address, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -1599,7 +1661,7 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < SZ_MEMORY) {
|
||||
// packet size. Can be almost arbetary size.
|
||||
// packet size. Can be almost arbitrary size.
|
||||
unsigned int len = SZ_FIRMWARE_BLOCK;
|
||||
|
||||
// Read a block
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user