Refactored verification code so Programmer is in charge of it rather

than MainWindow. Also, I think I have verify while writing working
but I can't test it yet because I haven't implemented in in the
firmware. Bumped version number up as well.
This commit is contained in:
Doug Brown 2012-09-30 12:15:11 -07:00
parent 23b28c2cc7
commit b57f0a83e1
6 changed files with 577 additions and 299 deletions

View File

@ -30,6 +30,7 @@ static Programmer *p;
#define selectedCapacityKey "selectedCapacity"
#define verifyAfterWriteKey "verifyAfterWrite"
#define verifyWhileWritingKey "verifyWhileWriting"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@ -64,8 +65,35 @@ MainWindow::MainWindow(QWidget *parent) :
ui->simmCapacityBox->setCurrentIndex(selectedIndex);
}
// Decide whether or not to verify after write
ui->verifyAfterWriteBox->setChecked(settings.value(verifyAfterWriteKey, true).toBool());
// Fill in the list of verification options
ui->verifyBox->addItem("Don't verify", QVariant(NoVerification));
ui->verifyBox->addItem("Verify while writing", QVariant(VerifyWhileWriting));
ui->verifyBox->addItem("Verify after writing", QVariant(VerifyAfterWrite));
// Decide whether to verify while writing, after writing, or never.
// This would probably be better suited as an enum rather than multiple bools,
// but I started out with it as a single bool, so for backward compatibility,
// I simply added another bool for the "verify while writing" capability.
bool verifyAfterWrite = settings.value(verifyAfterWriteKey, false).toBool();
bool verifyWhileWriting = settings.value(verifyWhileWritingKey, true).toBool();
selectedIndex = 0;
if (verifyWhileWriting)
{
selectedIndex = ui->verifyBox->findData(VerifyWhileWriting);
}
else if (verifyAfterWrite)
{
selectedIndex = ui->verifyBox->findData(VerifyAfterWrite);
}
else
{
selectedIndex = ui->verifyBox->findData(NoVerification);
}
if (selectedIndex != -1)
{
ui->verifyBox->setCurrentIndex(selectedIndex);
}
ui->chosenWriteFile->setText("");
ui->chosenReadFile->setText("");
@ -79,12 +107,12 @@ MainWindow::MainWindow(QWidget *parent) :
readFile = NULL;
writeFile = NULL;
verifyArray = NULL;
verifyBuffer = NULL;
connect(p, SIGNAL(writeStatusChanged(WriteStatus)), SLOT(programmerWriteStatusChanged(WriteStatus)));
connect(p, SIGNAL(writeTotalLengthChanged(uint32_t)), SLOT(programmerWriteTotalLengthChanged(uint32_t)));
connect(p, SIGNAL(writeCompletionLengthChanged(uint32_t)), SLOT(programmerWriteCompletionLengthChanged(uint32_t)));
connect(p, SIGNAL(writeVerifyTotalLengthChanged(uint32_t)), SLOT(programmerVerifyTotalLengthChanged(uint32_t)));
connect(p, SIGNAL(writeVerifyCompletionLengthChanged(uint32_t)), SLOT(programmerVerifyCompletionLengthChanged(uint32_t)));
connect(p, SIGNAL(electricalTestStatusChanged(ElectricalTestStatus)), SLOT(programmerElectricalTestStatusChanged(ElectricalTestStatus)));
connect(p, SIGNAL(electricalTestFailLocation(uint8_t,uint8_t)), SLOT(programmerElectricalTestLocation(uint8_t,uint8_t)));
connect(p, SIGNAL(readStatusChanged(ReadStatus)), SLOT(programmerReadStatusChanged(ReadStatus)));
@ -132,8 +160,6 @@ void MainWindow::on_selectReadFileButton_clicked()
void MainWindow::on_readFromSIMMButton_clicked()
{
// We are not doing a verify after a write..
readVerifying = false;
if (readFile)
{
readFile->close();
@ -223,7 +249,7 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
case WriteErasing:
ui->statusLabel->setText("Erasing SIMM (this may take a few seconds)...");
break;
case WriteComplete:
case WriteCompleteNoVerify:
if (writeFile)
{
writeFile->close();
@ -231,53 +257,70 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
writeFile = NULL;
}
if (ui->verifyAfterWriteBox->isChecked())
QMessageBox::information(this, "Write complete", "The write operation finished.");
ui->pages->setCurrentWidget(ui->controlPage);
break;
case WriteCompleteVerifyOK:
if (writeFile)
{
// Set up the read buffers
readVerifying = true;
if (verifyArray) delete verifyArray;
verifyArray = new QByteArray((int)p->SIMMCapacity(), 0);
if (verifyBuffer) delete verifyBuffer;
verifyBuffer = new QBuffer(verifyArray);
if (!verifyBuffer->open(QBuffer::ReadWrite))
{
delete verifyBuffer;
delete verifyArray;
verifyBuffer = NULL;
verifyArray = NULL;
programmerReadStatusChanged(ReadError);
return;
}
// Start reading from SIMM to temporary RAM buffer
resetAndShowStatusPage();
// Only read back the size of the file if we can. This will save
// some time and prevent us from needing to read the ENTIRE SIMM
// if the file is only a quarter of the size of the SIMM.
uint32_t readLen = 0;
QFile temp(ui->chosenWriteFile->text());
if (temp.exists())
{
qint64 tmpLen = temp.size();
if (tmpLen > 0)
{
readLen = static_cast<uint32_t>(tmpLen);
}
else
{
readLen = 0;
}
}
p->readSIMM(verifyBuffer, readLen);
qDebug() << "Reading from SIMM for verification...";
writeFile->close();
delete writeFile;
writeFile = NULL;
}
else
QMessageBox::information(this, "Write complete", "The write operation finished, and the contents were verified successfully.");
ui->pages->setCurrentWidget(ui->controlPage);
break;
case WriteVerifying:
resetAndShowStatusPage();
break;
case WriteVerifyStarting:
ui->statusLabel->setText("Verifying SIMM contents...");
break;
case WriteVerifyError:
if (writeFile)
{
QMessageBox::information(this, "Write complete", "The write operation finished.");
ui->pages->setCurrentWidget(ui->controlPage);
writeFile->close();
delete writeFile;
writeFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify error", "An error occurred reading the SIMM contents for verification.");
break;
case WriteVerifyCancelled:
if (writeFile)
{
writeFile->close();
delete writeFile;
writeFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify cancelled", "The verify operation was cancelled.");
break;
case WriteVerifyTimedOut:
if (writeFile)
{
writeFile->close();
delete writeFile;
writeFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify timed out", "The verify operation timed out.");
break;
case WriteVerificationFailure:
if (writeFile)
{
writeFile->close();
delete writeFile;
writeFile = NULL;
}
// The verify failure code is somewhat complicated so it's best to put
// it elsewhere.
handleVerifyFailureReply();
break;
case WriteError:
if (writeFile)
@ -290,7 +333,7 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Write error", "An error occurred writing to the SIMM.");
break;
case WriteNeedsFirmwareUpdate:
case WriteNeedsFirmwareUpdateBiggerSIMM:
if (writeFile)
{
writeFile->close();
@ -301,6 +344,17 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Firmware update needed", "The programmer board needs a firmware update to support a larger SIMM. Please update the firmware and try again.");
break;
case WriteNeedsFirmwareUpdateVerifyWhileWrite:
if (writeFile)
{
writeFile->close();
delete writeFile;
writeFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Firmware update needed", "The programmer board needs a firmware update to support the \"verify while writing\" capability. Please update the firmware and try again.");
break;
case WriteCancelled:
if (writeFile)
{
@ -361,7 +415,15 @@ void MainWindow::programmerWriteCompletionLengthChanged(uint32_t len)
ui->progressBar->setValue((int)len);
}
void MainWindow::programmerVerifyTotalLengthChanged(uint32_t totalLen)
{
ui->progressBar->setMaximum((int)totalLen);
}
void MainWindow::programmerVerifyCompletionLengthChanged(uint32_t len)
{
ui->progressBar->setValue((int)len);
}
void MainWindow::on_electricalTestButton_clicked()
{
@ -415,200 +477,51 @@ void MainWindow::programmerReadStatusChanged(ReadStatus newStatus)
switch (newStatus)
{
case ReadStarting:
if (readVerifying)
{
ui->statusLabel->setText("Verifying SIMM contents...");
}
else
{
ui->statusLabel->setText("Reading SIMM contents...");
}
ui->statusLabel->setText("Reading SIMM contents...");
break;
case ReadComplete:
if (readVerifying)
if (readFile)
{
// Re-open the write file temporarily to compare it against the buffer.
QFile temp(ui->chosenWriteFile->text());
if (!temp.open(QFile::ReadOnly))
{
QMessageBox::warning(this, "Verify failed", "Unable to open file for verification.");
}
else
{
QByteArray fileBytes = temp.readAll();
if (fileBytes.count() <= verifyArray->count())
{
const char *fileBytesPtr = fileBytes.constData();
const char *readBytesPtr = verifyArray->constData();
if (memcmp(fileBytesPtr, readBytesPtr, fileBytes.count()) != 0)
{
// Now let's do some trickery and figure out which chip is acting up (or chips)
uint8_t badICMask = 0;
// Keep a list of which chips are reading bad data back
for (int x = 0; (x < fileBytes.count()) && (badICMask != 0xF); x++)
{
if (fileBytesPtr[x] != readBytesPtr[x])
{
// OK, we found a mismatched byte. Now look at
// which byte (0-3) it is in each 4-byte group.
// If it's byte 0, it's the MOST significant byte
// because the 68k is big endian. IC4 contains the
// MSB, so IC4 is the first chip, IC3 second, and
// so on. That's why I subtract it from 3 --
// 0 through 3 get mapped to 3 through 0.
badICMask |= (1 << (3 - (x % 4)));
}
}
// Make a comma-separated list of IC names from this list
QString icList;
bool first = true;
for (int x = 0; x < 4; x++)
{
if (badICMask & (1 << x))
{
if (first)
{
// not IC0 through IC3; IC1 through IC4.
// that's why I add one.
icList.append(QString("IC%1").arg(x+1));
first = false;
}
else
{
icList.append(QString(", IC%1").arg(x+1));
}
}
}
QMessageBox::warning(this, "Verify error", "The data read back from the SIMM did not match the data written to it. Bad data on chips: " + icList);
}
else
{
QMessageBox::information(this, "Write complete", "The write operation finished, and the contents were verified successfully.");
}
}
else
{
QMessageBox::warning(this, "Verify error", "The data read back from the SIMM did not match the data written to it--wrong amount of data read back.");
}
}
// Close stuff not needed anymore
if (verifyBuffer)
{
verifyBuffer->close();
delete verifyBuffer;
verifyBuffer = NULL;
}
if (verifyArray)
{
delete verifyArray;
verifyArray = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
readFile->close();
delete readFile;
readFile = NULL;
}
else
{
if (readFile)
{
readFile->close();
delete readFile;
readFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::information(this, "Read complete", "The read operation finished.");
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::information(this, "Read complete", "The read operation finished.");
break;
case ReadError:
if (readVerifying)
if (readFile)
{
if (verifyBuffer)
{
verifyBuffer->close();
delete verifyBuffer;
}
verifyBuffer = NULL;
if (verifyArray) delete verifyArray;
verifyArray = NULL;
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify error", "An error occurred reading the SIMM contents for verification.");
readFile->close();
delete readFile;
readFile = NULL;
}
else
{
if (readFile)
{
readFile->close();
delete readFile;
readFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read error", "An error occurred reading from the SIMM.");
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read error", "An error occurred reading from the SIMM.");
break;
case ReadCancelled:
if (readVerifying)
if (readFile)
{
if (verifyBuffer)
{
verifyBuffer->close();
delete verifyBuffer;
}
verifyBuffer = NULL;
if (verifyArray) delete verifyArray;
verifyArray = NULL;
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify cancelled", "The verify operation was cancelled.");
readFile->close();
delete readFile;
readFile = NULL;
}
else
{
if (readFile)
{
readFile->close();
delete readFile;
readFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read cancelled", "The read operation was cancelled.");
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read cancelled", "The read operation was cancelled.");
break;
case ReadTimedOut:
if (readVerifying)
if (readFile)
{
if (verifyBuffer)
{
verifyBuffer->close();
delete verifyBuffer;
}
verifyBuffer = NULL;
if (verifyArray) delete verifyArray;
verifyArray = NULL;
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify timed out", "The verify operation timed out.");
readFile->close();
delete readFile;
readFile = NULL;
}
else
{
if (readFile)
{
readFile->close();
delete readFile;
readFile = NULL;
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read timed out", "The read operation timed out.");
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Read timed out", "The read operation timed out.");
break;
}
}
@ -758,7 +671,7 @@ void MainWindow::resetAndShowStatusPage()
void MainWindow::on_simmCapacityBox_currentIndexChanged(int index)
{
uint32_t newCapacity = (uint32_t)ui->simmCapacityBox->itemData(index).toUInt();
uint32_t newCapacity = static_cast<uint32_t>(ui->simmCapacityBox->itemData(index).toUInt());
p->setSIMMCapacity(newCapacity);
QSettings settings;
if (!initializing)
@ -769,14 +682,66 @@ void MainWindow::on_simmCapacityBox_currentIndexChanged(int index)
}
}
void MainWindow::on_verifyAfterWriteBox_toggled(bool checked)
void MainWindow::on_verifyBox_currentIndexChanged(int index)
{
if (index < 0) return;
VerificationOption vo = static_cast<VerificationOption>(ui->verifyBox->itemData(index).toUInt());
// Save this as the new default.
QSettings settings;
settings.setValue(verifyAfterWriteKey, checked);
p->setVerifyMode(vo);
if (!initializing)
{
if (vo == NoVerification)
{
settings.setValue(verifyAfterWriteKey, false);
settings.setValue(verifyWhileWritingKey, false);
}
else if (vo == VerifyAfterWrite)
{
settings.setValue(verifyAfterWriteKey, true);
settings.setValue(verifyWhileWritingKey, false);
}
else if (vo == VerifyWhileWriting)
{
settings.setValue(verifyAfterWriteKey, false);
settings.setValue(verifyWhileWritingKey, true);
}
}
}
void MainWindow::on_actionAbout_SIMM_Programmer_triggered()
{
AboutBox::instance()->show();
}
void MainWindow::handleVerifyFailureReply()
{
// Make a comma-separated list of IC names from this list
uint8_t badICMask = p->verifyBadChipMask();
QString icList;
bool first = true;
for (int x = 0; x < 4; x++)
{
if (badICMask & (1 << x))
{
if (first)
{
// not IC0 through IC3; IC1 through IC4.
// that's why I add one.
icList.append(QString("IC%1").arg(x+1));
first = false;
}
else
{
icList.append(QString(", IC%1").arg(x+1));
}
}
}
ui->pages->setCurrentWidget(ui->controlPage);
QMessageBox::warning(this, "Verify error", "The data read back from the SIMM did not match the data written to it. Bad data on chips: " + icList);
}

View File

@ -22,8 +22,6 @@
#include <QMainWindow>
#include <QFile>
#include <QBuffer>
#include <QByteArray>
#include "programmer.h"
namespace Ui {
@ -52,6 +50,9 @@ private slots:
void programmerWriteTotalLengthChanged(uint32_t totalLen);
void programmerWriteCompletionLengthChanged(uint32_t len);
void programmerVerifyTotalLengthChanged(uint32_t totalLen);
void programmerVerifyCompletionLengthChanged(uint32_t len);
void programmerElectricalTestStatusChanged(ElectricalTestStatus newStatus);
void programmerElectricalTestLocation(uint8_t loc1, uint8_t loc2);
@ -80,7 +81,7 @@ private slots:
void on_actionAbout_SIMM_Programmer_triggered();
void on_verifyAfterWriteBox_toggled(bool checked);
void on_verifyBox_currentIndexChanged(int index);
private:
Ui::MainWindow *ui;
@ -89,12 +90,10 @@ private:
bool readFileValid;
QFile *writeFile;
QFile *readFile;
QBuffer *verifyBuffer;
QByteArray *verifyArray;
QString electricalTestString;
bool readVerifying;
void resetAndShowStatusPage();
void handleVerifyFailureReply();
};
#endif // MAINWINDOW_H

View File

@ -82,14 +82,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="verifyAfterWriteBox">
<property name="text">
<string>Verify contents after write</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QComboBox" name="verifyBox"/>
</item>
<item>
<spacer name="horizontalSpacer_2">

View File

@ -27,6 +27,7 @@ typedef enum ProgrammerCommandState
WaitingForNextCommand = 0,
WriteSIMMWaitingSetSizeReply,
WriteSIMMWaitingSetVerifyModeReply,
WriteSIMMWaitingEraseReply,
WriteSIMMWaitingWriteReply,
WriteSIMMWaitingFinishReply,
@ -82,7 +83,9 @@ typedef enum ProgrammerCommand
EnterProgrammer,
BootloaderEraseAndWriteProgram,
SetSIMMTypePLCC32_2MB,
SetSIMMTypeLarger
SetSIMMTypeLarger,
SetVerifyWhileWriting,
SetNoVerifyWhileWriting
} ProgrammerCommand;
typedef enum ProgrammerReply
@ -118,7 +121,8 @@ typedef enum ProgrammerWriteReply
{
ProgrammerWriteOK,
ProgrammerWriteError,
ProgrammerWriteConfirmCancel
ProgrammerWriteConfirmCancel,
ProgrammerWriteVerificationError = 0x80 /* high bit */
} ProgrammerWriteReply;
typedef enum ProgrammerIdentifyReply
@ -173,6 +177,11 @@ static QString programmerBoardPortName;
Programmer::Programmer(QObject *parent) :
QObject(parent)
{
_verifyMode = VerifyAfterWrite;
_verifyBadChipMask = 0;
verifyArray = new QByteArray();
verifyBuffer = new QBuffer(verifyArray);
verifyBuffer->open(QBuffer::ReadWrite);
serialPort = new QextSerialPort(QextSerialPort::EventDriven);
connect(serialPort, SIGNAL(readyRead()), SLOT(dataReady()));
}
@ -181,9 +190,19 @@ Programmer::~Programmer()
{
closePort();
delete serialPort;
verifyBuffer->close();
delete verifyBuffer;
delete verifyArray;
}
void Programmer::readSIMM(QIODevice *device, uint32_t len)
{
// We're not verifying in this case
isReadVerifying = false;
internalReadSIMM(device, len);
}
void Programmer::internalReadSIMM(QIODevice *device, uint32_t len)
{
readDevice = device;
lenRead = 0;
@ -268,17 +287,27 @@ void Programmer::handleChar(uint8_t c)
case WaitingForNextCommand:
// Not expecting anything. Ignore it.
break;
// Expecting reply after we told the programmer the size of SIMM to expect
case WriteSIMMWaitingSetSizeReply:
switch (c)
{
case CommandReplyOK:
// If we got an OK reply, we're ready to go, so start...
// If we got an OK reply, we're good to go. Next, check for the
// "verify while writing" capability if needed...
// 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;
uint8_t verifyCommand;
if (verifyMode() == VerifyWhileWriting)
{
verifyCommand = SetVerifyWhileWriting;
}
else
{
verifyCommand = SetNoVerifyWhileWriting;
}
curState = WriteSIMMWaitingSetVerifyModeReply;
sendByte(verifyCommand);
break;
case CommandReplyInvalid:
case CommandReplyError:
@ -293,7 +322,7 @@ void Programmer::handleChar(uint8_t c)
qDebug() << "Programmer board needs firmware update.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteNeedsFirmwareUpdate);
emit writeStatusChanged(WriteNeedsFirmwareUpdateBiggerSIMM);
}
else
{
@ -301,6 +330,61 @@ void Programmer::handleChar(uint8_t c)
// doesn't need updating -- it just didn't know how to handle
// the "set size" command. But that's OK -- it only supports
// the size we requested, so nothing's wrong.
// So...check for the "verify while writing" capability if needed.
uint8_t verifyCommand;
if (verifyMode() == VerifyWhileWriting)
{
verifyCommand = SetVerifyWhileWriting;
}
else
{
verifyCommand = SetNoVerifyWhileWriting;
}
curState = WriteSIMMWaitingSetVerifyModeReply;
sendByte(verifyCommand);
}
break;
}
break;
// Expecting reply from programmer after we told it to verify during write
// (or not to verify during write)
case WriteSIMMWaitingSetVerifyModeReply:
switch (c)
{
case CommandReplyOK:
// If we got an OK reply, we're ready to go, so start...
// 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;
break;
case CommandReplyInvalid:
case CommandReplyError:
// If we got an error reply, we MAY still be OK unless we were
// asking to verify while writing, in which case the firmware
// doesn't support verify during write so the user needs to know.
if (verifyMode() == VerifyWhileWriting)
{
// 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(WriteNeedsFirmwareUpdateVerifyWhileWrite);
}
else
{
// Error reply, but we're not trying to verify while writing, so
// the firmware doesn't need updating -- it just didn't know how to handle
// the "set verify mode" command. But that's OK -- we don't need
// that command if we're not verifying while writing.
// 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);
@ -311,6 +395,8 @@ void Programmer::handleChar(uint8_t c)
}
break;
// Expecting reply from programmer after we told it to erase the chip
case WriteSIMMWaitingEraseReply:
{
switch (c)
@ -332,33 +418,52 @@ void Programmer::handleChar(uint8_t c)
}
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:
switch (c)
// This is a special case in the protocol for efficiency.
if (c & ProgrammerWriteVerificationError)
{
case CommandReplyOK:
// We're in write SIMM mode. Now ask to start writing
if (writeLenRemaining > 0)
{
sendByte(ComputerWriteMore);
curState = WriteSIMMWaitingWriteMoreReply;
qDebug() << "Write more..." << writeLenRemaining << "remaining.";
}
else
{
sendByte(ComputerWriteFinish);
curState = WriteSIMMWaitingFinishReply;
qDebug() << "Finished writing. Sending write finish command...";
}
break;
case CommandReplyError:
qDebug() << "Error entering write mode.";
_verifyBadChipMask = c & ~ProgrammerWriteVerificationError;
qDebug() << "Verification error during write.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteError);
emit writeStatusChanged(WriteVerificationFailure);
break;
}
else
{
switch (c)
{
case CommandReplyOK:
// We're in write SIMM mode. Now ask to start writing
if (writeLenRemaining > 0)
{
sendByte(ComputerWriteMore);
curState = WriteSIMMWaitingWriteMoreReply;
qDebug() << "Write more..." << writeLenRemaining << "remaining.";
}
else
{
sendByte(ComputerWriteFinish);
curState = WriteSIMMWaitingFinishReply;
qDebug() << "Finished writing. Sending write finish command...";
}
break;
case CommandReplyError:
qDebug() << "Error entering write mode.";
curState = WaitingForNextCommand;
closePort();
emit writeStatusChanged(WriteError);
break;
}
}
break;
// Expecting reply from programmer after we requested to write another data chunk
case WriteSIMMWaitingWriteMoreReply:
{
switch (c)
@ -405,14 +510,41 @@ void Programmer::handleChar(uint8_t c)
}
break;
}
// Expecting reply from programmer after we told it we're done writing
case WriteSIMMWaitingFinishReply:
switch (c)
{
case ProgrammerWriteOK:
curState = WaitingForNextCommand;
qDebug() << "Write success at end";
closePort();
emit writeStatusChanged(WriteComplete);
if (verifyMode() == VerifyAfterWrite)
{
isReadVerifying = true;
// Ensure the verify buffer is empty
verifyArray->clear();
verifyBuffer->seek(0);
// Start reading from the SIMM now!
emit writeStatusChanged(WriteVerifying);
internalReadSIMM(verifyBuffer, writeDevice->size());
}
else
{
curState = WaitingForNextCommand;
qDebug() << "Write success at end";
closePort();
// Emit the correct signal based on how we finished
if (verifyMode() == NoVerification)
{
emit writeStatusChanged(WriteCompleteNoVerify);
}
else
{
emit writeStatusChanged(WriteCompleteVerifyOK);
}
}
break;
case ProgrammerWriteError:
default:
@ -427,6 +559,7 @@ void Programmer::handleChar(uint8_t c)
// ELECTRICAL TEST STATE HANDLERS
// Expecting reply from programmer after we told it to run an electrical test
case ElectricalTestWaitingStartReply:
switch (c)
{
@ -443,6 +576,9 @@ void Programmer::handleChar(uint8_t c)
emit electricalTestStatusChanged(ElectricalTestCouldntStart);
}
break;
// Expecting info from programmer about the electrical test in progress
// (Either that it's done or that it found a failure)
case ElectricalTestWaitingNextStatus:
switch (c)
{
@ -464,22 +600,33 @@ void Programmer::handleChar(uint8_t c)
break;
}
break;
// Expecting electrical test fail location #1
case ElectricalTestWaitingFirstFail:
electricalTestFirstErrorLoc = c;
curState = ElectricalTestWaitingSecondFail;
break;
// Expecting electrical test fail location #2
case ElectricalTestWaitingSecondFail:
emit electricalTestFailLocation(electricalTestFirstErrorLoc, c);
curState = ElectricalTestWaitingNextStatus;
break;
// READ SIMM STATE HANDLERS
// Expecting reply after we told the programmer to start reading
case ReadSIMMWaitingStartReply:
switch (c)
{
case CommandReplyOK:
emit readStatusChanged(ReadStarting);
if (!isReadVerifying)
{
emit readStatusChanged(ReadStarting);
}
else
{
emit writeStatusChanged(WriteVerifyStarting);
}
curState = ReadSIMMWaitingLengthReply;
// Send the length requesting to be read
@ -495,28 +642,59 @@ void Programmer::handleChar(uint8_t c)
default:
curState = WaitingForNextCommand;
closePort();
emit readStatusChanged(ReadError);
if (!isReadVerifying)
{
emit readStatusChanged(ReadError);
}
else
{
// Ensure the verify buffer is empty if we were verifying
verifyArray->clear();
verifyBuffer->seek(0);
emit writeStatusChanged(WriteVerifyError);
}
break;
}
break;
// Expecting reply after we gave the programmer a length to read
case ReadSIMMWaitingLengthReply:
switch (c)
{
case ProgrammerReadOK:
curState = ReadSIMMWaitingData;
emit readTotalLengthChanged(lenRemaining);
emit readCompletionLengthChanged(0);
if (!isReadVerifying)
{
emit readTotalLengthChanged(lenRemaining);
emit readCompletionLengthChanged(0);
}
else
{
emit writeVerifyTotalLengthChanged(lenRemaining);
emit writeVerifyCompletionLengthChanged(0);
}
readChunkLenRemaining = READ_CHUNK_SIZE;
break;
case ProgrammerReadError:
default:
curState = WaitingForNextCommand;
closePort();
emit readStatusChanged(ReadError);
if (!isReadVerifying)
{
emit readStatusChanged(ReadError);
}
else
{
// Ensure the verify buffer is empty if we were verifying
verifyArray->clear();
verifyBuffer->seek(0);
emit writeStatusChanged(WriteVerifyError);
}
break;
}
break;
// Expecting a chunk of data back from the programmer
case ReadSIMMWaitingData:
// Only keep adding to the readback if we need to
if (lenRead < trueLenToRead)
@ -527,24 +705,51 @@ void Programmer::handleChar(uint8_t c)
lenRead++;
if (--readChunkLenRemaining == 0)
{
emit readCompletionLengthChanged(lenRead);
if (!isReadVerifying)
{
emit readCompletionLengthChanged(lenRead);
}
else
{
emit writeVerifyCompletionLengthChanged(lenRead);
}
qDebug() << "Received a chunk of data";
sendByte(ComputerReadOK);
curState = ReadSIMMWaitingStatusReply;
}
break;
// Expecting status reply from programmer after we confirmed reception of
// previous chunk of data
case ReadSIMMWaitingStatusReply:
switch (c)
{
case ProgrammerReadFinished:
curState = WaitingForNextCommand;
closePort();
emit readStatusChanged(ReadComplete);
if (!isReadVerifying)
{
emit readStatusChanged(ReadComplete);
}
else
{
doVerifyAfterWriteCompare();
}
break;
case ProgrammerReadConfirmCancel:
curState = WaitingForNextCommand;
closePort();
emit readStatusChanged(ReadCancelled);
if (!isReadVerifying)
{
emit readStatusChanged(ReadCancelled);
}
else
{
// Ensure the verify buffer is empty if we were verifying
verifyArray->clear();
verifyBuffer->seek(0);
emit writeStatusChanged(WriteVerifyCancelled);
}
break;
case ProgrammerReadMoreData:
curState = ReadSIMMWaitingData;
@ -555,6 +760,9 @@ void Programmer::handleChar(uint8_t c)
break;
// BOOTLOADER STATE HANDLERS
// Expecting reply after we asked for bootloader state (original request is
// to end up in programmer mode)
case BootloaderStateAwaitingOKReply:
if (c == CommandReplyOK)
{
@ -568,17 +776,14 @@ void Programmer::handleChar(uint8_t c)
// TODO: Error out somehow
}
break;
// Expecting bootloader state after request was confirmed (original request
// is to end up in programmer mode)
case BootloaderStateAwaitingReply:
switch (c)
{
case BootloaderStateInBootloader:
// Oops! We're in the bootloader. Better change over to the programmer.
// TODO: Send "enter programmer" command.
// Close serial port.
// Wait for serial port to reappear (or just wait a fixed time?)
// Open serial port.
// Ensure we're in the programmer?
// Then do the command correctly
qDebug() << "We're in the bootloader, so sending an \"enter programmer\" request.";
emit startStatusChanged(ProgrammerInitializing);
sendByte(EnterProgrammer);
@ -600,6 +805,8 @@ void Programmer::handleChar(uint8_t c)
}
break;
// Expecting reply after we asked for bootloader state (original request is
// to end up in bootloader mode)
case BootloaderStateAwaitingOKReplyToBootloader:
if (c == CommandReplyOK)
{
@ -613,17 +820,14 @@ void Programmer::handleChar(uint8_t c)
// TODO: Error out somehow
}
break;
// Expecting bootloader state after request was confirmed (original request
// is to end up in bootloader mode)
case BootloaderStateAwaitingReplyToBootloader:
switch (c)
{
case BootloaderStateInProgrammer:
// Oops! We're in the programmer. Better change over to the bootloader.
// TODO: Send "enter bootloader" command.
// Close serial port.
// Wait for serial port to reappear (or just wait a fixed time?)
// Open serial port.
// Ensure we're in the bootloader?
// Then do the command correctly
qDebug() << "We're in the programmer, so sending an \"enter bootloader\" request.";
emit startStatusChanged(ProgrammerInitializing);
sendByte(EnterBootloader);
@ -646,6 +850,8 @@ void Programmer::handleChar(uint8_t c)
break;
// IDENTIFICATION STATE HANDLERS
// // Expecting reply after we told the programmer what size of SIMM to use
case IdentificationWaitingSetSizeReply:
switch (c)
{
@ -681,6 +887,8 @@ void Programmer::handleChar(uint8_t c)
break;
}
break;
// Expecting reply after we asked to identify chips
case IdentificationAwaitingOKReply:
if (c == CommandReplyOK)
{
@ -697,6 +905,8 @@ void Programmer::handleChar(uint8_t c)
curState = WaitingForNextCommand;
}
break;
// Expecting device/manufacturer info about the chips
case IdentificationWaitingData:
if (identificationCounter & 1) // device ID?
{
@ -713,6 +923,8 @@ void Programmer::handleChar(uint8_t c)
curState = IdentificationAwaitingDoneReply;
}
break;
// Expecting final done confirmation after receiving all device/manufacturer info
case IdentificationAwaitingDoneReply:
curState = WaitingForNextCommand;
closePort();
@ -727,6 +939,8 @@ void Programmer::handleChar(uint8_t c)
break;
// WRITE BOOTLOADER PROGRAM STATE HANDLERS
// Expecting reply after we asked to flash the firmware
case BootloaderEraseProgramAwaitingStartOKReply:
if (c == CommandReplyOK)
{
@ -742,6 +956,8 @@ void Programmer::handleChar(uint8_t c)
emit firmwareFlashStatusChanged(FirmwareFlashError);
}
break;
// Expecting reply after we told bootloader we're done flashing firmware
case BootloaderEraseProgramWaitingFinishReply:
if (c == BootloaderWriteOK)
{
@ -758,6 +974,8 @@ void Programmer::handleChar(uint8_t c)
emit firmwareFlashStatusChanged(FirmwareFlashError);
}
break;
// Expecting reply after we asked to write more firmware data
case BootloaderEraseProgramWaitingWriteMoreReply:
if (c == BootloaderWriteOK)
{
@ -797,6 +1015,8 @@ void Programmer::handleChar(uint8_t c)
emit firmwareFlashStatusChanged(FirmwareFlashError);
}
break;
// Expecting reply after we sent a chunk of firmware data
case BootloaderEraseProgramWaitingWriteReply:
if (c == CommandReplyOK)
{
@ -1086,7 +1306,78 @@ void Programmer::setSIMMCapacity(uint32_t bytes)
_simmCapacity = bytes;
}
uint32_t Programmer::SIMMCapacity()
uint32_t Programmer::SIMMCapacity() const
{
return _simmCapacity;
}
void Programmer::setVerifyMode(VerificationOption mode)
{
_verifyMode = mode;
}
VerificationOption Programmer::verifyMode() const
{
return _verifyMode;
}
void Programmer::doVerifyAfterWriteCompare()
{
// Do the comparison, emit the correct signal
// Read the entire file we just wrote into a QByteArray
writeDevice->seek(0);
QByteArray originalFileContents = writeDevice->readAll();
WriteStatus emitStatus;
// Now, compare the readback (but only for the length of originalFileContents
// (because the readback might be longer since it has to be a multiple of
// READ_CHUNK_SIZE)
if (originalFileContents.size() <= verifyArray->size())
{
const char *fileBytesPtr = originalFileContents.constData();
const char *readBytesPtr = verifyArray->constData();
if (memcmp(fileBytesPtr, readBytesPtr, originalFileContents.size()) != 0)
{
// Now let's do some trickery and figure out which chip is acting up (or chips)
_verifyBadChipMask = 0;
// Keep a list of which chips are reading bad data back
for (int x = 0; (x < originalFileContents.size()) && (_verifyBadChipMask != 0xF); x++)
{
if (fileBytesPtr[x] != readBytesPtr[x])
{
// OK, we found a mismatched byte. Now look at
// which byte (0-3) it is in each 4-byte group.
// If it's byte 0, it's the MOST significant byte
// because the 68k is big endian. IC4 contains the
// MSB, so IC4 is the first chip, IC3 second, and
// so on. That's why I subtract it from 3 --
// 0 through 3 get mapped to 3 through 0.
_verifyBadChipMask |= (1 << (3 - (x % 4)));
}
}
emitStatus = WriteVerificationFailure;
}
else
{
emitStatus = WriteCompleteVerifyOK;
}
}
else
{
// Wrong amount of data read back for some reason...shouldn't ever happen,
// but I'll call it a verification failure.
emitStatus = WriteVerificationFailure;
}
// Reset verification buffer to emptiness
verifyArray->clear();
verifyBuffer->seek(0);
// Finally, emit the final status signal
emit writeStatusChanged(emitStatus);
}

View File

@ -26,6 +26,7 @@
#include <qextserialport.h>
#include <qextserialenumerator.h>
#include <stdint.h>
#include <QBuffer>
typedef enum StartStatus
{
@ -45,14 +46,22 @@ typedef enum ReadStatus
typedef enum WriteStatus
{
WriteErasing,
WriteComplete,
WriteCompleteNoVerify,
WriteError,
WriteCancelled,
WriteEraseComplete,
WriteEraseFailed,
WriteTimedOut,
WriteFileTooBig,
WriteNeedsFirmwareUpdate
WriteNeedsFirmwareUpdateBiggerSIMM,
WriteNeedsFirmwareUpdateVerifyWhileWrite,
WriteVerifying,
WriteVerificationFailure,
WriteVerifyStarting,
WriteVerifyError,
WriteVerifyCancelled,
WriteVerifyTimedOut,
WriteCompleteVerifyOK
} WriteStatus;
typedef enum ElectricalTestStatus
@ -82,6 +91,14 @@ typedef enum FirmwareFlashStatus
FirmwareFlashTimedOut
} FirmwareFlashStatus;
// Various choices for verification
typedef enum VerificationOption
{
NoVerification,
VerifyWhileWriting,
VerifyAfterWrite
} VerificationOption;
// Electrical test indexes
#define GROUND_FAIL_INDEX 0xFF
@ -108,7 +125,10 @@ public:
void flashFirmware(QString filename);
void startCheckingPorts();
void setSIMMCapacity(uint32_t bytes);
uint32_t SIMMCapacity();
uint32_t SIMMCapacity() const;
void setVerifyMode(VerificationOption mode);
VerificationOption verifyMode() const;
uint8_t verifyBadChipMask() const { return _verifyBadChipMask; }
signals:
void startStatusChanged(StartStatus status);
@ -119,6 +139,8 @@ signals:
void writeStatusChanged(WriteStatus status);
void writeTotalLengthChanged(uint32_t total);
void writeCompletionLengthChanged(uint32_t len);
void writeVerifyTotalLengthChanged(uint32_t total);
void writeVerifyCompletionLengthChanged(uint32_t total);
void electricalTestStatusChanged(ElectricalTestStatus status);
void electricalTestFailLocation(uint8_t loc1, uint8_t loc2);
@ -164,11 +186,19 @@ private:
uint32_t firmwareLenRemaining;
uint32_t firmwareLenWritten;
VerificationOption _verifyMode;
uint8_t _verifyBadChipMask;
bool isReadVerifying;
QBuffer *verifyBuffer;
QByteArray *verifyArray;
void openPort();
void closePort();
void internalReadSIMM(QIODevice *device, uint32_t len);
void startProgrammerCommand(uint8_t commandByte, uint32_t newState);
void startBootloaderCommand(uint8_t commandByte, uint32_t newState);
void doVerifyAfterWriteCompare();
private slots:
void dataReady();

View File

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