This is an incomplete implementation of the new "erase some of the SIMM"

feature. The erase capability is there, so next up comes the write.

The next step is to add a mechanism to the protocol to start writing at
a location other than 0 (although this is not needed for this particular
feature, I'd like to have it in there first). Then, I have to update
this software to use that new protocol and make sure verification still
works. I'm about 50% done I'd say.
This commit is contained in:
Doug Brown 2012-10-16 21:35:43 -07:00
parent b57f0a83e1
commit 09686d2199
6 changed files with 237 additions and 15 deletions

View File

@ -31,6 +31,7 @@ static Programmer *p;
#define selectedCapacityKey "selectedCapacity"
#define verifyAfterWriteKey "verifyAfterWrite"
#define verifyWhileWritingKey "verifyWhileWriting"
#define selectedEraseSizeKey "selectedEraseSize"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@ -95,6 +96,22 @@ MainWindow::MainWindow(QWidget *parent) :
ui->verifyBox->setCurrentIndex(selectedIndex);
}
// Fill in list of "write first xxx bytes" options
ui->howMuchToWriteBox->addItem("Erase/write entire SIMM", QVariant(0));
ui->howMuchToWriteBox->addItem("Only erase/write first 256 KB", QVariant(256*1024));
ui->howMuchToWriteBox->addItem("Only erase/write first 512 KB", QVariant(512*1024));
ui->howMuchToWriteBox->addItem("Only erase/write first 1 MB", QVariant(1024*1024));
ui->howMuchToWriteBox->addItem("Only erase/write first 1.5 MB", QVariant(3*512*1024));
ui->howMuchToWriteBox->addItem("Only erase/write first 2 MB", QVariant(2*1024*1024));
// Select "erase entire SIMM" by default, or load last-used setting
QVariant selectedEraseSize = settings.value(selectedEraseSizeKey, QVariant(0));
selectedIndex = ui->howMuchToWriteBox->findData(selectedEraseSize);
if (selectedIndex != -1)
{
ui->howMuchToWriteBox->setCurrentIndex(selectedIndex);
}
ui->chosenWriteFile->setText("");
ui->chosenReadFile->setText("");
writeFileValid = false;
@ -203,7 +220,16 @@ void MainWindow::on_writeToSIMMButton_clicked()
return;
}
resetAndShowStatusPage();
p->writeToSIMM(writeFile);
uint howMuchToErase = ui->howMuchToWriteBox->itemData(ui->howMuchToWriteBox->currentIndex()).toUInt();
if (howMuchToErase == 0)
{
p->writeToSIMM(writeFile);
}
else
{
p->writeToSIMM(writeFile, 0, howMuchToErase);
}
qDebug() << "Writing to SIMM...";
}
else
@ -402,6 +428,17 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "File too big", "The file you chose to write to the SIMM is too big according to the chip size you have selected.");
break;
case WriteEraseBlockWrongSize:
if (writeFile)
{
writeFile->close();
delete writeFile;
writeFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Bad erase size", "The programmer cannot handle the erase size you chose.");
break;
}
}
@ -713,6 +750,21 @@ void MainWindow::on_verifyBox_currentIndexChanged(int index)
}
}
void MainWindow::on_howMuchToWriteBox_currentIndexChanged(int index)
{
if (index < 0) return;
uint32_t newEraseSize = static_cast<uint32_t>(ui->howMuchToWriteBox->itemData(index).toUInt());
QSettings settings;
if (!initializing)
{
// If we're not initializing (it gets called while we're initializing),
// go ahead and save this as the new default.
settings.setValue(selectedEraseSizeKey, newEraseSize);
}
}
void MainWindow::on_actionAbout_SIMM_Programmer_triggered()
{
AboutBox::instance()->show();

View File

@ -83,6 +83,8 @@ private slots:
void on_verifyBox_currentIndexChanged(int index);
void on_howMuchToWriteBox_currentIndexChanged(int index);
private:
Ui::MainWindow *ui;
bool initializing;

View File

@ -84,6 +84,9 @@
<item>
<widget class="QComboBox" name="verifyBox"/>
</item>
<item>
<widget class="QComboBox" name="howMuchToWriteBox"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">

View File

@ -60,7 +60,13 @@ typedef enum ProgrammerCommandState
BootloaderEraseProgramAwaitingStartOKReply,
BootloaderEraseProgramWaitingFinishReply,
BootloaderEraseProgramWaitingWriteMoreReply,
BootloaderEraseProgramWaitingWriteReply
BootloaderEraseProgramWaitingWriteReply,
WritePortionWaitingSetSizeReply,
WritePortionWaitingSetVerifyModeReply,
WritePortionWaitingEraseReply,
WritePortionWaitingEraseConfirmation,
WritePortionWaitingEraseResult
} ProgrammerCommandState;
typedef enum ProgrammerBoardFoundState
@ -85,7 +91,8 @@ typedef enum ProgrammerCommand
SetSIMMTypePLCC32_2MB,
SetSIMMTypeLarger,
SetVerifyWhileWriting,
SetNoVerifyWhileWriting
SetNoVerifyWhileWriting,
ErasePortion
} ProgrammerCommand;
typedef enum ProgrammerReply
@ -156,6 +163,13 @@ typedef enum ComputerBootloaderEraseWriteRequest
ComputerBootloaderCancel
} ComputerBootloaderEraseWriteRequest;
typedef enum ProgrammerErasePortionOfChipReply
{
ProgrammerErasePortionOK = 0,
ProgrammerErasePortionError,
ProgrammerErasePortionFinished
} ProgrammerErasePortionOfChipReply;
#define PROGRAMMER_USB_VENDOR_ID 0x16D0
#define PROGRAMMER_USB_DEVICE_ID 0x06AA
@ -164,6 +178,8 @@ typedef enum ComputerBootloaderEraseWriteRequest
#define READ_CHUNK_SIZE 1024
#define FIRMWARE_CHUNK_SIZE 1024
#define BLOCK_ERASE_SIZE (256*1024UL)
static ProgrammerCommandState curState = WaitingForNextCommand;
// After identifying that we're in the main program, what will be the command
@ -259,11 +275,57 @@ void Programmer::writeToSIMM(QIODevice *device)
}
}
void Programmer::writeToSIMM(QIODevice *device, uint32_t startOffset, uint32_t length)
{
writeDevice = device;
if ((writeDevice->size() > SIMMCapacity()) ||
(startOffset + length > SIMMCapacity()))
{
curState = WaitingForNextCommand;
emit writeStatusChanged(WriteFileTooBig);
return;
}
else if ((startOffset % BLOCK_ERASE_SIZE) || (length % BLOCK_ERASE_SIZE))
{
curState = WaitingForNextCommand;
emit writeStatusChanged(WriteEraseBlockWrongSize);
return;
}
else
{
lenWritten = 0;
writeLenRemaining = length;
device->seek(startOffset);
writeOffset = startOffset;
writeLength = length;
// Based on the SIMM size, tell the programmer board.
uint8_t setSizeCommand;
if (SIMMCapacity() > 2*1024*1024)
{
setSizeCommand = SetSIMMTypeLarger;
}
else
{
setSizeCommand = SetSIMMTypePLCC32_2MB;
}
startProgrammerCommand(setSizeCommand, WritePortionWaitingSetSizeReply);
}
}
void Programmer::sendByte(uint8_t b)
{
serialPort->write((const char *)&b, 1);
}
void Programmer::sendWord(uint32_t w)
{
sendByte((w >> 0) & 0xFF);
sendByte((w >> 8) & 0xFF);
sendByte((w >> 16) & 0xFF);
sendByte((w >> 24) & 0xFF);
}
uint8_t Programmer::readByte()
{
uint8_t returnVal;
@ -290,6 +352,7 @@ void Programmer::handleChar(uint8_t c)
// Expecting reply after we told the programmer the size of SIMM to expect
case WriteSIMMWaitingSetSizeReply:
case WritePortionWaitingSetSizeReply:
switch (c)
{
case CommandReplyOK:
@ -306,7 +369,14 @@ void Programmer::handleChar(uint8_t c)
verifyCommand = SetNoVerifyWhileWriting;
}
curState = WriteSIMMWaitingSetVerifyModeReply;
if (curState == WriteSIMMWaitingSetSizeReply)
{
curState = WriteSIMMWaitingSetVerifyModeReply;
}
else if (curState == WritePortionWaitingSetSizeReply)
{
curState = WritePortionWaitingSetVerifyModeReply;
}
sendByte(verifyCommand);
break;
case CommandReplyInvalid:
@ -342,7 +412,14 @@ void Programmer::handleChar(uint8_t c)
verifyCommand = SetNoVerifyWhileWriting;
}
curState = WriteSIMMWaitingSetVerifyModeReply;
if (curState == WriteSIMMWaitingSetSizeReply)
{
curState = WriteSIMMWaitingSetVerifyModeReply;
}
else if (curState == WritePortionWaitingSetSizeReply)
{
curState = WritePortionWaitingSetVerifyModeReply;
}
sendByte(verifyCommand);
}
break;
@ -353,6 +430,7 @@ void Programmer::handleChar(uint8_t c)
// Expecting reply from programmer after we told it to verify during write
// (or not to verify during write)
case WriteSIMMWaitingSetVerifyModeReply:
case WritePortionWaitingSetVerifyModeReply:
switch (c)
{
case CommandReplyOK:
@ -361,8 +439,16 @@ void Programmer::handleChar(uint8_t c)
// Special case: Send out notification we are starting an erase command.
// I don't have any hooks into the process between now and the erase reply.
emit writeStatusChanged(WriteErasing);
sendByte(EraseChips);
curState = WriteSIMMWaitingEraseReply;
if (curState == WriteSIMMWaitingSetVerifyModeReply)
{
sendByte(EraseChips);
curState = WriteSIMMWaitingEraseReply;
}
else if (curState == WritePortionWaitingSetVerifyModeReply)
{
sendByte(ErasePortion);
curState = WritePortionWaitingEraseReply;
}
break;
case CommandReplyInvalid:
case CommandReplyError:
@ -388,8 +474,16 @@ void Programmer::handleChar(uint8_t c)
// Special case: Send out notification we are starting an erase command.
// I don't have any hooks into the process between now and the erase reply.
emit writeStatusChanged(WriteErasing);
sendByte(EraseChips);
curState = WriteSIMMWaitingEraseReply;
if (curState == WriteSIMMWaitingSetVerifyModeReply)
{
sendByte(EraseChips);
curState = WriteSIMMWaitingEraseReply;
}
else if (curState == WritePortionWaitingSetVerifyModeReply)
{
sendByte(ErasePortion);
curState = WritePortionWaitingEraseReply;
}
}
break;
}
@ -419,6 +513,73 @@ void Programmer::handleChar(uint8_t c)
break;
}
case WritePortionWaitingEraseReply:
{
switch (c)
{
case CommandReplyOK:
sendWord(writeOffset);
sendWord(writeLength);
qDebug("Sending %u, %u", writeOffset, writeLength);
curState = WritePortionWaitingEraseConfirmation;
qDebug() << "Sent erase positions, waiting for reply...";
break;
case CommandReplyError:
// Uh oh -- this is an old firmware that doesn't support verify
// while write. Let the caller know that the programmer board
// needs a firmware update.
qDebug() << "Programmer board needs firmware update.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteNeedsFirmwareUpdateErasePortion);
break;
}
break;
}
case WritePortionWaitingEraseConfirmation:
{
switch (c)
{
case ProgrammerErasePortionOK:
curState = WritePortionWaitingEraseResult;
break;
case ProgrammerErasePortionError:
// Programmer didn't like the position/length we gave it
qDebug() << "Programmer didn't like erase pos/length.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteEraseFailed);
break;
}
break;
}
case WritePortionWaitingEraseResult:
{
switch (c)
{
case ProgrammerErasePortionFinished:
// we're done erasing, now it's time to write the data
// starting at where we wanted to flash to
// TODO HERE IS WHERE I LEFT OFF
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteCompleteNoVerify);
break;
case ProgrammerErasePortionError:
// Programmer failed to erase
qDebug() << "Programmer had error erasing.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteEraseFailed);
break;
}
break;
}
// Expecting reply from programmer after we sent a chunk of data to write
// (or after we first told it we're going to start writing)
case WriteSIMMWaitingWriteReply:
@ -630,10 +791,7 @@ void Programmer::handleChar(uint8_t c)
curState = ReadSIMMWaitingLengthReply;
// Send the length requesting to be read
sendByte((lenRemaining >> 0) & 0xFF);
sendByte((lenRemaining >> 8) & 0xFF);
sendByte((lenRemaining >> 16) & 0xFF);
sendByte((lenRemaining >> 24) & 0xFF);
sendWord(lenRemaining);
// Now wait for the go-ahead from the programmer's side
break;

View File

@ -61,7 +61,9 @@ typedef enum WriteStatus
WriteVerifyError,
WriteVerifyCancelled,
WriteVerifyTimedOut,
WriteCompleteVerifyOK
WriteCompleteVerifyOK,
WriteEraseBlockWrongSize,
WriteNeedsFirmwareUpdateErasePortion
} WriteStatus;
typedef enum ElectricalTestStatus
@ -118,6 +120,7 @@ public:
virtual ~Programmer();
void readSIMM(QIODevice *device, uint32_t len = 0);
void writeToSIMM(QIODevice *device);
void writeToSIMM(QIODevice *device, uint32_t startOffset, uint32_t length);
void runElectricalTest();
QString electricalTestPinName(uint8_t index);
void identifySIMMChips();
@ -165,6 +168,7 @@ private:
QextSerialPort *serialPort;
void sendByte(uint8_t b);
void sendWord(uint32_t w);
uint8_t readByte();
void handleChar(uint8_t c);
uint32_t _simmCapacity;
@ -192,6 +196,9 @@ private:
QBuffer *verifyBuffer;
QByteArray *verifyArray;
uint32_t writeOffset;
uint32_t writeLength;
void openPort();
void closePort();

View File

@ -22,7 +22,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_REVISION 2
#define VERSION_REVISION 3
#define STRINGIFY_GUTS(x) #x
#define STRINGIFY(x) STRINGIFY_GUTS(x)