refactoring programmer
This commit is contained in:
parent
b9052ca694
commit
b9a3524daf
9 changed files with 284 additions and 364 deletions
|
@ -16,7 +16,11 @@ class MemoryBase {
|
||||||
return flash.ReadBlock(addr, reinterpret_cast<uint8_t*> (ptr), len);
|
return flash.ReadBlock(addr, reinterpret_cast<uint8_t*> (ptr), len);
|
||||||
}
|
}
|
||||||
void Erase (const uint32_t blok) {
|
void Erase (const uint32_t blok) {
|
||||||
flash.EraseSector(blok);
|
/* Flash používá 24-bitovou adresu počátku bloku, zde máme k dispozici
|
||||||
|
* jen 16-bitový offset. Takže to jen natáhneme 256 krát. Software
|
||||||
|
* tomu musí odpovídat.
|
||||||
|
* */
|
||||||
|
flash.EraseSector(blok << 8);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
/*********************************************************************************
|
/*********************************************************************************
|
||||||
* Do mluvícího teploměru bylo potřeba nějak dostat data do externí flash.
|
* Do mluvícího teploměru bylo potřeba nějak dostat data do externí flash.
|
||||||
* Zde je základ programátoru, je to recyklovaný kód, takže zatím to umí jen
|
* Zde je základ programátoru, je to recyklovaný kód, takže zatím to umí jen
|
||||||
* binární soubory do 64KiB, ale patrně nebude problém dopsat to na větší délku.
|
* binární soubory. Dodělat Intel hex není problém, ale nepotřebuji to.
|
||||||
|
* Umí to jen nor flash se stránkou 4096 bytů, předpokládaná velikost je 32Mbit.
|
||||||
* Software je dost surový, bez kontrol, prostě jen aby to trochu fungovalo.
|
* Software je dost surový, bez kontrol, prostě jen aby to trochu fungovalo.
|
||||||
**********************************************************************************/
|
**********************************************************************************/
|
||||||
static GpioClass led (GPIOB, 8);
|
static GpioClass led (GPIOB, 8);
|
||||||
|
|
|
@ -7,7 +7,8 @@ MFLAGS = -o $(PR)
|
||||||
|
|
||||||
all: $(PR)
|
all: $(PR)
|
||||||
|
|
||||||
OBJECTS = main.o usart.o baud.o linkprotocol.o intelhex.o
|
OBJECTS = main.o usart.o baud.o programmer.o intelhex.o
|
||||||
|
#linkprotocol.o
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) -c $(CFLAGS) $< -o $@
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
#ifndef HELPERS_H
|
|
||||||
#define HELPERS_H
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "fifo.h"
|
|
||||||
#include "baselayer.h"
|
|
||||||
|
|
||||||
class MemoryBase {
|
|
||||||
unsigned lenght;
|
|
||||||
unsigned char * data;
|
|
||||||
public:
|
|
||||||
explicit MemoryBase (const unsigned len) noexcept : lenght(len) {
|
|
||||||
data = new unsigned char [lenght];
|
|
||||||
}
|
|
||||||
~MemoryBase () { delete [] data; }
|
|
||||||
uint32_t getLenght () { return lenght; }
|
|
||||||
uint8_t * getData () { return data; }
|
|
||||||
uint32_t Write (const uint32_t addr, const void * ptr, const uint32_t len) {
|
|
||||||
printf("Readen at 0x%04X \r", addr);
|
|
||||||
fflush(stdout);
|
|
||||||
const uint8_t * dptr = reinterpret_cast<const uint8_t*>(ptr);
|
|
||||||
for (unsigned n=0; n<len; n++) data [addr + n] = dptr [n];
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
uint32_t Read (const uint32_t addr, void * ptr, const uint32_t len) {
|
|
||||||
uint8_t * data = reinterpret_cast<uint8_t*>(ptr);
|
|
||||||
for (unsigned n=0; n<len; n++) data[n] = n;
|
|
||||||
return len; }
|
|
||||||
void Erase (const uint32_t blok) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CdcCmd : public BaseLayer {
|
|
||||||
static constexpr int maxlen = 0x80;
|
|
||||||
FIFO<char, maxlen> ring;
|
|
||||||
char line [maxlen];
|
|
||||||
unsigned index;
|
|
||||||
public:
|
|
||||||
explicit CdcCmd () noexcept : BaseLayer(), ring(), index(0u) {}
|
|
||||||
uint32_t Up(const char * data, const uint32_t len) override {
|
|
||||||
for (unsigned n=0u; n<len; n++) ring.Write (data [n]);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
void 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char * GetLine (unsigned & len) {
|
|
||||||
char c;
|
|
||||||
while (ring.Read(c)) {
|
|
||||||
line [index++] = c;
|
|
||||||
if (c == '\n') {
|
|
||||||
len = index;
|
|
||||||
/*
|
|
||||||
fprintf(stdout, "RX");
|
|
||||||
int r = fwrite (line, 1, index, stdout); (void) r;
|
|
||||||
fflush (stdout);
|
|
||||||
*/
|
|
||||||
index = 0u;
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len = 0u;
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif // HELPERS_H
|
|
|
@ -1,122 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "linkprotocol.h"
|
|
||||||
|
|
||||||
#define trace(...)
|
|
||||||
|
|
||||||
LinkProtocol::LinkProtocol(CdcCmd & g, MemoryBase & b) noexcept : cdccmd(g), ihx(), driver(b),
|
|
||||||
begin_addr(0), start_addr(0), lenght (0) {
|
|
||||||
}
|
|
||||||
void LinkProtocol::ParseLine (const char * line) {
|
|
||||||
const unsigned readen = strlen (line);
|
|
||||||
RowTypes t = ihx.parseRecord (line, readen);
|
|
||||||
switch (t) {
|
|
||||||
case dataRecord: AcquireDataRecord (); break;
|
|
||||||
case elaRecord: AcquireElaRecord (); break;
|
|
||||||
case slaRecord: AcquireSlaRecord (); break;
|
|
||||||
case eofRecord: AcquireEofRecord (); break;
|
|
||||||
case reqRecord: AcquireReqRecord (); break;
|
|
||||||
case ersRecord: AcquireErsRecord (); break;
|
|
||||||
default:
|
|
||||||
trace ("BAD record 0x%02X\r\n", t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void LinkProtocol::AcquireDataRecord() {
|
|
||||||
uint32_t ofs, len;
|
|
||||||
uint8_t * ptr = ihx.getDataRow (ofs, len);
|
|
||||||
uint32_t res = driver.Write (begin_addr + ofs, ptr, len);
|
|
||||||
if (res) {
|
|
||||||
//SendAck();
|
|
||||||
ihx.AddOffset (res); // posun offsetu az po ack
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//SendAck (false);
|
|
||||||
}
|
|
||||||
// První paket, který musí přijít při každé akci.
|
|
||||||
void LinkProtocol::AcquireElaRecord() {
|
|
||||||
ihx.getAddress (begin_addr);
|
|
||||||
trace("Begin = 0x%08X\r\n", begin_addr);
|
|
||||||
//driver = GetDriverByAddress (begin_addr);
|
|
||||||
//if (driver) driver->On (begin_addr);
|
|
||||||
SendAck();
|
|
||||||
}
|
|
||||||
typedef void (*pHandler) (void);
|
|
||||||
void LinkProtocol::AcquireSlaRecord() {
|
|
||||||
ihx.getAddress (start_addr);
|
|
||||||
trace("Start = 0x%08X\r\n", start_addr);
|
|
||||||
}
|
|
||||||
void LinkProtocol::AcquireEofRecord() {
|
|
||||||
ihx.getLenght (lenght);
|
|
||||||
trace ("Lenght = %d\r\n", lenght);
|
|
||||||
SendAck();
|
|
||||||
}
|
|
||||||
void LinkProtocol::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);
|
|
||||||
res = driver.Read (begin_addr + ofs, data, len);
|
|
||||||
res = ihx.DataRecord (strbuf, data, res);
|
|
||||||
cdccmd.SendString (strbuf, res);
|
|
||||||
}
|
|
||||||
void LinkProtocol::AcquireErsRecord() {
|
|
||||||
uint32_t block;
|
|
||||||
ihx.getOffset (block);
|
|
||||||
driver.Erase (block);
|
|
||||||
SendAck();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinkProtocol::SendAck (bool ok) {
|
|
||||||
RowTypes t = ok ? ackRecord : nakRecord;
|
|
||||||
const uint32_t r = ihx.BTxRecord (strbuf, t);
|
|
||||||
cdccmd.SendString (strbuf, r);
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
void LinkProtocol::ReadMem() {
|
|
||||||
uint32_t res = ihx.BTxRecord (strbuf, reqRecord);
|
|
||||||
cdccmd.SendString (strbuf, res);
|
|
||||||
}
|
|
||||||
bool LinkProtocol::isEOF(const unsigned len) {
|
|
||||||
uint32_t ofs;
|
|
||||||
ihx.getOffset(ofs);
|
|
||||||
if (ofs < len) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool LinkProtocol::StartOperation() {
|
|
||||||
uint32_t res = ihx.ElaRecord(strbuf, 0u);
|
|
||||||
cdccmd.SendString (strbuf, res);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool LinkProtocol::Erase(const unsigned int n) {
|
|
||||||
uint32_t ofs, addr = n * 0x1000u;
|
|
||||||
ihx.getOffset(ofs);
|
|
||||||
ihx.AddOffset(addr - ofs);
|
|
||||||
uint32_t res = ihx.BTxRecord (strbuf, ersRecord);
|
|
||||||
cdccmd.SendString (strbuf, res);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool LinkProtocol::WriteMem(const uint8_t * data, const unsigned int len) {
|
|
||||||
unsigned ofs = 0u, rem = len, chunk;
|
|
||||||
for (;;) {
|
|
||||||
unsigned value;
|
|
||||||
char * res = cdccmd.GetLine(value);
|
|
||||||
if (value == 0u) continue;
|
|
||||||
RowTypes t = ihx.parseRecord(res, value);
|
|
||||||
if (t != ackRecord) return false;
|
|
||||||
if (rem == 0u) break;
|
|
||||||
|
|
||||||
chunk = rem > 0x20 ? 0x20 : rem;
|
|
||||||
unsigned rl = ihx.DataRecord(strbuf, data + ofs, chunk);
|
|
||||||
printf("Write at 0x%04X \r", ofs);
|
|
||||||
fflush(stdout);
|
|
||||||
ihx.AddOffset(chunk);
|
|
||||||
cdccmd.SendString(strbuf, rl);
|
|
||||||
ofs += chunk;
|
|
||||||
rem -= chunk;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef LINKPROTOCOL_H
|
|
||||||
#define LINKPROTOCOL_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "intelhex.h"
|
|
||||||
|
|
||||||
class CdcCmd;
|
|
||||||
class MemoryBase;
|
|
||||||
/**
|
|
||||||
* @class LinkProtocol
|
|
||||||
* @brief Protokol po CDC.
|
|
||||||
*
|
|
||||||
* Vychází z formátu IntelHex. komunikaci začíná PC, modul odpovídá. První co musí PC (vždy na začátku konunikace !) poslat
|
|
||||||
* je paket ElaRecord (4), který určuje počáteční adresu - podle ní modul vybere potřebný ovladač paměti. Formy komunikace :
|
|
||||||
* -# Mazání obsahu flash. Probíhá po jednotlivých blocích.
|
|
||||||
* - PC -> MODUL : ersRecord (v poli offset číslo bloku relativně k počátku typu paměti)
|
|
||||||
* - MODUL -> PC : ackRecord (v poli offset číslo bloku relativně k počátku typu paměti)
|
|
||||||
* -# Zápis dat do paměti.
|
|
||||||
* - PC -> MODUL : dataRecord (max. 32 bytů)
|
|
||||||
* - MODUL -> PC : ackRecord nebo nakRecord pokud je cosi špatně
|
|
||||||
* -# Čtení dat z paměti.
|
|
||||||
* - PC -> MODUL : reqRecord (v poli offset odkud chci číst)
|
|
||||||
* - MODUL -> PC : dataRecord - pokud má nulovou délku, další data nejsou. Posílána je délka 32 bytů.
|
|
||||||
* -# Spuštění uživatelského programu.
|
|
||||||
* - PC -> MODUL : slaRecord
|
|
||||||
* - bez odpovědi - je to jen pro uživatelské testy a může to špatně skončit. Vlastně je to přidáno
|
|
||||||
* jen proto, že to jde.
|
|
||||||
* */
|
|
||||||
class LinkProtocol {
|
|
||||||
static constexpr unsigned strbuflen = 0x80u;
|
|
||||||
public:
|
|
||||||
explicit LinkProtocol(CdcCmd & g, MemoryBase & b) noexcept;
|
|
||||||
void ParseLine (const char * line);
|
|
||||||
bool StartOperation ();
|
|
||||||
void ReadMem ();
|
|
||||||
bool WriteMem (const uint8_t * data, const unsigned len);
|
|
||||||
bool Erase (const unsigned n);
|
|
||||||
bool isEOF (const unsigned len);
|
|
||||||
protected:
|
|
||||||
void AcquireDataRecord ();
|
|
||||||
void AcquireElaRecord ();
|
|
||||||
void AcquireSlaRecord ();
|
|
||||||
void AcquireEofRecord ();
|
|
||||||
void AcquireReqRecord ();
|
|
||||||
void AcquireErsRecord ();
|
|
||||||
|
|
||||||
void SendAck (bool ok=true);
|
|
||||||
private:
|
|
||||||
CdcCmd & cdccmd;
|
|
||||||
IntelHex ihx;
|
|
||||||
MemoryBase & driver;
|
|
||||||
|
|
||||||
uint32_t begin_addr;
|
|
||||||
uint32_t start_addr;
|
|
||||||
uint32_t lenght;
|
|
||||||
|
|
||||||
char strbuf [strbuflen];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // LINKPROTOCOL_H
|
|
|
@ -1,118 +1,27 @@
|
||||||
#include <signal.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <sys/types.h>
|
#include <cstdlib>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
#include "fifo.h"
|
#include "programmer.h"
|
||||||
#include "linkprotocol.h"
|
|
||||||
#include "helpers.h"
|
|
||||||
|
|
||||||
static constexpr unsigned FlashBlockSize = 0x1000u;
|
|
||||||
volatile bool loop = false;
|
|
||||||
void sig_handler (int) {
|
|
||||||
loop = false;
|
|
||||||
}
|
|
||||||
static UsartClass usart ("/dev/serial/by-id/usb-Kizarm_Labs._Flash_Programmer_0001-if00", 9600);
|
|
||||||
static MemoryBase mem (0x400u * FlashBlockSize); // 4MiB flash
|
|
||||||
static CdcCmd cmd;
|
|
||||||
static LinkProtocol lnk (cmd, mem);
|
|
||||||
|
|
||||||
static void read_flash (const unsigned len) {
|
|
||||||
lnk.StartOperation();
|
|
||||||
while (loop) {
|
|
||||||
unsigned value;
|
|
||||||
char * res = cmd.GetLine(value);
|
|
||||||
if (value == 0u) continue;
|
|
||||||
lnk.ParseLine(res);
|
|
||||||
if (lnk.isEOF(len)) break;
|
|
||||||
lnk.ReadMem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void erase_blocks (const unsigned num = 1) {
|
|
||||||
unsigned block = 0u;
|
|
||||||
lnk.StartOperation();
|
|
||||||
while (loop) {
|
|
||||||
unsigned value;
|
|
||||||
char * res = cmd.GetLine(value);
|
|
||||||
if (value == 0u) continue;
|
|
||||||
if (block >= num) break;
|
|
||||||
lnk.ParseLine(res);
|
|
||||||
lnk.Erase (block);
|
|
||||||
printf("Erasing blok %d \r", block);
|
|
||||||
fflush(stdout);
|
|
||||||
block += 1u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static uint8_t * open_file_for_read (const char * name, unsigned & len) {
|
|
||||||
struct stat prop;
|
|
||||||
const int r = stat (name, & prop);
|
|
||||||
if (r) return nullptr;
|
|
||||||
const unsigned flen = prop.st_size;
|
|
||||||
FILE * in = fopen (name, "r");
|
|
||||||
uint8_t * data = new uint8_t [flen];
|
|
||||||
const int l = fread (data, 1, flen, in);
|
|
||||||
printf("readen = %d bytes\n", l);
|
|
||||||
fclose(in);
|
|
||||||
len = flen;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
static void read_flash_binary (const char * name) {
|
|
||||||
const unsigned flen = 0x10000u;
|
|
||||||
printf("Read data\n");
|
|
||||||
read_flash (flen);
|
|
||||||
FILE * out = fopen(name,"w");
|
|
||||||
int r = fwrite(mem.getData(), 1, flen, out);
|
|
||||||
(void) r;
|
|
||||||
fclose(out);
|
|
||||||
}
|
|
||||||
static void write_flash_binary (const char * name) {
|
|
||||||
unsigned flen = 0u;
|
|
||||||
uint8_t * data = open_file_for_read(name, flen);
|
|
||||||
if (!data) return;
|
|
||||||
printf("Write data\n");
|
|
||||||
uint32_t blocks = flen / FlashBlockSize;
|
|
||||||
if (flen % FlashBlockSize) blocks += 1u;
|
|
||||||
erase_blocks (blocks);
|
|
||||||
|
|
||||||
lnk.StartOperation();
|
|
||||||
lnk.WriteMem (data, flen);
|
|
||||||
delete [] data;
|
|
||||||
}
|
|
||||||
static void verify_flash_binary (const char * name) {
|
|
||||||
unsigned flen = 0u;
|
|
||||||
uint8_t * data = open_file_for_read(name, flen);
|
|
||||||
if (!data) return;
|
|
||||||
printf("Verify data\n");
|
|
||||||
read_flash (flen);
|
|
||||||
uint8_t * fdata = mem.getData();
|
|
||||||
unsigned ok = 0;
|
|
||||||
for (unsigned n=0u; n<flen; n++) {
|
|
||||||
if (fdata[n] != data[n]) {
|
|
||||||
printf("err at %04X - %02X != %02X\n", n, fdata[n], data[n]);
|
|
||||||
ok += 1u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ok == 0u) printf("\nFlash OK\n");
|
|
||||||
else printf("\nTotal errors = %d\n", ok);
|
|
||||||
|
|
||||||
delete [] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
printf("Usage:\r\t$ %s r|w|v file.bin\n", argv[0]);
|
printf("Usage:\r\t$ %s r|w|v file.bin [numblocks]\n", argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
loop = true;
|
UsartClass usart ("/dev/serial/by-id/usb-Kizarm_Labs._Flash_Programmer_0001-if00", 9600);
|
||||||
signal(SIGINT, sig_handler);
|
Programmer cmd;
|
||||||
cmd += usart;
|
cmd += usart;
|
||||||
|
cmd.Flush();
|
||||||
if (argv[1][0] == 'r') {
|
if (argv[1][0] == 'r') {
|
||||||
read_flash_binary (argv[2]);
|
long len = 16;
|
||||||
|
if (argc > 3) {
|
||||||
|
len = strtol (argv[3], nullptr, 10);
|
||||||
|
}
|
||||||
|
cmd.read_flash_binary (argv[2], len);
|
||||||
} else if (argv[1][0] == 'w') {
|
} else if (argv[1][0] == 'w') {
|
||||||
write_flash_binary(argv[2]);
|
cmd.write_flash_binary(argv[2]);
|
||||||
} else if (argv[1][0] == 'v') {
|
} else if (argv[1][0] == 'v') {
|
||||||
verify_flash_binary(argv[2]);
|
cmd.verify_flash_binary(argv[2]);
|
||||||
} else {
|
} else {
|
||||||
printf("bad parameter %s\n", argv[1]);
|
printf("bad parameter %s\n", argv[1]);
|
||||||
}
|
}
|
||||||
|
|
216
V203F6P6/programmer/software/programmer.cpp
Normal file
216
V203F6P6/programmer/software/programmer.cpp
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
#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");
|
||||||
|
}
|
46
V203F6P6/programmer/software/programmer.h
Normal file
46
V203F6P6/programmer/software/programmer.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef PROGRAMMER_H
|
||||||
|
#define PROGRAMMER_H
|
||||||
|
#include "cstdint"
|
||||||
|
#include "baselayer.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
#include "intelhex.h"
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class Programmer : public BaseLayer {
|
||||||
|
static constexpr unsigned MaxStrLen = 1024u;
|
||||||
|
static constexpr unsigned MaxPages = 1024u;
|
||||||
|
static constexpr unsigned PageSize = 0x1000u;
|
||||||
|
static constexpr unsigned ihxPage = 0x10000u;
|
||||||
|
FIFO<char, MaxStrLen> ring;
|
||||||
|
IntelHex ihx;
|
||||||
|
char strbuf[MaxStrLen];
|
||||||
|
char line [MaxStrLen];
|
||||||
|
unsigned line_len, line_index;
|
||||||
|
unsigned begin_addr;
|
||||||
|
unsigned file_len;
|
||||||
|
uint8_t * file_pool;
|
||||||
|
uint8_t * memory_pool;
|
||||||
|
public:
|
||||||
|
explicit Programmer ();
|
||||||
|
virtual ~Programmer ();
|
||||||
|
uint32_t Up (const char * data, const uint32_t len) override;
|
||||||
|
void Flush ();
|
||||||
|
|
||||||
|
void read_flash_binary (const char * name, const unsigned blen = 16u);
|
||||||
|
void verify_flash_binary (const char * name);
|
||||||
|
void write_flash_binary (const char * name);
|
||||||
|
protected:
|
||||||
|
bool open_file_for_read (const char * name);
|
||||||
|
void SendString (const char * ptr, const uint32_t len);
|
||||||
|
bool GetLine ();
|
||||||
|
void ParseLine ();
|
||||||
|
void StartOperation (const unsigned addr);
|
||||||
|
void AcquireDataRecord ();
|
||||||
|
void AcquireReqRecord ();
|
||||||
|
|
||||||
|
void Erase (const unsigned n);
|
||||||
|
void read_flash (const unsigned len);
|
||||||
|
void erase_blocks (const unsigned blocks);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PROGRAMMER_H
|
Loading…
Add table
Reference in a new issue