From 222ba811574b7cc9166995deef42a52b9cc26c24 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 14 Feb 2013 20:02:17 +0100 Subject: [PATCH 1/5] Add a parser for Intel HEX files. --- src/Makefile.am | 1 + src/ihex.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ihex.h | 56 +++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 src/ihex.c create mode 100644 src/ihex.h diff --git a/src/Makefile.am b/src/Makefile.am index 3e1417c..2cce288 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ libdivecomputer_la_SOURCES = \ mares_puck.c \ mares_darwin.c mares_darwin_parser.c \ mares_iconhd.c mares_iconhd_parser.c \ + ihex.h ihex.c \ hw_ostc.c hw_ostc_parser.c \ hw_frog.c \ hw_ostc3.c \ diff --git a/src/ihex.c b/src/ihex.c new file mode 100644 index 0000000..5389696 --- /dev/null +++ b/src/ihex.c @@ -0,0 +1,206 @@ +/* + * libdivecomputer + * + * Copyright (C) 2013 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "ihex.h" +#include "context-private.h" +#include "checksum.h" +#include "array.h" + +struct dc_ihex_file_t { + dc_context_t *context; + FILE *fp; +}; + +dc_status_t +dc_ihex_file_open (dc_ihex_file_t **result, dc_context_t *context, const char *filename) +{ + dc_ihex_file_t *file = NULL; + + if (result == NULL || filename == NULL) { + ERROR (context, "Invalid arguments."); + return DC_STATUS_INVALIDARGS; + } + + file = malloc (sizeof (dc_ihex_file_t)); + if (file == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + file->context = context; + + file->fp = fopen (filename, "rb"); + if (file->fp == NULL) { + ERROR (context, "Failed to open the file."); + free (file); + return DC_STATUS_IO; + } + + *result = file; + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_ihex_file_read (dc_ihex_file_t *file, dc_ihex_entry_t *entry) +{ + unsigned char ascii[9 + 2 * 255 + 2] = {0}; + unsigned char data[4 + 255 + 1] = {0}; + unsigned int type, length, address; + unsigned char csum_a, csum_b; + size_t n; + + if (file == NULL || entry == NULL) { + ERROR (file ? file->context : NULL, "Invalid arguments."); + return DC_STATUS_INVALIDARGS; + } + + /* Read the start code. */ + while (1) { + n = fread (ascii, 1, 1, file->fp); + if (n != 1) { + if (feof (file->fp)) { + return DC_STATUS_DONE; + } else { + ERROR (file->context, "Failed to read the start code."); + return DC_STATUS_IO; + } + } + + if (ascii[0] == ':') + break; + + /* Ignore CR and LF characters. */ + if (ascii[0] != '\n' && ascii[0] != '\r') { + ERROR (file->context, "Unexpected character (0x%02).", ascii[0]); + return DC_STATUS_DATAFORMAT; + } + } + + /* Read the record length, address and type. */ + n = fread (ascii + 1, 1, 8, file->fp); + if (n != 8) { + ERROR (file->context, "Failed to read the header."); + return DC_STATUS_IO; + } + + /* Convert to binary representation. */ + if (array_convert_hex2bin (ascii + 1, 8, data, 4) != 0) { + ERROR (file->context, "Invalid hexadecimal character."); + return DC_STATUS_DATAFORMAT; + } + + /* Get the record length. */ + length = data[0]; + + /* Read the record payload. */ + n = fread (ascii + 9, 1, 2 * length + 2, file->fp); + if (n != 2 * length + 2) { + ERROR (file->context, "Failed to read the data."); + return DC_STATUS_IO; + } + + /* Convert to binary representation. */ + if (array_convert_hex2bin (ascii + 9, 2 * length + 2, data + 4, length + 1) != 0) { + ERROR (file->context, "Invalid hexadecimal character."); + return DC_STATUS_DATAFORMAT; + } + + /* Verify the checksum. */ + csum_a = data[4 + length]; + csum_b = ~checksum_add_uint8 (data, 4 + length, 0x00) + 1; + if (csum_a != csum_b) { + ERROR (file->context, "Unexpected checksum (0x%02x, 0x%02x).", csum_a, csum_b); + return DC_STATUS_DATAFORMAT; + } + + /* Get the record address. */ + address = array_uint16_be (data + 1); + + /* Get the record type. */ + type = data[3]; + if (type < 0 || type > 5) { + ERROR (file->context, "Invalid record type (0x%02x).", type); + return DC_STATUS_DATAFORMAT; + } + + /* Verify the length and address. */ + if (type != 0) { + unsigned int len = 0; + switch (type) { + case 1: /* End of file record. */ + len = 0; + break; + case 2: /* Extended segment address record. */ + case 4: /* Extended linear address record. */ + len = 2; + break; + case 3: /* Start segment address record. */ + case 5: /* Start linear address record. */ + len = 4; + break; + } + if (length != len || address != 0) { + ERROR (file->context, "Invalid record length or address."); + return DC_STATUS_DATAFORMAT; + } + } + + /* Set the record fields. */ + entry->type = type; + entry->address = address; + entry->length = length; + + /* Copy the record data. */ + memcpy (entry->data, data + 4, entry->length); + memset (entry->data + entry->length, 0, sizeof (entry->data) - entry->length); + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_ihex_file_reset (dc_ihex_file_t *file) +{ + if (file == NULL) { + ERROR (NULL, "Invalid arguments."); + return DC_STATUS_INVALIDARGS; + } + + rewind (file->fp); + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_ihex_file_close (dc_ihex_file_t *file) +{ + if (file) { + fclose (file->fp); + free (file); + } + + return DC_STATUS_SUCCESS; +} diff --git a/src/ihex.h b/src/ihex.h new file mode 100644 index 0000000..10cc9e6 --- /dev/null +++ b/src/ihex.h @@ -0,0 +1,56 @@ +/* + * libdivecomputer + * + * Copyright (C) 2013 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_IHEX_H +#define DC_IHEX_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dc_ihex_file_t dc_ihex_file_t; + +typedef struct dc_ihex_entry_t { + unsigned int type; + unsigned int address; + unsigned int length; + unsigned char data[255]; +} dc_ihex_entry_t; + +dc_status_t +dc_ihex_file_open (dc_ihex_file_t **file, dc_context_t *context, const char *filename); + +dc_status_t +dc_ihex_file_read (dc_ihex_file_t *file, dc_ihex_entry_t *entry); + +dc_status_t +dc_ihex_file_reset (dc_ihex_file_t *file); + +dc_status_t +dc_ihex_file_close (dc_ihex_file_t *file); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_IHEX_H */ From 14286e823664c8b8894be51bc2f18d0dd7727184 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 14 Feb 2013 21:34:36 +0100 Subject: [PATCH 2/5] Add support for updating the HW OSTC firmware. Only the bootloader V2 protocol is supported for now. --- include/libdivecomputer/hw_ostc.h | 3 + src/hw_ostc.c | 289 ++++++++++++++++++++++++++++++ src/libdivecomputer.symbols | 1 + 3 files changed, 293 insertions(+) diff --git a/include/libdivecomputer/hw_ostc.h b/include/libdivecomputer/hw_ostc.h index 6e0a8c8..4dfb523 100644 --- a/include/libdivecomputer/hw_ostc.h +++ b/include/libdivecomputer/hw_ostc.h @@ -67,6 +67,9 @@ hw_ostc_extract_dives (dc_device_t *device, const unsigned char data[], unsigned dc_status_t hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int frog); +dc_status_t +hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/hw_ostc.c b/src/hw_ostc.c index f95601d..c005e2d 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -29,6 +29,7 @@ #include "serial.h" #include "checksum.h" #include "array.h" +#include "ihex.h" #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable) @@ -37,6 +38,10 @@ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ ) +#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +#define MAXRETRIES 9 + #define FW_190 0x015A #define SZ_MD2HASH 18 @@ -45,6 +50,13 @@ #define SZ_FW_190 0x8000 #define SZ_FW_NEW 0x10000 +#define SZ_FIRMWARE 0x17F40 +#define SZ_BLOCK 0x40 + +#define ACK 0x4B /* "K" for ok */ +#define NAK 0x4E /* "N" for not ok */ +#define PICTYPE 0x57 /* PIC type (18F4685) */ + #define WIDTH 320 #define HEIGHT 240 #define BLACK 0x00 @@ -56,6 +68,11 @@ typedef struct hw_ostc_device_t { unsigned char fingerprint[5]; } hw_ostc_device_t; +typedef struct hw_ostc_firmware_t { + unsigned char data[SZ_FIRMWARE]; + unsigned char bitmap[SZ_FIRMWARE / SZ_BLOCK]; +} hw_ostc_firmware_t; + static dc_status_t hw_ostc_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); static dc_status_t hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); @@ -652,3 +669,275 @@ hw_ostc_extract_dives (dc_device_t *abstract, const unsigned char data[], unsign return DC_STATUS_SUCCESS; } + + +static dc_status_t +hw_ostc_firmware_readfile (hw_ostc_firmware_t *firmware, dc_context_t *context, const char *filename) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + if (firmware == NULL) { + ERROR (context, "Invalid arguments."); + return DC_STATUS_INVALIDARGS; + } + + // Initialize the buffers. + memset (firmware->data, 0xFF, sizeof (firmware->data)); + memset (firmware->bitmap, 0x00, sizeof (firmware->bitmap)); + + // Open the hex file. + dc_ihex_file_t *file = NULL; + rc = dc_ihex_file_open (&file, context, filename); + if (rc != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to open the hex file."); + return rc; + } + + // Read the hex file. + unsigned int lba = 0; + dc_ihex_entry_t entry; + while ((rc = dc_ihex_file_read (file, &entry)) == DC_STATUS_SUCCESS) { + if (entry.type == 0) { + // Data record. + unsigned int address = (lba << 16) + entry.address; + if (address + entry.length > SZ_FIRMWARE) { + WARNING (context, "Ignoring out of range record (0x%08x,%u).", address, entry.length); + continue; + } + + // Copy the record to the buffer. + memcpy (firmware->data + address, entry.data, entry.length); + + // Mark the corresponding blocks in the bitmap. + unsigned int begin = address / SZ_BLOCK; + unsigned int end = (address + entry.length + SZ_BLOCK - 1) / SZ_BLOCK; + for (unsigned int i = begin; i < end; ++i) { + firmware->bitmap[i] = 1; + } + } else if (entry.type == 1) { + // End of file record. + break; + } else if (entry.type == 4) { + // Extended linear address record. + lba = array_uint16_be (entry.data); + } else { + ERROR (context, "Unexpected record type."); + dc_ihex_file_close (file); + return DC_STATUS_DATAFORMAT; + } + } + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { + ERROR (context, "Failed to read the record."); + dc_ihex_file_close (file); + return rc; + } + + // Close the file. + dc_ihex_file_close (file); + + // Verify the presence of the first block. + if (firmware->bitmap[0] == 0) { + ERROR (context, "No first data block."); + return DC_STATUS_DATAFORMAT; + } + + // Setup the last block. + // Copy the "goto main" instruction, stored in the first 8 bytes of the hex + // file, to the end of the last block at address 0x17F38. This last block + // needs to be present, regardless of whether it's included in the hex file + // or not! + memset (firmware->data + SZ_FIRMWARE - SZ_BLOCK, 0xFF, SZ_BLOCK - 8); + memcpy (firmware->data + SZ_FIRMWARE - 8, firmware->data, 8); + firmware->bitmap[C_ARRAY_SIZE(firmware->bitmap) - 1] = 1; + + // Setup the first block. + // Copy the hardcoded "goto 0x17F40" instruction to the start of the first + // block at address 0x00000. + const unsigned char header[] = {0xA0, 0xEF, 0xBF, 0xF0}; + memcpy (firmware->data, header, sizeof (header)); + + return rc; +} + + +static dc_status_t +hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) +{ + dc_device_t *abstract = (dc_device_t *) device; + + // Send the command. + unsigned char command[1] = {0xC1}; + int n = serial_write (device->port, command, sizeof (command)); + if (n != sizeof (command)) { + ERROR (abstract->context, "Failed to send the command."); + return EXITCODE (n); + } + + // Read the response. + unsigned char answer[2] = {0}; + n = serial_read (device->port, answer, sizeof (answer)); + if (n != sizeof (answer)) { + ERROR (abstract->context, "Failed to receive the response."); + return EXITCODE (n); + } + + // Verify the response. + const unsigned char expected[2] = {PICTYPE, ACK}; + if (memcmp (answer, expected, sizeof (expected)) != 0) { + ERROR (abstract->context, "Unexpected response."); + return DC_STATUS_PROTOCOL; + } + + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +hw_ostc_firmware_setup (hw_ostc_device_t *device) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + unsigned int nretries = 0; + while ((rc = hw_ostc_firmware_setup_internal (device)) != DC_STATUS_SUCCESS) { + if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) + break; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + break; + } + + return rc; +} + + +static dc_status_t +hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, unsigned int size) +{ + dc_device_t *abstract = (dc_device_t *) device; + + // Send the packet. + int n = serial_write (device->port, data, size); + if (n != size) { + ERROR (abstract->context, "Failed to send the packet."); + return EXITCODE (n); + } + + // Read the response. + unsigned char answer[1] = {0}; + n = serial_read (device->port, answer, sizeof (answer)); + if (n != sizeof (answer)) { + ERROR (abstract->context, "Failed to receive the response."); + return EXITCODE (n); + } + + // Verify the response. + const unsigned char expected[] = {ACK}; + if (memcmp (answer, expected, sizeof (expected)) != 0) { + ERROR (abstract->context, "Unexpected response."); + return DC_STATUS_PROTOCOL; + } + + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +hw_ostc_firmware_write (hw_ostc_device_t *device, unsigned char *data, unsigned int size) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + unsigned int nretries = 0; + while ((rc = hw_ostc_firmware_write_internal (device, data, size)) != DC_STATUS_SUCCESS) { + if (rc != DC_STATUS_TIMEOUT && rc != DC_STATUS_PROTOCOL) + break; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + break; + } + + return rc; +} + + +dc_status_t +hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; + dc_context_t *context = (abstract ? abstract->context : NULL); + + if (!ISINSTANCE (abstract)) + return DC_STATUS_INVALIDARGS; + + // Allocate memory for the firmware data. + hw_ostc_firmware_t *firmware = (hw_ostc_firmware_t *) malloc (sizeof (hw_ostc_firmware_t)); + if (firmware == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Read the hex file. + rc = hw_ostc_firmware_readfile (firmware, context, filename); + if (rc != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to read the firmware file."); + free (firmware); + return rc; + } + + // Temporary set a relative short timeout. The command to setup the + // bootloader needs to be send repeatedly, until the response packet is + // received. Thus the time between each two attempts is directly controlled + // by the timeout value. + serial_set_timeout (device->port, 300); + + // Setup the bootloader. + rc = hw_ostc_firmware_setup (device); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to setup the bootloader."); + free (firmware); + return rc; + } + + // Increase the timeout again. + serial_set_timeout (device->port, 1000); + + // Enable progress notifications. + dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; + progress.maximum = C_ARRAY_SIZE(firmware->bitmap); + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + for (unsigned int i = 0; i < C_ARRAY_SIZE(firmware->bitmap); ++i) { + // Skip empty blocks. + if (firmware->bitmap[i] == 0) + continue; + + // Create the packet. + unsigned int address = i * SZ_BLOCK; + unsigned char packet[4 + SZ_BLOCK + 1] = { + (address >> 16) & 0xFF, + (address >> 8) & 0xFF, + (address ) & 0xFF, + SZ_BLOCK + }; + memcpy (packet + 4, firmware->data + address, SZ_BLOCK); + packet[sizeof (packet) - 1] = ~checksum_add_uint8 (packet, 4 + SZ_BLOCK, 0x00) + 1; + + // Send the packet. + rc = hw_ostc_firmware_write (device, packet, sizeof (packet)); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the packet."); + free (firmware); + return rc; + } + + // Update and emit a progress event. + progress.current = i + 1; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + } + + free (firmware); + + return DC_STATUS_SUCCESS; +} diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 2188971..525f193 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -140,6 +140,7 @@ hw_ostc_device_eeprom_write hw_ostc_device_reset hw_ostc_device_screenshot hw_ostc_extract_dives +hw_ostc_device_fwupdate hw_frog_device_open hw_frog_device_version hw_frog_device_clock From bc89e0a3de4e6a7f34ef9d556082ec59853f51ff Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 26 Jul 2013 22:39:56 +0200 Subject: [PATCH 3/5] Autodetect the bootloader protocol variant. When updating the firmware while the OSTC is running in normal mode, the V2 protocol should be used. However, the OSTC can also be rebooted from the menu or reset using the magnetic switch, and then the V1 protocol should be used. The only difference with the V2 protocol is the slower baudrate (19200 vs 115200). True autodetection of the protocol variant is difficult, because the bootloader will abort the firmware update when not receiving a 0xC1 byte. But we can still take advantage of the fact that the normal firmware does ignore any 0xC1 bytes sent at the wrong baudrate, and probe with the V1 protocol first. If the bootloader is already running, it will respond immediately and we're done. If the normal firmware is still running, it won't respond and the probing with the V1 protocol will fail. If we then switch to the V2 protocol, the firmware update will continue as before. The result is a firmware updater which supports both bootloader protocols without requiring any manual configuration. --- src/hw_ostc.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/hw_ostc.c b/src/hw_ostc.c index c005e2d..4a389ad 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -793,7 +793,7 @@ hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) static dc_status_t -hw_ostc_firmware_setup (hw_ostc_device_t *device) +hw_ostc_firmware_setup (hw_ostc_device_t *device, unsigned int maxretries) { dc_status_t rc = DC_STATUS_SUCCESS; @@ -803,7 +803,7 @@ hw_ostc_firmware_setup (hw_ostc_device_t *device) break; // Abort if the maximum number of retries is reached. - if (nretries++ >= MAXRETRIES) + if (nretries++ >= maxretries) break; } @@ -893,7 +893,21 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) serial_set_timeout (device->port, 300); // Setup the bootloader. - rc = hw_ostc_firmware_setup (device); + const unsigned int baudrates[] = {19200, 115200}; + for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { + // Adjust the baudrate. + if (serial_configure (device->port, baudrates[i], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) { + ERROR (abstract->context, "Failed to set the terminal attributes."); + free (firmware); + return DC_STATUS_IO; + } + + // Try to setup the bootloader. + unsigned int maxretries = (i == 0 ? 1 : MAXRETRIES); + rc = hw_ostc_firmware_setup (device, maxretries); + if (rc == DC_STATUS_SUCCESS) + break; + } if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to setup the bootloader."); free (firmware); From 8e1a8c14a3222301fb873ed78008444266951dae Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 27 Jul 2013 06:54:14 +0200 Subject: [PATCH 4/5] Add a small example application. --- examples/Makefile.am | 3 + examples/hw_ostc_fwupdate.c | 126 ++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 examples/hw_ostc_fwupdate.c diff --git a/examples/Makefile.am b/examples/Makefile.am index fc0664d..2283028 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -21,6 +21,7 @@ bin_PROGRAMS = \ darwin \ iconhd \ ostc \ + ostc-fwupdate \ frog \ edy \ leonardo \ @@ -72,6 +73,8 @@ iconhd_SOURCES = mares_iconhd_test.c $(COMMON) ostc_SOURCES = hw_ostc_test.c $(COMMON) +ostc_fwupdate_SOURCES = hw_ostc_fwupdate.c $(COMMON) + frog_SOURCES = hw_frog_test.c $(COMMON) edy_SOURCES = cressi_edy_test.c $(COMMON) diff --git a/examples/hw_ostc_fwupdate.c b/examples/hw_ostc_fwupdate.c new file mode 100644 index 0000000..a9e7fde --- /dev/null +++ b/examples/hw_ostc_fwupdate.c @@ -0,0 +1,126 @@ +/* + * libdivecomputer + * + * Copyright (C) 2013 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include // fopen, fwrite, fclose +#include + +#include + +#include "utils.h" +#include "common.h" + +static void +event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) +{ + const dc_event_progress_t *progress = (dc_event_progress_t *) data; + + switch (event) { + case DC_EVENT_PROGRESS: + message ("Event: progress %3.2f%% (%u/%u)\n", + 100.0 * (double) progress->current / (double) progress->maximum, + progress->current, progress->maximum); + break; + default: + break; + } +} + +static dc_status_t +fwupdate (const char *name, const char *hexfile) +{ + dc_context_t *context = NULL; + dc_device_t *device = NULL; + + dc_context_new (&context); + dc_context_set_loglevel (context, DC_LOGLEVEL_ALL); + dc_context_set_logfunc (context, logfunc, NULL); + + message ("hw_ostc_device_open\n"); + dc_status_t rc = hw_ostc_device_open (&device, context, name); + if (rc != DC_STATUS_SUCCESS) { + WARNING ("Error opening serial port."); + dc_context_free (context); + return rc; + } + + message ("dc_device_set_events.\n"); + rc = dc_device_set_events (device, DC_EVENT_PROGRESS, event_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + WARNING ("Error registering the event handler."); + dc_device_close (device); + dc_context_free (context); + return rc; + } + + message ("hw_ostc_device_fwupdate\n"); + rc = hw_ostc_device_fwupdate (device, hexfile); + if (rc != DC_STATUS_SUCCESS) { + WARNING ("Error flashing firmware."); + dc_device_close (device); + dc_context_free (context); + return rc; + } + + message ("dc_device_close\n"); + rc = dc_device_close (device); + if (rc != DC_STATUS_SUCCESS) { + WARNING ("Cannot close device."); + dc_context_free (context); + return rc; + } + + dc_context_free (context); + + return DC_STATUS_SUCCESS; +} + + +int main(int argc, char *argv[]) +{ + message_set_logfile ("OSTC-FWUPDATE.LOG"); + +#ifdef _WIN32 + const char* name = "COM1"; +#else + const char* name = "/dev/ttyUSB0"; +#endif + const char *hexfile = NULL; + + if (argc > 1) { + name = argv[1]; + } + if (argc > 2) { + hexfile = argv[2]; + } + + message ("DEVICE=%s\n", name); + message ("HEXFILE=%s\n", hexfile); + + dc_status_t a = fwupdate (name, hexfile); + + message ("SUMMARY\n"); + message ("-------\n"); + message ("fwupdate: %s\n", errmsg (a)); + + message_set_logfile (NULL); + + return 0; +} From 22a8bc70ea220e6dac796527db5e5614b17c61c1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 21 Aug 2013 10:03:54 +0200 Subject: [PATCH 5/5] Add a warning to the firmware update code. --- src/hw_ostc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hw_ostc.c b/src/hw_ostc.c index 4a389ad..fac8ebc 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -860,7 +860,14 @@ hw_ostc_firmware_write (hw_ostc_device_t *device, unsigned char *data, unsigned return rc; } - +/* + * Think twice before modifying the code for updating the ostc firmware! + * It has been carefully developed and tested with assistance from + * Heinrichs-Weikamp, using a special development unit. If you start + * experimenting with a normal unit and accidentally screw up, you might + * brick the device permanently and turn it into an expensive + * paperweight. You have been warned! + */ dc_status_t hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) {