Hello,
I developped a more flexible interface to fill the buffer and upgrade the system from a pusher (like a webserver).
It simply need three members calls. Here is the principle :
Flasher.begin();
File file = FS.open("myfile.hex", FILE_READ);
while(file.available()) {
char buffer[512];
size_t r = file.read(buffer, 512);
if (!Flasher.addChunk(buffer, r)) {
Flasher.abort();
break;
}
}
file.close();
if (Flasher.finish()) {
// Flash OK
} else {
// Flash NOK
Flasher.abort();
}
You can append the "buffer" char by char or chunk by chunk.
Here the implementation :
//******************************************************************************
// FXUTIL.H -- FlasherX utility functions
//******************************************************************************
#ifndef FXUTIL_H_
#define FXUTIL_H_
#include <Arduino.h>
#include <list>
extern "C" {
#include "FlashTxx.h" // TLC/T3x/T4x/TMM flash primitives
}
//#include "Utils.h"
#define LOGF(...)
typedef struct {
char buffer[96];
int bufferlen;
bool complete;
uint32_t line;
} flasher_line_t;
typedef struct {
char *data; // pointer to array allocated elsewhere
unsigned int addr; // address in intel hex record
unsigned int code; // intel hex record type (0=data, etc.)
unsigned int num; // number of data bytes in intel hex record
uint32_t base; // base address to be added to intel hex 16-bit addr
uint32_t min; // min address in hex file
uint32_t max; // max address in hex file
int eof; // set true on intel hex EOF (code = 1)
int lines; // number of hex records received
} hex_info_t;
class FlasherClass {
public:
FlasherClass();
bool begin();
bool addChunk(const char *buffer, int bufferlen);
bool finish();
void abort();
protected:
uint32_t _buffer_addr;
uint32_t _buffer_size;
std::list<flasher_line_t> _lines;
char _hex_data[32] __attribute__((aligned(8))); // buffer for hex data
hex_info_t _hex;
};
extern FlasherClass Flasher;
#endif
//******************************************************************************
// FXUTIL.CPP -- FlasherX utility functions
//******************************************************************************
#include <Arduino.h>
#include <stdio.h> // sscanf(), etc.
#include <string.h> // strlen(), etc.
#include "FXUtil.h"
//******************************************************************************
// process_hex_record() process record and return okay (0) or error (1)
//******************************************************************************
int process_hex_record(hex_info_t *hex)
{
if (hex->code == 0) { // data -- update min/max address so far
if (hex->base + hex->addr + hex->num > hex->max)
hex->max = hex->base + hex->addr + hex->num;
if (hex->base + hex->addr < hex->min)
hex->min = hex->base + hex->addr;
}
else if (hex->code == 1) { // EOF (:flash command not received yet)
hex->eof = 1;
}
else if (hex->code == 2) { // extended segment address (top 16 of 24-bit addr)
hex->base = ((hex->data[0] << 8) | hex->data[1]) << 4;
}
else if (hex->code == 3) { // start segment address (80x86 real mode only)
return 1;
}
else if (hex->code == 4) { // extended linear address (top 16 of 32-bit addr)
hex->base = ((hex->data[0] << 8) | hex->data[1]) << 16;
}
else if (hex->code == 5) { // start linear address (32-bit big endian addr)
hex->base = (hex->data[0] << 24) | (hex->data[1] << 16)
| (hex->data[2] << 8) | (hex->data[3] << 0);
}
else {
return 1;
}
return 0;
}
//******************************************************************************
// Intel Hex record foramt:
//
// Start code: one character, ASCII colon ':'.
// Byte count: two hex digits, number of bytes (hex digit pairs) in data field.
// Address: four hex digits
// Record type: two hex digits, 00 to 05, defining the meaning of the data field.
// Data: n bytes of data represented by 2n hex digits.
// Checksum: two hex digits, computed value used to verify record has no errors.
//
// Examples:
// :10 9D30 00 711F0000AD38000005390000F5460000 35
// :04 9D40 00 01480000 D6
// :00 0000 01 FF
//******************************************************************************
/* Intel HEX read/write functions, Paul Stoffregen, paul@ece.orst.edu */
/* This code is in the public domain. Please retain my name and */
/* email address in distributed copies, and let me know about any bugs */
/* I, Paul Stoffregen, give no warranty, expressed or implied for */
/* this software and/or documentation provided, including, without */
/* limitation, warranty of merchantability and fitness for a */
/* particular purpose. */
// type modifications by Jon Zeeff
/* parses a line of intel hex code, stores the data in bytes[] */
/* and the beginning address in addr, and returns a 1 if the */
/* line was valid, or a 0 if an error occured. The variable */
/* num gets the number of bytes that were stored into bytes[] */
int parse_hex_line(const char *theline, char *bytes,
unsigned int *addr, unsigned int *num, unsigned int *code)
{
unsigned sum, len, cksum;
const char *ptr;
int temp;
*num = 0;
if (theline[0] != ':')
return 0;
if (strlen(theline) < 11)
return 0;
ptr = theline + 1;
if (!sscanf(ptr, "%02x", &len))
return 0;
ptr += 2;
if (strlen(theline) < (11 + (len * 2)))
return 0;
if (!sscanf(ptr, "%04x", (unsigned int *)addr))
return 0;
ptr += 4;
/* Serial.printf("Line: length=%d Addr=%d\n", len, *addr); */
if (!sscanf(ptr, "%02x", code))
return 0;
ptr += 2;
sum = (len & 255) + ((*addr >> 8) & 255) + (*addr & 255) + (*code & 255);
while (*num != len)
{
if (!sscanf(ptr, "%02x", &temp))
return 0;
bytes[*num] = temp;
ptr += 2;
sum += bytes[*num] & 255;
(*num)++;
if (*num >= 256)
return 0;
}
if (!sscanf(ptr, "%02x", &cksum))
return 0;
if (((sum & 255) + (cksum & 255)) & 255)
return 0; /* checksum error */
return 1;
}
FlasherClass::FlasherClass()
: _buffer_addr(0)
, _buffer_size(0)
{
}
bool FlasherClass::begin()
{
_lines.clear();
_hex.data = _hex_data;
_hex.addr = 0;
_hex.num = 0;
_hex.code = 0;
_hex.base = 0;
_hex.min = 0xFFFFFFFF;
_hex.max = 0;
_hex.eof = 0;
_hex.lines = 0;
if (firmware_buffer_init(&_buffer_addr, &_buffer_size) == 0)
return false;
LOGF("FlasherClass::begin() : _buffer_addr=%08X _buffer_size=%u\n", _buffer_addr, _buffer_size);
return true;
}
bool FlasherClass::addChunk(const char *buffer, int bufferlen)
{
if (bufferlen == 0)
return false;
//LOGF("FlasherClass::addChunk() : ");
for (int i = 0; i < bufferlen; i++) {
// If there is no lines in the lines list
if (_lines.empty()) {
flasher_line_t l = { "", 0, false, 1 };
_lines.push_front(l);
//LOGF("0");
}
// If end of line
if (buffer[i] == '\n' || buffer[i] == '\r') {
// Create a new line only if the current one is not empty
if (_lines.front().bufferlen > 0) {
_lines.front().complete = true;
flasher_line_t l = { "", 0, false, _lines.front().line + 1 };
_lines.push_front(l);
//LOGF("1");
}
continue;
}
// Append to line
if (_lines.front().bufferlen < sizeof(flasher_line_t::buffer))
_lines.front().buffer[_lines.front().bufferlen++] = buffer[i];
}
//LOGF("2");
while (_lines.back().complete) {
if (parse_hex_line((const char *)_lines.back().buffer, _hex.data, &_hex.addr, &_hex.num, &_hex.code) == 0) {
LOGF("FlasherClass : parse_hex_line() error\n");
_lines.pop_back();
return false;
}
//LOGF("3");
_lines.pop_back();
if (process_hex_record(&_hex) != 0) {
LOGF("FlasherClass : invalid hex code %d\n", _hex.code);
return false;
}
if (_hex.code != 0)
continue;
//LOGF("4");
uint32_t addr = _buffer_addr + _hex.base + _hex.addr - FLASH_BASE_ADDR;
if (_hex.max > (FLASH_BASE_ADDR + _buffer_size)) {
LOGF("FlasherClass : max address %08lX too large\n", _hex.max);
return false;
}
if (!IN_FLASH(_buffer_addr)) {
memcpy((void *)addr, (void *)_hex.data, _hex.num);
//LOGF("5");
}
if (IN_FLASH(_buffer_addr)) {
int error = flash_write_block(addr, _hex.data, _hex.num);
if (error) {
LOGF("FlasherClass : error %02X in flash_write_block()\n", error);
return false;
}
//LOGF("6");
}
_hex.lines++;
}
//LOGF("7 - %d %d\n", _lines.size(), _lines.front().line);
return true;
}
bool FlasherClass::finish()
{
LOGF("FlasherClass::finish()\n");
// check FSEC value in new code -- abort if incorrect
#if defined(KINETISK) || defined(KINETISL)
uint32_t value = *(uint32_t *)(0x40C + _buffer_addr);
if (value == 0xfffff9de) {
LOGF("new code contains correct FSEC value %08lX\n", value);
}
else {
LOGF("abort - FSEC value %08lX should be FFFFF9DE\n", value);
return false;
}
#endif
// check FLASH_ID in new code - abort if not found
if (check_flash_id(_buffer_addr, _hex.max - _hex.min)) {
LOGF("FlasherClass : new code contains correct target ID %s\n", FLASH_ID);
}
else {
LOGF("FlasherClass : new code missing string %s\n", FLASH_ID);
return false;
}
flash_move(FLASH_BASE_ADDR, _buffer_addr, _hex.max - _hex.min);
// NEVER RETURN ?
//firmware_buffer_free(_buffer_addr, _buffer_size);
return true;
}
void FlasherClass::abort()
{
firmware_buffer_free(_buffer_addr, _buffer_size);
}
FlasherClass Flasher;
`
Hello, I developped a more flexible interface to fill the buffer and upgrade the system from a pusher (like a webserver). It simply need three members calls. Here is the principle :
You can append the "buffer" char by char or chunk by chunk.
Here the implementation :