From b9a3524daf186ec825b45b19587bea1de8d53f91 Mon Sep 17 00:00:00 2001 From: Kizarm Date: Tue, 4 Feb 2025 16:32:08 +0100 Subject: [PATCH] refactoring programmer --- V203F6P6/programmer/helpers.h | 6 +- V203F6P6/programmer/main.cpp | 3 +- V203F6P6/programmer/software/Makefile | 3 +- V203F6P6/programmer/software/helpers.h | 75 ------ V203F6P6/programmer/software/linkprotocol.cpp | 122 ---------- V203F6P6/programmer/software/linkprotocol.h | 60 ----- V203F6P6/programmer/software/main.cpp | 117 ++-------- V203F6P6/programmer/software/programmer.cpp | 216 ++++++++++++++++++ V203F6P6/programmer/software/programmer.h | 46 ++++ 9 files changed, 284 insertions(+), 364 deletions(-) delete mode 100644 V203F6P6/programmer/software/helpers.h delete mode 100644 V203F6P6/programmer/software/linkprotocol.cpp delete mode 100644 V203F6P6/programmer/software/linkprotocol.h create mode 100644 V203F6P6/programmer/software/programmer.cpp create mode 100644 V203F6P6/programmer/software/programmer.h diff --git a/V203F6P6/programmer/helpers.h b/V203F6P6/programmer/helpers.h index 8190079..6e8fee3 100644 --- a/V203F6P6/programmer/helpers.h +++ b/V203F6P6/programmer/helpers.h @@ -16,7 +16,11 @@ class MemoryBase { return flash.ReadBlock(addr, reinterpret_cast (ptr), len); } 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); } }; diff --git a/V203F6P6/programmer/main.cpp b/V203F6P6/programmer/main.cpp index 5c6ed14..e17edcb 100644 --- a/V203F6P6/programmer/main.cpp +++ b/V203F6P6/programmer/main.cpp @@ -6,7 +6,8 @@ /********************************************************************************* * 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 - * 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. **********************************************************************************/ static GpioClass led (GPIOB, 8); diff --git a/V203F6P6/programmer/software/Makefile b/V203F6P6/programmer/software/Makefile index d6d9ceb..1a81810 100644 --- a/V203F6P6/programmer/software/Makefile +++ b/V203F6P6/programmer/software/Makefile @@ -7,7 +7,8 @@ MFLAGS = -o $(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 $(CC) -c $(CFLAGS) $< -o $@ diff --git a/V203F6P6/programmer/software/helpers.h b/V203F6P6/programmer/software/helpers.h deleted file mode 100644 index 1403965..0000000 --- a/V203F6P6/programmer/software/helpers.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef HELPERS_H -#define HELPERS_H -#include -#include -#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(ptr); - for (unsigned n=0; n(ptr); - for (unsigned n=0; n 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 -#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; -} diff --git a/V203F6P6/programmer/software/linkprotocol.h b/V203F6P6/programmer/software/linkprotocol.h deleted file mode 100644 index 8b04cdc..0000000 --- a/V203F6P6/programmer/software/linkprotocol.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef LINKPROTOCOL_H -#define LINKPROTOCOL_H - -#include -#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 diff --git a/V203F6P6/programmer/software/main.cpp b/V203F6P6/programmer/software/main.cpp index c765098..cef96f8 100644 --- a/V203F6P6/programmer/software/main.cpp +++ b/V203F6P6/programmer/software/main.cpp @@ -1,118 +1,27 @@ -#include #include -#include -#include -#include +#include #include "usart.h" -#include "fifo.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 3) { + len = strtol (argv[3], nullptr, 10); + } + cmd.read_flash_binary (argv[2], len); } else if (argv[1][0] == 'w') { - write_flash_binary(argv[2]); + cmd.write_flash_binary(argv[2]); } else if (argv[1][0] == 'v') { - verify_flash_binary(argv[2]); + cmd.verify_flash_binary(argv[2]); } else { printf("bad parameter %s\n", argv[1]); } diff --git a/V203F6P6/programmer/software/programmer.cpp b/V203F6P6/programmer/software/programmer.cpp new file mode 100644 index 0000000..31afc84 --- /dev/null +++ b/V203F6P6/programmer/software/programmer.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#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 (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 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 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