216 lines
5.9 KiB
C++
216 lines
5.9 KiB
C++
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include "programmer.h"
|
|
#define trace printf
|
|
|
|
Programmer::Programmer() : BaseLayer(), ring(), ihx(),
|
|
line_len(0u), line_index(0u), begin_addr(0u), file_len(0u) {
|
|
file_pool = new uint8_t [MaxPages * PageSize];
|
|
memory_pool = new uint8_t [MaxPages * PageSize];
|
|
}
|
|
Programmer::~Programmer() {
|
|
delete [] memory_pool;
|
|
delete [] file_pool;
|
|
}
|
|
void Programmer::Flush() {
|
|
char c;
|
|
while (ring.Read(c));
|
|
}
|
|
|
|
uint32_t Programmer::Up(const char * data, const uint32_t len) {
|
|
for (unsigned n=0u; n<len; n++) ring.Write (data [n]);
|
|
return len;
|
|
}
|
|
|
|
void Programmer::read_flash_binary(const char * name, const unsigned int blen) {
|
|
file_len = blen * PageSize;
|
|
if (file_len > (MaxPages * PageSize)) {
|
|
fprintf(stderr, "read request too long - %d\n", file_len);
|
|
}
|
|
printf("read %d bytes...\n", file_len);
|
|
read_flash(file_len);
|
|
FILE * out = fopen(name, "w");
|
|
int r = fwrite(memory_pool, 1, file_len, out);
|
|
printf("writen %d bytes to %s\n", r, name);
|
|
fclose(out);
|
|
}
|
|
void Programmer::verify_flash_binary(const char * name) {
|
|
if (!open_file_for_read(name)) return;
|
|
printf("verify %d bytes...\n", file_len);
|
|
read_flash(file_len);
|
|
unsigned err = 0u;
|
|
for (unsigned n=0u; n<file_len; n++) {
|
|
if (file_pool[n] != memory_pool[n]) {
|
|
fprintf(stderr, "err at 0x%06X: 0x%02X != 0x%02X\n", n, file_pool[n], memory_pool[n]);
|
|
err += 1u;
|
|
}
|
|
}
|
|
if (err) printf("verify errors: %d\n", err);
|
|
else printf("flash OK\n");
|
|
}
|
|
void Programmer::write_flash_binary(const char * name) {
|
|
if (!open_file_for_read(name)) return;
|
|
uint32_t blocks = file_len / PageSize;
|
|
if (file_len % PageSize) blocks += 1u;
|
|
erase_blocks (blocks);
|
|
|
|
begin_addr = 0u;
|
|
StartOperation(begin_addr);
|
|
unsigned ofs = 0u, rem = file_len, chunk;
|
|
while (true) {
|
|
chunk = rem > 0x20 ? 0x20 : rem;
|
|
unsigned rl = ihx.DataRecord(strbuf, file_pool + begin_addr + ofs, chunk);
|
|
SendString(strbuf, rl);
|
|
while (!GetLine());
|
|
RowTypes t = ihx.parseRecord(line, line_len);
|
|
if (t != ackRecord) fprintf(stderr, "BAD WriteOperation 0x%X\n", begin_addr + ofs);
|
|
ihx.AddOffset(chunk);
|
|
ofs += chunk;
|
|
rem -= chunk;
|
|
printf("write at 0x%04X \r", begin_addr + ofs);
|
|
fflush(stdout);
|
|
if (ofs >= ihxPage) {
|
|
begin_addr += ihxPage;
|
|
StartOperation(begin_addr);
|
|
ofs = 0u;
|
|
}
|
|
if (rem == 0u) break;
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void Programmer::SendString(const char * ptr, const uint32_t len) {
|
|
/*
|
|
fprintf(stdout, "TX");
|
|
int r = fwrite (ptr, 1, len, stdout); (void) r;
|
|
fflush (stdout);
|
|
*/
|
|
unsigned ofs = 0u, res = len;
|
|
while (res) {
|
|
const unsigned n = Down (ptr + ofs, res);
|
|
ofs += n;
|
|
res -= n;
|
|
}
|
|
}
|
|
bool Programmer::open_file_for_read(const char * name) {
|
|
struct stat prop;
|
|
const int r = stat (name, & prop);
|
|
if (r) {
|
|
fprintf(stderr, "file %s not exists.", name);
|
|
return false;
|
|
}
|
|
const unsigned flen = prop.st_size;
|
|
if (flen > (MaxPages * PageSize)) {
|
|
fprintf(stderr, "verify/write request too long - %d\n", flen);
|
|
return false;
|
|
}
|
|
FILE * in = fopen (name, "r");
|
|
if (!in) {
|
|
fprintf(stderr, "file %s not open for read.", name);
|
|
return false;
|
|
}
|
|
const int l = fread (file_pool, 1, flen, in);
|
|
printf("%s: readen = %d bytes\n", name, l);
|
|
fclose(in);
|
|
file_len = flen;
|
|
return true;
|
|
}
|
|
bool Programmer::GetLine() {
|
|
char c;
|
|
while (ring.Read(c)) {
|
|
line [line_index++] = c;
|
|
if (c == '\n') {
|
|
line_len = line_index;
|
|
/*
|
|
fprintf(stdout, "RX");
|
|
int r = fwrite (line, 1, line_len, stdout); (void) r;
|
|
fflush (stdout);
|
|
*/
|
|
line_index = 0u;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
void Programmer::ParseLine() {
|
|
RowTypes t = ihx.parseRecord (line, line_len);
|
|
switch (t) {
|
|
case dataRecord: AcquireDataRecord (); break;
|
|
case reqRecord: AcquireReqRecord (); break;
|
|
default:
|
|
trace ("BAD record 0x%02X\r\n", t);
|
|
break;
|
|
}
|
|
}
|
|
void Programmer::StartOperation(const unsigned addr) {
|
|
uint32_t res = ihx.ElaRecord(strbuf, addr);
|
|
SendString (strbuf, res);
|
|
while (!GetLine());
|
|
RowTypes t = ihx.parseRecord(line, line_len);
|
|
if (t != ackRecord) fprintf(stderr, "BAD StartOperation\n");
|
|
}
|
|
|
|
void Programmer::AcquireDataRecord() {
|
|
uint32_t ofs, len;
|
|
uint8_t * ptr = ihx.getDataRow (ofs, len);
|
|
memcpy (memory_pool + begin_addr + ofs, ptr, len);
|
|
if (len) {
|
|
ihx.AddOffset (len); // posun offsetu az po ack
|
|
return;
|
|
}
|
|
}
|
|
void Programmer::AcquireReqRecord() {
|
|
static constexpr unsigned chunk_size = 0x10;
|
|
uint8_t data [chunk_size];
|
|
uint32_t res = 0x10, len, ofs;
|
|
len = chunk_size;
|
|
ihx.getOffset (ofs);
|
|
//trace ("AcquireReqRecord: %04X, len=%d\r\n", ofs, len);
|
|
memcpy (data, memory_pool + begin_addr + ofs, len);
|
|
res = ihx.DataRecord (strbuf, data, len);
|
|
SendString (strbuf, res);
|
|
}
|
|
void Programmer::read_flash(const unsigned len) {
|
|
StartOperation(begin_addr);
|
|
while (true) {
|
|
const uint32_t res = ihx.BTxRecord (strbuf, reqRecord);
|
|
SendString (strbuf, res);
|
|
while (!GetLine());
|
|
ParseLine();
|
|
uint32_t ofs;
|
|
ihx.getOffset(ofs);
|
|
printf("read flash at 0x%X \r", begin_addr + ofs);
|
|
fflush(stdout);
|
|
if (ofs >= ihxPage) {
|
|
begin_addr += ihxPage;
|
|
StartOperation(begin_addr);
|
|
ofs = 0u;
|
|
}
|
|
if ((begin_addr + ofs) >= len) break;
|
|
}
|
|
printf("\n");
|
|
}
|
|
void Programmer::Erase(const unsigned int n) {
|
|
uint32_t ofs, addr = n * 0x10u; // adresa zmenšena 256x
|
|
ihx.getOffset(ofs);
|
|
ihx.AddOffset(addr - ofs);
|
|
uint32_t res = ihx.BTxRecord (strbuf, ersRecord);
|
|
SendString (strbuf, res);
|
|
}
|
|
|
|
void Programmer::erase_blocks(const unsigned int blocks) {
|
|
StartOperation(0u);
|
|
for (unsigned n=0u; n<blocks; n++) {
|
|
Erase(n);
|
|
while (!GetLine());
|
|
RowTypes t = ihx.parseRecord(line, line_len);
|
|
if (t != ackRecord) fprintf(stderr, "BAD EraseOperation %d\n", n);
|
|
printf("erase block %d \r", n+1);
|
|
fflush(stdout);
|
|
}
|
|
printf("\n");
|
|
}
|