diff --git a/mainwindow.cpp b/mainwindow.cpp index 2adb56d..962de34 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -35,7 +35,11 @@ static Programmer *p; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + writeFile(NULL), + readFile(NULL), + writeBuffer(NULL), + readBuffer(NULL) { initializing = true; // Make default QSettings use these settings @@ -46,6 +50,7 @@ MainWindow::MainWindow(QWidget *parent) : p = new Programmer(); ui->setupUi(this); + hideFlashIndividualControls(); ui->pages->setCurrentWidget(ui->notConnectedPage); ui->actionUpdate_firmware->setEnabled(false); @@ -122,9 +127,6 @@ MainWindow::MainWindow(QWidget *parent) : ui->statusLabel->setText(""); ui->cancelButton->setEnabled(false); - readFile = NULL; - writeFile = 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))); @@ -144,6 +146,37 @@ MainWindow::MainWindow(QWidget *parent) : connect(p, SIGNAL(programmerBoardDisconnectedDuringOperation()), SLOT(programmerBoardDisconnectedDuringOperation())); p->startCheckingPorts(); + // Set up the multi chip flasher UI -- connect signals + connect(ui->chosenFlashIC1File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenFlashIC2File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenFlashIC3File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenFlashIC4File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + + connect(ui->chosenReadIC1File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenReadIC2File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenReadIC3File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->chosenReadIC4File, SIGNAL(textEdited(QString)), SLOT(updateFlashIndividualControlsEnabled())); + + connect(ui->flashIC1CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->flashIC2CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->flashIC3CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->flashIC4CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + + connect(ui->readIC1CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->readIC2CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->readIC3CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + connect(ui->readIC4CheckBox, SIGNAL(clicked()), SLOT(updateFlashIndividualControlsEnabled())); + + connect(ui->selectFlashIC1Button, SIGNAL(clicked()), SLOT(selectIndividualWriteFileClicked())); + connect(ui->selectFlashIC2Button, SIGNAL(clicked()), SLOT(selectIndividualWriteFileClicked())); + connect(ui->selectFlashIC3Button, SIGNAL(clicked()), SLOT(selectIndividualWriteFileClicked())); + connect(ui->selectFlashIC4Button, SIGNAL(clicked()), SLOT(selectIndividualWriteFileClicked())); + + connect(ui->selectReadIC1Button, SIGNAL(clicked()), SLOT(selectIndividualReadFileClicked())); + connect(ui->selectReadIC2Button, SIGNAL(clicked()), SLOT(selectIndividualReadFileClicked())); + connect(ui->selectReadIC3Button, SIGNAL(clicked()), SLOT(selectIndividualReadFileClicked())); + connect(ui->selectReadIC4Button, SIGNAL(clicked()), SLOT(selectIndividualReadFileClicked())); + initializing = false; } @@ -177,6 +210,18 @@ void MainWindow::on_selectReadFileButton_clicked() void MainWindow::on_readFromSIMMButton_clicked() { + // Ensure we don't think we're in buffer writing/reading mode...we're reading to + // an actual file. + if (writeBuffer) + { + delete writeBuffer; + writeBuffer = NULL; + } + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } if (readFile) { readFile->close(); @@ -204,6 +249,18 @@ void MainWindow::on_readFromSIMMButton_clicked() void MainWindow::on_writeToSIMMButton_clicked() { + // Ensure we don't think we're in buffer writing/reading mode...we're writing + // an actual file. + if (writeBuffer) + { + delete writeBuffer; + writeBuffer = NULL; + } + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } if (writeFile) { writeFile->close(); @@ -273,7 +330,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) switch (newStatus) { case WriteErasing: - ui->statusLabel->setText("Erasing SIMM (this may take a few seconds)..."); + if (writeBuffer) + { + ui->statusLabel->setText("Erasing chip(s) to be flashed (this may take a few seconds)..."); + } + else + { + ui->statusLabel->setText("Erasing SIMM (this may take a few seconds)..."); + } break; case WriteCompleteNoVerify: if (writeFile) @@ -284,7 +348,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) } QMessageBox::information(this, "Write complete", "The write operation finished."); - ui->pages->setCurrentWidget(ui->controlPage); + + returnToControlPage(); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteCompleteVerifyOK: if (writeFile) @@ -295,9 +366,15 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) } QMessageBox::information(this, "Write complete", "The write operation finished, and the contents were verified successfully."); - ui->pages->setCurrentWidget(ui->controlPage); - break; + returnToControlPage(); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } + break; case WriteVerifying: resetAndShowStatusPage(); break; @@ -311,8 +388,15 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) delete writeFile; writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + + returnToControlPage(); QMessageBox::warning(this, "Verify error", "An error occurred reading the SIMM contents for verification."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteVerifyCancelled: if (writeFile) @@ -322,8 +406,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Verify cancelled", "The verify operation was cancelled."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteVerifyTimedOut: if (writeFile) @@ -333,8 +423,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Verify timed out", "The verify operation timed out."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteVerificationFailure: if (writeFile) @@ -347,6 +443,12 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) // The verify failure code is somewhat complicated so it's best to put // it elsewhere. handleVerifyFailureReply(); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteError: if (writeFile) @@ -356,8 +458,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Write error", "An error occurred writing to the SIMM."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteNeedsFirmwareUpdateBiggerSIMM: if (writeFile) @@ -367,8 +475,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); 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."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteNeedsFirmwareUpdateVerifyWhileWrite: if (writeFile) @@ -378,8 +492,48 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); 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."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } + break; + case WriteNeedsFirmwareUpdateErasePortion: + if (writeFile) + { + writeFile->close(); + delete writeFile; + writeFile = NULL; + } + + returnToControlPage(); + QMessageBox::warning(this, "Firmware update needed", "The programmer board needs a firmware update to support the \"erase only a portion of the SIMM\" capability. Please update the firmware and try again."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } + break; + case WriteNeedsFirmwareUpdateIndividualChips: + if (writeFile) + { + writeFile->close(); + delete writeFile; + writeFile = NULL; + } + + returnToControlPage(); + QMessageBox::warning(this, "Firmware update needed", "The programmer board needs a firmware update to support the \"program individual chips\" capability. Please update the firmware and try again."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteCancelled: if (writeFile) @@ -389,8 +543,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Write cancelled", "The write operation was cancelled."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteEraseComplete: ui->statusLabel->setText("Writing SIMM..."); @@ -403,8 +563,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Write error", "An error occurred erasing the SIMM."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteTimedOut: if (writeFile) @@ -414,8 +580,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Write timed out", "The write operation timed out."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteFileTooBig: if (writeFile) @@ -425,8 +597,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); 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."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; case WriteEraseBlockWrongSize: if (writeFile) @@ -436,8 +614,14 @@ void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus) writeFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Bad erase size", "The programmer cannot handle the erase size you chose."); + if (writeBuffer) + { + writeBuffer->close(); + delete writeBuffer; + writeBuffer = NULL; + } break; } } @@ -523,9 +707,18 @@ void MainWindow::programmerReadStatusChanged(ReadStatus newStatus) delete readFile; readFile = NULL; } + if (readBuffer) + { + finishMultiRead(); + } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::information(this, "Read complete", "The read operation finished."); + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } break; case ReadError: if (readFile) @@ -535,8 +728,13 @@ void MainWindow::programmerReadStatusChanged(ReadStatus newStatus) readFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Read error", "An error occurred reading from the SIMM."); + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } break; case ReadCancelled: if (readFile) @@ -546,8 +744,13 @@ void MainWindow::programmerReadStatusChanged(ReadStatus newStatus) readFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Read cancelled", "The read operation was cancelled."); + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } break; case ReadTimedOut: if (readFile) @@ -557,8 +760,13 @@ void MainWindow::programmerReadStatusChanged(ReadStatus newStatus) readFile = NULL; } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); QMessageBox::warning(this, "Read timed out", "The read operation timed out."); + if (readBuffer) + { + delete readBuffer; + readBuffer = NULL; + } break; } } @@ -668,7 +876,7 @@ void MainWindow::on_identifyButton_clicked() void MainWindow::programmerBoardConnected() { - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); ui->actionUpdate_firmware->setEnabled(true); } @@ -794,6 +1002,467 @@ void MainWindow::handleVerifyFailureReply() } } - ui->pages->setCurrentWidget(ui->controlPage); + returnToControlPage(); 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); } + +void MainWindow::on_flashIndividualEnterButton_clicked() +{ + showFlashIndividualControls(); + updateFlashIndividualControlsEnabled(); + ui->pages->setCurrentWidget(ui->flashChipsPage); +} + +void MainWindow::on_returnNormalButton_clicked() +{ + hideFlashIndividualControls(); // to allow the window to be shrunk when not active + ui->pages->setCurrentWidget(ui->controlPage); +} + +void MainWindow::hideFlashIndividualControls() +{ + ui->chosenFlashIC1File->hide(); + ui->chosenFlashIC2File->hide(); + ui->chosenFlashIC3File->hide(); + ui->chosenFlashIC4File->hide(); + + ui->chosenReadIC1File->hide(); + ui->chosenReadIC2File->hide(); + ui->chosenReadIC3File->hide(); + ui->chosenReadIC4File->hide(); + + ui->flashIC1CheckBox->hide(); + ui->flashIC2CheckBox->hide(); + ui->flashIC3CheckBox->hide(); + ui->flashIC4CheckBox->hide(); + + ui->readIC1CheckBox->hide(); + ui->readIC2CheckBox->hide(); + ui->readIC3CheckBox->hide(); + ui->readIC4CheckBox->hide(); + + ui->selectFlashIC1Button->hide(); + ui->selectFlashIC2Button->hide(); + ui->selectFlashIC3Button->hide(); + ui->selectFlashIC4Button->hide(); + + ui->selectReadIC1Button->hide(); + ui->selectReadIC2Button->hide(); + ui->selectReadIC3Button->hide(); + ui->selectReadIC4Button->hide(); + + ui->multiFlashChipsButton->hide(); + ui->multiReadChipsButton->hide(); + + ui->returnNormalButton->hide(); +} + +void MainWindow::showFlashIndividualControls() +{ + ui->chosenFlashIC1File->show(); + ui->chosenFlashIC2File->show(); + ui->chosenFlashIC3File->show(); + ui->chosenFlashIC4File->show(); + + ui->chosenReadIC1File->show(); + ui->chosenReadIC2File->show(); + ui->chosenReadIC3File->show(); + ui->chosenReadIC4File->show(); + + ui->flashIC1CheckBox->show(); + ui->flashIC2CheckBox->show(); + ui->flashIC3CheckBox->show(); + ui->flashIC4CheckBox->show(); + + ui->readIC1CheckBox->show(); + ui->readIC2CheckBox->show(); + ui->readIC3CheckBox->show(); + ui->readIC4CheckBox->show(); + + ui->selectFlashIC1Button->show(); + ui->selectFlashIC2Button->show(); + ui->selectFlashIC3Button->show(); + ui->selectFlashIC4Button->show(); + + ui->selectReadIC1Button->show(); + ui->selectReadIC2Button->show(); + ui->selectReadIC3Button->show(); + ui->selectReadIC4Button->show(); + + ui->multiFlashChipsButton->show(); + ui->multiReadChipsButton->show(); + + ui->returnNormalButton->show(); +} + +void MainWindow::updateFlashIndividualControlsEnabled() +{ + int numWriteFilesChecked = 0; + int numReadFilesChecked = 0; + bool hasBadWriteFileName = false; + bool hasBadReadFileName = false; + + QCheckBox * const flashBoxes[] = {ui->flashIC1CheckBox, + ui->flashIC2CheckBox, + ui->flashIC3CheckBox, + ui->flashIC4CheckBox}; + QCheckBox * const readBoxes[] = {ui->readIC1CheckBox, + ui->readIC2CheckBox, + ui->readIC3CheckBox, + ui->readIC4CheckBox}; + QPushButton * const flashSelectButtons[] = {ui->selectFlashIC1Button, + ui->selectFlashIC2Button, + ui->selectFlashIC3Button, + ui->selectFlashIC4Button}; + QPushButton * const readSelectButtons[] = {ui->selectReadIC1Button, + ui->selectReadIC2Button, + ui->selectReadIC3Button, + ui->selectReadIC4Button}; + QLineEdit * const flashChosenFileEdits[] = {ui->chosenFlashIC1File, + ui->chosenFlashIC2File, + ui->chosenFlashIC3File, + ui->chosenFlashIC4File}; + QLineEdit * const readChosenFileEdits[] = {ui->chosenReadIC1File, + ui->chosenReadIC2File, + ui->chosenReadIC3File, + ui->chosenReadIC4File}; + + for (size_t x = 0; x < sizeof(flashBoxes)/sizeof(flashBoxes[0]); x++) + { + bool isChecked = flashBoxes[x]->isChecked(); + + flashChosenFileEdits[x]->setEnabled(isChecked); + flashSelectButtons[x]->setEnabled(isChecked); + if (isChecked) + { + numWriteFilesChecked++; + QFileInfo fi(flashChosenFileEdits[x]->text()); + if (flashChosenFileEdits[x]->text().isEmpty() || !fi.exists() || !fi.isFile()) + { + hasBadWriteFileName = true; + } + } + + isChecked = readBoxes[x]->isChecked(); + + readChosenFileEdits[x]->setEnabled(isChecked); + readSelectButtons[x]->setEnabled(isChecked); + if (isChecked) + { + numReadFilesChecked++; + QFileInfo fi(readChosenFileEdits[x]->text()); + if (readChosenFileEdits[x]->text().isEmpty() || !fi.dir().exists()) + { + hasBadReadFileName = true; + } + } + } + + // All of the individual controls should be handled; now do the two main + // buttons. + if ((numWriteFilesChecked == 0) || hasBadWriteFileName) + { + ui->multiFlashChipsButton->setEnabled(false); + } + else + { + ui->multiFlashChipsButton->setEnabled(true); + } + + if ((numReadFilesChecked == 0) || hasBadReadFileName) + { + ui->multiReadChipsButton->setEnabled(false); + } + else + { + ui->multiReadChipsButton->setEnabled(true); + } +} + +void MainWindow::selectIndividualWriteFileClicked() +{ + QString filename = QFileDialog::getOpenFileName(this, "Select a file to write to the chip:"); + if (!filename.isNull()) + { + if (sender() == static_cast(ui->selectFlashIC1Button)) + { + ui->chosenFlashIC1File->setText(filename); + } + else if (sender() == static_cast(ui->selectFlashIC2Button)) + { + ui->chosenFlashIC2File->setText(filename); + } + else if (sender() == static_cast(ui->selectFlashIC3Button)) + { + ui->chosenFlashIC3File->setText(filename); + } + else if (sender() == static_cast(ui->selectFlashIC4Button)) + { + ui->chosenFlashIC4File->setText(filename); + } + updateFlashIndividualControlsEnabled(); + } +} + +void MainWindow::selectIndividualReadFileClicked() +{ + QString filename = QFileDialog::getSaveFileName(this, "Save binary file as:"); + if (!filename.isNull()) + { + if (sender() == static_cast(ui->selectReadIC1Button)) + { + ui->chosenReadIC1File->setText(filename); + } + else if (sender() == static_cast(ui->selectReadIC2Button)) + { + ui->chosenReadIC2File->setText(filename); + } + else if (sender() == static_cast(ui->selectReadIC3Button)) + { + ui->chosenReadIC3File->setText(filename); + } + else if (sender() == static_cast(ui->selectReadIC4Button)) + { + ui->chosenReadIC4File->setText(filename); + } + updateFlashIndividualControlsEnabled(); + } +} + +void MainWindow::on_multiFlashChipsButton_clicked() +{ + QCheckBox * const flashBoxes[] = {ui->flashIC1CheckBox, + ui->flashIC2CheckBox, + ui->flashIC3CheckBox, + ui->flashIC4CheckBox}; + + QLineEdit * const flashChosenFileEdits[] = {ui->chosenFlashIC1File, + ui->chosenFlashIC2File, + ui->chosenFlashIC3File, + ui->chosenFlashIC4File}; + + // Read up to four files and create a combined image that we flash using + // the standard procedure... + if (writeBuffer) + { + delete writeBuffer; + } + writeBuffer = new QBuffer(); + qint64 maxSize = 0; + bool hadError = false; + uint8_t chipsMask = 0; + + // Read each file and ensure it exists. Oh, and create the mask of which + // chips we're flashing. + QFile *files[sizeof(flashBoxes)/sizeof(flashBoxes[0])] = {NULL, NULL, NULL, NULL}; + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (flashBoxes[x]->isChecked()) + { + files[x] = new QFile(flashChosenFileEdits[x]->text()); + if (!files[x]->exists()) + { + hadError = true; + } + if (files[x]->size() > maxSize) + { + maxSize = files[x]->size(); + } + files[x]->open(QFile::ReadOnly); + // Create our chip mask. chip mask is backward from IC numbering + // (bit 0 = IC4, bit 1 = IC3, ...) + chipsMask |= (1 << (3-x)); + } + } + + // If there was an error or one of the files picked was too big, + // error out. + if (hadError || (maxSize > (p->SIMMCapacity() / 4))) + { + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (files[x]) delete files[x]; + } + + programmerWriteStatusChanged(WriteError); + return; + } + + // Combine the (up to four) files into a single + // interleaved file to send to the SIMM + writeBuffer->open(QFile::ReadWrite); + for (int x = 0; x < maxSize; x++) + { + // Go in reverse order through the files so the data is saved to + // the SIMM in the correct order + for (int y = (int)(sizeof(files)/sizeof(files[0])) - 1; y >= 0; y--) + { + char c = 0xFF; + if (files[y] && !files[y]->atEnd()) + { + files[y]->getChar(&c); + + } + writeBuffer->putChar(c); + } + } + + // Discard the temporary files + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (files[x]) + { + files[x]->close(); + delete files[x]; + } + } + + // Now go back to the beginning of the file... + // and write it! + resetAndShowStatusPage(); + writeBuffer->seek(0); + p->writeToSIMM(writeBuffer, chipsMask); +} + +void MainWindow::on_multiReadChipsButton_clicked() +{ + QCheckBox * const readBoxes[] = {ui->readIC1CheckBox, + ui->readIC2CheckBox, + ui->readIC3CheckBox, + ui->readIC4CheckBox}; + + QLineEdit * const readChosenFileEdits[] = {ui->chosenReadIC1File, + ui->chosenReadIC2File, + ui->chosenReadIC3File, + ui->chosenReadIC4File}; + + // Prepare to read the files; when the read is complete we will save + // the files as necessary + if (readBuffer) + { + delete readBuffer; + } + readBuffer = new QBuffer(); + + // Try to open each file to make sure it's writable first. Then close it. + bool hadError = false; + for (size_t x = 0; x < sizeof(readBoxes)/sizeof(readBoxes[0]); x++) + { + if (readBoxes[x]->isChecked()) + { + QFile tmp(readChosenFileEdits[x]->text()); + if (!tmp.open(QFile::ReadWrite)) + { + hadError = true; + } + else + { + tmp.close(); + } + } + } + + // If there was an error creating one of the files, bail out. + if (hadError) + { + programmerReadStatusChanged(ReadError); + return; + } + + // Open up the buffer to read into + readBuffer->open(QFile::ReadWrite); + + // Now start reading it! + resetAndShowStatusPage(); + p->readSIMM(readBuffer); +} + +void MainWindow::finishMultiRead() +{ + QCheckBox * const readBoxes[] = {ui->readIC1CheckBox, + ui->readIC2CheckBox, + ui->readIC3CheckBox, + ui->readIC4CheckBox}; + + QLineEdit * const readChosenFileEdits[] = {ui->chosenReadIC1File, + ui->chosenReadIC2File, + ui->chosenReadIC3File, + ui->chosenReadIC4File}; + + bool hadError = false; + + QFile *files[sizeof(readBoxes)/sizeof(readBoxes[0])] = {NULL, NULL, NULL, NULL}; + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (readBoxes[x]->isChecked()) + { + files[x] = new QFile(readChosenFileEdits[x]->text()); + if (!files[x]->open(QFile::WriteOnly)) + { + hadError = true; + } + } + } + + if (hadError) + { + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (files[x]) delete files[x]; + } + + programmerReadStatusChanged(ReadError); + return; + } + + // Take the final read file and de-interleave it into separate chip files + readBuffer->seek(0); + while (!readBuffer->atEnd()) + { + // Go in reverse order through the files so the data is saved to the + // files in the correct order + for (int y = (int)(sizeof(files)/sizeof(files[0])) - 1; y >= 0; y--) + { + char c = 0xFF; + if (readBuffer->getChar(&c)) // grab a character... + { + // and as long as it was a success, stick it into the appropriate file + // (IF we have one), or discard it if we didn't care about the chip + // it went with. + if (files[y]) + { + files[y]->putChar(c); + } + } + else // no success? we're probably near end of SIMM. just discard it and close the file + { + files[y]->close(); + delete files[y]; + files[y] = NULL; + } + } + } + + // Close the individual files that are remaining + for (size_t x = 0; x < sizeof(files)/sizeof(files[0]); x++) + { + if (files[x]) + { + files[x]->close(); + delete files[x]; + } + } +} + +void MainWindow::returnToControlPage() +{ + // Depending on what we were doing, return to the correct page + if (writeBuffer || readBuffer) + { + ui->pages->setCurrentWidget(ui->flashChipsPage); + } + else + { + ui->pages->setCurrentWidget(ui->controlPage); + } +} diff --git a/mainwindow.h b/mainwindow.h index 20a34d7..0373a7c 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -85,6 +85,17 @@ private slots: void on_howMuchToWriteBox_currentIndexChanged(int index); + void on_flashIndividualEnterButton_clicked(); + void on_returnNormalButton_clicked(); + + void updateFlashIndividualControlsEnabled(); + void selectIndividualWriteFileClicked(); + void selectIndividualReadFileClicked(); + + void on_multiFlashChipsButton_clicked(); + void on_multiReadChipsButton_clicked(); + void finishMultiRead(); + private: Ui::MainWindow *ui; bool initializing; @@ -93,9 +104,16 @@ private: QFile *writeFile; QFile *readFile; QString electricalTestString; + QBuffer *writeBuffer; + QBuffer *readBuffer; void resetAndShowStatusPage(); void handleVerifyFailureReply(); + + void hideFlashIndividualControls(); + void showFlashIndividualControls(); + + void returnToControlPage(); }; #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui index 6a70faf..dbd5b8d 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 557 - 405 + 444 @@ -24,7 +24,7 @@ - 0 + 3 @@ -174,6 +174,13 @@ + + + + Flash individual chips... + + + @@ -207,7 +214,7 @@ - + Qt::Vertical @@ -276,6 +283,289 @@ + + + + + + Flash file(s) to chips + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Flash IC1: + + + + + + + + + + + + Select file... + + + + + + + + + Flash IC2: + + + + + + + + + + + + Select file... + + + + + + + + + + + + + + Select file... + + + + + + + + + + + + + + Select file... + + + + + + + + + Flash IC3: + + + + + + + Flash IC4: + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Flash chip(s) + + + + + + + + + + + + Read files(s) from chips + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Read IC1: + + + + + + + + + + + + Select file... + + + + + + + + + Read IC2: + + + + + + + + + + + + Select file... + + + + + + + + + + + + + + Select file... + + + + + + + + + + + + + + Select file... + + + + + + + + + Read IC3: + + + + + + + Read IC4: + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Read chip(s) + + + + + + + + + + + + + + This mode allows you to flash/read individual chips on a SIMM + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Return to normal mode + + + + + + + diff --git a/programmer.cpp b/programmer.cpp index 4a7bfe4..1cf00f3 100644 --- a/programmer.cpp +++ b/programmer.cpp @@ -28,6 +28,8 @@ typedef enum ProgrammerCommandState WriteSIMMWaitingSetSizeReply, WriteSIMMWaitingSetVerifyModeReply, + WriteSIMMWaitingSetChipMaskReply, + WriteSIMMWaitingSetChipMaskValueReply, WriteSIMMWaitingEraseReply, WriteSIMMWaitingWriteReply, WriteSIMMWaitingFinishReply, @@ -65,6 +67,8 @@ typedef enum ProgrammerCommandState WritePortionWaitingSetSizeReply, WritePortionWaitingSetVerifyModeReply, + WritePortionWaitingSetChipMaskReply, + WritePortionWaitingSetChipMaskValueReply, WritePortionWaitingEraseReply, WritePortionWaitingEraseConfirmation, WritePortionWaitingEraseResult, @@ -96,7 +100,8 @@ typedef enum ProgrammerCommand SetNoVerifyWhileWriting, ErasePortion, WriteChipsAt, - ReadChipsAt + ReadChipsAt, + SetChipsMask } ProgrammerCommand; typedef enum ProgrammerReply @@ -259,9 +264,10 @@ void Programmer::internalReadSIMM(QIODevice *device, uint32_t len, uint32_t offs } } -void Programmer::writeToSIMM(QIODevice *device) +void Programmer::writeToSIMM(QIODevice *device, uint8_t chipsMask) { writeDevice = device; + writeChipMask = chipsMask; if (writeDevice->size() > SIMMCapacity()) { curState = WaitingForNextCommand; @@ -288,9 +294,10 @@ void Programmer::writeToSIMM(QIODevice *device) } } -void Programmer::writeToSIMM(QIODevice *device, uint32_t startOffset, uint32_t length) +void Programmer::writeToSIMM(QIODevice *device, uint32_t startOffset, uint32_t length, uint8_t chipsMask) { writeDevice = device; + writeChipMask = chipsMask; if ((writeDevice->size() > SIMMCapacity()) || (startOffset + length > SIMMCapacity())) { @@ -451,20 +458,16 @@ void Programmer::handleChar(uint8_t c) 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); + // If we got an OK reply, we're good. Now try to set the chip mask. if (curState == WriteSIMMWaitingSetVerifyModeReply) { - sendByte(EraseChips); - curState = WriteSIMMWaitingEraseReply; + sendByte(SetChipsMask); + curState = WriteSIMMWaitingSetChipMaskReply; } else if (curState == WritePortionWaitingSetVerifyModeReply) { - sendByte(ErasePortion); - curState = WritePortionWaitingEraseReply; + sendByte(SetChipsMask); + curState = WritePortionWaitingSetChipMaskReply; } break; case CommandReplyInvalid: @@ -488,20 +491,104 @@ void Programmer::handleChar(uint8_t c) // 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. + + // So move onto the next thing to try. + if (curState == WriteSIMMWaitingSetVerifyModeReply) + { + sendByte(SetChipsMask); + curState = WriteSIMMWaitingSetChipMaskReply; + } + else if (curState == WritePortionWaitingSetVerifyModeReply) + { + sendByte(SetChipsMask); + curState = WritePortionWaitingSetChipMaskReply; + } + } + break; + } + + break; + + case WriteSIMMWaitingSetChipMaskReply: + case WritePortionWaitingSetChipMaskReply: + switch (c) + { + case CommandReplyOK: + // OK, now we can send the chip mask and move onto the next state + sendByte(writeChipMask); + if (curState == WriteSIMMWaitingSetChipMaskReply) + { + curState = WriteSIMMWaitingSetChipMaskValueReply; + } + else if (curState == WritePortionWaitingSetChipMaskReply) + { + curState = WritePortionWaitingSetChipMaskValueReply; + } + break; + case CommandReplyInvalid: + case CommandReplyError: + // Error reply. If we're trying to set a mask of 0x0F, no error, it + // just means the firmware's out of date and doesn't support setting + // custom chip masks. Ignore and move on. + if (writeChipMask == 0x0F) + { + // OK, erase the SIMM and get the ball rolling. // 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); - if (curState == WriteSIMMWaitingSetVerifyModeReply) + if (curState == WriteSIMMWaitingSetChipMaskReply) { sendByte(EraseChips); curState = WriteSIMMWaitingEraseReply; } - else if (curState == WritePortionWaitingSetVerifyModeReply) + else if (curState == WritePortionWaitingSetChipMaskReply) { sendByte(ErasePortion); curState = WritePortionWaitingEraseReply; } } + else + { + // Uh oh -- this is an old firmware that doesn't support custom + // chip masks. Let the caller know that the programmer board + // needs a firmware update. + qDebug() << "Programmer board needs firmware update."; + curState = WaitingForNextCommand; + closePort(); + emit writeStatusChanged(WriteNeedsFirmwareUpdateIndividualChips); + } + break; + } + + break; + + case WriteSIMMWaitingSetChipMaskValueReply: + case WritePortionWaitingSetChipMaskValueReply: + switch (c) + { + case CommandReplyOK: + // OK, erase the SIMM and get the ball rolling. + // 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); + if (curState == WriteSIMMWaitingSetChipMaskValueReply) + { + sendByte(EraseChips); + curState = WriteSIMMWaitingEraseReply; + } + else if (curState == WritePortionWaitingSetChipMaskValueReply) + { + sendByte(ErasePortion); + curState = WritePortionWaitingEraseReply; + } + break; + case CommandReplyInvalid: + case CommandReplyError: + // Error after trying to set the value. + qDebug() << "Error reply setting chip mask."; + curState = WaitingForNextCommand; + closePort(); + emit writeStatusChanged(WriteError); break; } @@ -1569,7 +1656,23 @@ void Programmer::doVerifyAfterWriteCompare() } } - emitStatus = WriteVerificationFailure; + // Now make sure we're not complaining about chips we didn't + // write to...this will zero out errors on chips we weren't + // flashing, but will leave errors intact for chips we did write. + // (the chip mask is backwards from the IC numbering...that's why + // I have to do this in a special way) + if ((writeChipMask & 0x01) == 0) _verifyBadChipMask &= ~0x08; + if ((writeChipMask & 0x02) == 0) _verifyBadChipMask &= ~0x04; + if ((writeChipMask & 0x04) == 0) _verifyBadChipMask &= ~0x02; + if ((writeChipMask & 0x08) == 0) _verifyBadChipMask &= ~0x01; + if (_verifyBadChipMask != 0) + { + emitStatus = WriteVerificationFailure; + } + else + { + emitStatus = WriteCompleteVerifyOK; + } } else { diff --git a/programmer.h b/programmer.h index e174c54..2e8a336 100644 --- a/programmer.h +++ b/programmer.h @@ -63,7 +63,8 @@ typedef enum WriteStatus WriteVerifyTimedOut, WriteCompleteVerifyOK, WriteEraseBlockWrongSize, - WriteNeedsFirmwareUpdateErasePortion + WriteNeedsFirmwareUpdateErasePortion, + WriteNeedsFirmwareUpdateIndividualChips } WriteStatus; typedef enum ElectricalTestStatus @@ -119,8 +120,8 @@ public: explicit Programmer(QObject *parent = 0); 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 writeToSIMM(QIODevice *device, uint8_t chipsMask = 0x0F); + void writeToSIMM(QIODevice *device, uint32_t startOffset, uint32_t length, uint8_t chipsMask = 0x0F); void runElectricalTest(); QString electricalTestPinName(uint8_t index); void identifySIMMChips(); @@ -200,6 +201,7 @@ private: uint32_t writeOffset; uint32_t writeLength; + uint8_t writeChipMask; void openPort(); void closePort();