#include <string>
#include <exception>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "Flasher.h"
using namespace std;
void
FlasherInfo::print()
{
bool first;
printf("Device : %s\n", name.c_str());
printf("Version : %s\n", version.c_str());
printf("Address : 0x%x\n", address);
printf("Pages : %d\n", numPages);
printf("Page Size : %d bytes\n", pageSize);
printf("Total Size : %dKB\n", totalSize / 1024);
printf("Planes : %d\n", numPlanes);
printf("Lock Regions : %zd\n", lockRegions.size());
printf("Locked : ");
first = true;
for (uint32_t region = 0; region < lockRegions.size(); region++)
{
if (lockRegions[region])
{
printf("%s%d", first ? "" : ",", region);
first = false;
}
}
printf("%s\n", first ? "none" : "");
printf("Security : %s\n", security ? "true" : "false");
if (canBootFlash)
printf("Boot Flash : %s\n", bootFlash ? "true" : "false");
if (canBod)
printf("BOD : %s\n", bod ? "true" : "false");
if (canBor)
printf("BOR : %s\n", bor ? "true" : "false");
if (uniqueId.size() > 0)
{
printf("Unique Id : ");
for (uint32_t word = 0; word < uniqueId.size(); word++)
{
printf("%08x", uniqueId[word]);
}
printf("\n");
}
}
void
Flasher::erase(uint32_t foffset)
{
_observer.onStatus("Erase flash\n");
_flash->eraseAll(foffset);
_flash->eraseAuto(false);
}
void
Flasher::write(const char* filename, uint32_t foffset)
{
FILE* infile;
uint32_t pageSize = _flash->pageSize();
uint32_t pageNum = 0;
uint32_t numPages;
long fsize;
size_t fbytes;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
infile = fopen(filename, "rb");
if (!infile)
throw FileOpenError(errno);
try
{
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
throw FileIoError(errno);
rewind(infile);
numPages = (fsize + pageSize - 1) / pageSize;
if (numPages > _flash->numPages())
throw FileSizeError();
_observer.onStatus("Write %ld bytes to flash (%u pages)\n", fsize, numPages);
if (_samba.canWriteBuffer())
{
uint32_t offset = 0;
uint32_t bufferSize = _samba.writeBufferSize();
std::vector<uint8_t> buffer(bufferSize);
while ((fbytes = fread(buffer.data(), 1, bufferSize, infile)) > 0)
{
_observer.onProgress(offset / pageSize, numPages);
if (fbytes < bufferSize)
{
memset(buffer.data() + fbytes, 0, bufferSize - fbytes);
fbytes = (fbytes + pageSize - 1) / pageSize * pageSize;
}
_flash->loadBuffer(buffer.data(), (uint16_t)fbytes);
_flash->writeBuffer(foffset + offset, (uint32_t)fbytes);
offset += (uint32_t)fbytes;
}
}
else
{
std::vector<uint8_t> buffer(pageSize);
uint32_t pageOffset = foffset / pageSize;
while ((fbytes = fread(buffer.data(), 1, pageSize, infile)) > 0)
{
_observer.onProgress(pageNum, numPages);
_flash->loadBuffer(buffer.data(), (uint16_t)fbytes);
_flash->writePage(pageOffset + pageNum);
pageNum++;
if (pageNum == numPages || fbytes != pageSize)
break;
}
}
}
catch(...)
{
fclose(infile);
throw;
}
fclose(infile);
_observer.onProgress(numPages, numPages);
}
bool
Flasher::verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset)
{
FILE* infile;
uint32_t pageSize = _flash->pageSize();
std::vector<uint8_t> bufferA(pageSize);
std::vector<uint8_t> bufferB(pageSize);
uint32_t pageNum = 0;
uint32_t numPages;
uint32_t pageOffset;
uint32_t byteErrors = 0;
uint16_t flashCrc;
long fsize;
size_t fbytes;
pageErrors = 0;
totalErrors = 0;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
pageOffset = foffset / pageSize;
infile = fopen(filename, "rb");
if (!infile)
throw FileOpenError(errno);
try
{
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
throw FileIoError(errno);
rewind(infile);
numPages = (fsize + pageSize - 1) / pageSize;
if (numPages > _flash->numPages())
throw FileSizeError();
_observer.onStatus("Verify %ld bytes of flash\n", fsize);
while ((fbytes = fread(bufferA.data(), 1, pageSize, infile)) > 0)
{
byteErrors = 0;
_observer.onProgress(pageNum, numPages);
if (_samba.canChecksumBuffer())
{
uint16_t calcCrc = 0;
for (uint32_t i = 0; i < fbytes; i++)
calcCrc = _samba.checksumCalc(bufferA[i], calcCrc);
flashCrc = _samba.checksumBuffer((pageOffset + pageNum) * pageSize, (uint32_t)fbytes);
if (flashCrc != calcCrc)
{
_flash->readPage(pageOffset + pageNum, bufferB.data());
for (uint32_t i = 0; i < fbytes; i++)
{
if (bufferA[i] != bufferB[i])
byteErrors++;
}
}
}
else
{
_flash->readPage(pageOffset + pageNum, bufferB.data());
for (uint32_t i = 0; i < fbytes; i++)
{
if (bufferA[i] != bufferB[i])
byteErrors++;
}
}
if (byteErrors != 0)
{
pageErrors++;
totalErrors += byteErrors;
}
pageNum++;
if (pageNum == numPages || fbytes != pageSize)
break;
}
}
catch(...)
{
fclose(infile);
throw;
}
fclose(infile);
_observer.onProgress(numPages, numPages);
if (pageErrors != 0)
return false;
return true;
}
void
Flasher::read(const char* filename, uint32_t fsize, uint32_t foffset)
{
FILE* outfile;
uint32_t pageSize = _flash->pageSize();
std::vector<uint8_t> buffer(pageSize);
uint32_t pageNum = 0;
uint32_t pageOffset;
uint32_t numPages;
size_t fbytes;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
pageOffset = foffset / pageSize;
if (fsize == 0)
fsize = pageSize * (_flash->numPages() - pageOffset);
numPages = (fsize + pageSize - 1) / pageSize;
if (pageOffset + numPages > _flash->numPages())
throw FileSizeError();
outfile = fopen(filename, "wb");
if (!outfile)
throw FileOpenError(errno);
_observer.onStatus("Read %d bytes from flash\n", fsize);
try
{
for (pageNum = 0; pageNum < numPages; pageNum++)
{
_observer.onProgress(pageNum, numPages);
_flash->readPage(pageOffset + pageNum, buffer.data());
if (pageNum == numPages - 1 && fsize % pageSize > 0)
pageSize = fsize % pageSize;
fbytes = fwrite(buffer.data(), 1, pageSize, outfile);
if (fbytes != pageSize)
throw FileShortError();
}
}
catch(...)
{
fclose(outfile);
throw;
}
_observer.onProgress(numPages, numPages);
fclose(outfile);
}
void
Flasher::lock(const string& regionArg, bool enable)
{
if (regionArg.empty())
{
_observer.onStatus("%s all regions\n", enable ? "Lock" : "Unlock");
std::vector<bool> regions(_flash->lockRegions(), enable);
_flash->setLockRegions(regions);
}
else
{
size_t pos = 0;
size_t delim;
uint32_t region;
string sub;
std::vector<bool> regions = _flash->getLockRegions();
do
{
delim = regionArg.find(',', pos);
sub = regionArg.substr(pos, delim - pos);
region = strtol(sub.c_str(), NULL, 0);
_observer.onStatus("%s region %d\n", enable ? "Lock" : "Unlock", region);
regions[region] = enable;
pos = delim + 1;
} while (delim != string::npos);
_flash->setLockRegions(regions);
}
}
void
Flasher::info(FlasherInfo& info)
{
info.name = _flash->name();
info.version = _samba.version();
info.address = _flash->address();
info.numPages = _flash->numPages();
info.pageSize = _flash->pageSize();
info.totalSize = _flash->numPages() * _flash->pageSize();
info.numPlanes = _flash->numPlanes();
info.security = _flash->getSecurity();
info.bootFlash = _flash->getBootFlash();
info.bod = _flash->getBod();
info.bor = _flash->getBor();
info.uniqueId = _flash->getUniqueId();
info.canBootFlash = _flash->canBootFlash();
info.canBod = _flash->canBod();
info.canBor = _flash->canBor();
info.canChipErase = _samba.canChipErase();
info.canWriteBuffer = _samba.canWriteBuffer();
info.canChecksumBuffer = _samba.canChecksumBuffer();
info.lockRegions = _flash->getLockRegions();
}
void
Flasher::setSecurity()
{
_flash->setSecurity();
}
void
Flasher::setBod(bool enable)
{
_flash->setBod(enable);
}
void
Flasher::setBor(bool enable)
{
_flash->setBor(enable);
}
void
Flasher::setBootFlash(bool enable)
{
_flash->setBootFlash(enable);
}
void
Flasher::writeOptions()
{
_flash->writeOptions();
}
void
Flasher::reset()
{
_flash->ready();
_device.reset();
}
std::unique_ptr<FlasherInfo> new_flasher_info()
{
return std::unique_ptr<FlasherInfo>(new FlasherInfo());
}
std::unique_ptr<Flasher> new_flasher(Samba& samba, Device& device, FlasherObserver& observer)
{
return std::unique_ptr<Flasher>(new Flasher(samba, device, observer));
}