diff --git a/mainwindow.cpp b/mainwindow.cpp index 82c2da1..2adb56d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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(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(); diff --git a/mainwindow.h b/mainwindow.h index a851cb8..20a34d7 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -83,6 +83,8 @@ private slots: void on_verifyBox_currentIndexChanged(int index); + void on_howMuchToWriteBox_currentIndexChanged(int index); + private: Ui::MainWindow *ui; bool initializing; diff --git a/mainwindow.ui b/mainwindow.ui index 4c5517f..6a70faf 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -84,6 +84,9 @@ + + + diff --git a/programmer.cpp b/programmer.cpp index 990c515..de50028 100644 --- a/programmer.cpp +++ b/programmer.cpp @@ -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; diff --git a/programmer.h b/programmer.h index c104a36..bf4a5cf 100644 --- a/programmer.h +++ b/programmer.h @@ -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(); diff --git a/version.h b/version.h index 6a6407a..2e171ed 100644 --- a/version.h +++ b/version.h @@ -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)