mirror of
https://github.com/steve-chamberlin/mac-rom-simm-programmer.software.git
synced 2024-06-10 20:29:28 +00:00
Initial import of SIMM programmer code into Git
This commit is contained in:
commit
348d6121f4
26
ROMSIMMFlasher.pro
Normal file
26
ROMSIMMFlasher.pro
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2011-12-14T20:57:35
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT += core gui
|
||||||
|
|
||||||
|
TARGET = ROMSIMMFlasher
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES += main.cpp\
|
||||||
|
mainwindow.cpp \
|
||||||
|
usbprogrammerfinder_win.cpp \
|
||||||
|
programmer.cpp
|
||||||
|
|
||||||
|
HEADERS += mainwindow.h \
|
||||||
|
usbprogrammerfinder.h \
|
||||||
|
programmer.h
|
||||||
|
|
||||||
|
FORMS += mainwindow.ui
|
||||||
|
|
||||||
|
include(../qextserialport/src/qextserialport.pri)
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS_RELEASE += -DQT_NO_DEBUG_OUTPUT
|
11
main.cpp
Normal file
11
main.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <QtGui/QApplication>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
365
mainwindow.cpp
Normal file
365
mainwindow.cpp
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "programmer.h"
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
static Programmer *p;
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
p = new Programmer();
|
||||||
|
ui->chosenWriteFile->setText("");
|
||||||
|
ui->chosenReadFile->setText("");
|
||||||
|
writeFileValid = false;
|
||||||
|
readFileValid = false;
|
||||||
|
ui->writeToSIMMButton->setEnabled(false);
|
||||||
|
ui->readFromSIMMButton->setEnabled(false);
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
ui->progressBar->setEnabled(false);
|
||||||
|
ui->statusLabel->setText("");
|
||||||
|
ui->cancelButton->setEnabled(false);
|
||||||
|
|
||||||
|
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(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)));
|
||||||
|
connect(p, SIGNAL(readTotalLengthChanged(uint32_t)), SLOT(programmerReadTotalLengthChanged(uint32_t)));
|
||||||
|
connect(p, SIGNAL(readCompletionLengthChanged(uint32_t)), SLOT(programmerReadCompletionLengthChanged(uint32_t)));
|
||||||
|
connect(p, SIGNAL(identificationStatusChanged(IdentificationStatus)), SLOT(programmerIdentifyStatusChanged(IdentificationStatus)));
|
||||||
|
connect(p, SIGNAL(firmwareFlashStatusChanged(FirmwareFlashStatus)), SLOT(programmerFirmwareFlashStatusChanged(FirmwareFlashStatus)));
|
||||||
|
connect(p, SIGNAL(firmwareFlashTotalLengthChanged(uint32_t)), SLOT(programmerFirmwareFlashTotalLengthChanged(uint32_t)));
|
||||||
|
connect(p, SIGNAL(firmwareFlashCompletionLengthChanged(uint32_t)), SLOT(programmerFirmwareFlashCompletionLengthChanged(uint32_t)));
|
||||||
|
|
||||||
|
/*QList<QextPortInfo> l = QextSerialEnumerator::getPorts();
|
||||||
|
foreach (QextPortInfo p, l)
|
||||||
|
{
|
||||||
|
qDebug() << "Found port...";
|
||||||
|
qDebug() << "Enum name:" << p.enumName;
|
||||||
|
qDebug() << "Friend name:" << p.friendName;
|
||||||
|
qDebug() << "Phys name:" << p.physName;
|
||||||
|
qDebug() << "Port name:" << p.portName;
|
||||||
|
qDebug() << "Product ID:" << hex << p.productID;
|
||||||
|
qDebug() << "Vendor ID:" << hex << p.vendorID;
|
||||||
|
qDebug() << "";
|
||||||
|
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
if (p.portName.startsWith("COM"))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// TODO: Do checking for valid USB ID?
|
||||||
|
|
||||||
|
if ((p.vendorID == 0x03EB) && (p.productID == 0x204B))
|
||||||
|
{
|
||||||
|
ui->portList->addItem(QString("%1 (Programmer)").arg(p.portName), QVariant(p.portName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->portList->addItem(p.portName, QVariant(p.portName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
QextSerialEnumerator *p = new QextSerialEnumerator();
|
||||||
|
connect(p, SIGNAL(deviceDiscovered(QextPortInfo)), SLOT(portDiscovered(QextPortInfo)));
|
||||||
|
connect(p, SIGNAL(deviceRemoved(QextPortInfo)), SLOT(portRemoved(QextPortInfo)));
|
||||||
|
p->setUpNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_selectWriteFileButton_clicked()
|
||||||
|
{
|
||||||
|
QString filename = QFileDialog::getOpenFileName(this, "Select a ROM image:");
|
||||||
|
if (!filename.isNull())
|
||||||
|
{
|
||||||
|
writeFileValid = true;
|
||||||
|
ui->chosenWriteFile->setText(filename);
|
||||||
|
ui->writeToSIMMButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_selectReadFileButton_clicked()
|
||||||
|
{
|
||||||
|
QString filename = QFileDialog::getSaveFileName(this, "Save ROM image as:");
|
||||||
|
if (!filename.isNull())
|
||||||
|
{
|
||||||
|
readFileValid = true;
|
||||||
|
ui->chosenReadFile->setText(filename);
|
||||||
|
ui->readFromSIMMButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_readFromSIMMButton_clicked()
|
||||||
|
{
|
||||||
|
p->ReadSIMMToFile(ui->chosenReadFile->text());
|
||||||
|
qDebug() << "Reading from SIMM...";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_writeToSIMMButton_clicked()
|
||||||
|
{
|
||||||
|
p->WriteFileToSIMM(ui->chosenWriteFile->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_chosenWriteFile_textEdited(const QString &newText)
|
||||||
|
{
|
||||||
|
QFileInfo fi(newText);
|
||||||
|
if (fi.exists() && fi.isFile())
|
||||||
|
{
|
||||||
|
ui->writeToSIMMButton->setEnabled(true);
|
||||||
|
writeFileValid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->writeToSIMMButton->setEnabled(false);
|
||||||
|
writeFileValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerWriteStatusChanged(WriteStatus newStatus)
|
||||||
|
{
|
||||||
|
switch (newStatus)
|
||||||
|
{
|
||||||
|
case WriteComplete:
|
||||||
|
QMessageBox::information(this, "Write complete", "The write operation finished.");
|
||||||
|
break;
|
||||||
|
case WriteError:
|
||||||
|
QMessageBox::warning(this, "Write error", "An error occurred writing to the SIMM.");
|
||||||
|
break;
|
||||||
|
case WriteCancelled:
|
||||||
|
QMessageBox::warning(this, "Write cancelled", "The write operation was cancelled.");
|
||||||
|
break;
|
||||||
|
case WriteEraseComplete:
|
||||||
|
// No message needed for this
|
||||||
|
break;
|
||||||
|
case WriteEraseFailed:
|
||||||
|
QMessageBox::warning(this, "Write error", "An error occurred erasing the SIMM.");
|
||||||
|
break;
|
||||||
|
case WriteTimedOut:
|
||||||
|
QMessageBox::warning(this, "Write timed out", "The write operation timed out.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerWriteTotalLengthChanged(uint32_t totalLen)
|
||||||
|
{
|
||||||
|
ui->progressBar->setMaximum((int)totalLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerWriteCompletionLengthChanged(uint32_t len)
|
||||||
|
{
|
||||||
|
ui->progressBar->setValue((int)len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_electricalTestButton_clicked()
|
||||||
|
{
|
||||||
|
electricalTestString = "";
|
||||||
|
p->RunElectricalTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerElectricalTestStatusChanged(ElectricalTestStatus newStatus)
|
||||||
|
{
|
||||||
|
switch (newStatus)
|
||||||
|
{
|
||||||
|
case ElectricalTestStarted:
|
||||||
|
qDebug() << "Electrical test started";
|
||||||
|
break;
|
||||||
|
case ElectricalTestPassed:
|
||||||
|
QMessageBox::information(this, "Test passed", "The electrical test passed successfully.");
|
||||||
|
break;
|
||||||
|
case ElectricalTestFailed:
|
||||||
|
QMessageBox::warning(this, "Test failed", "The electrical test failed:\n\n" + electricalTestString);
|
||||||
|
break;
|
||||||
|
case ElectricalTestTimedOut:
|
||||||
|
QMessageBox::warning(this, "Test timed out", "The electrical test operation timed out.");
|
||||||
|
break;
|
||||||
|
case ElectricalTestCouldntStart:
|
||||||
|
QMessageBox::warning(this, "Communication error", "Unable to communicate with programmer board.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerElectricalTestLocation(uint8_t loc1, uint8_t loc2)
|
||||||
|
{
|
||||||
|
//qDebug() << "Electrical test error at (" << p->electricalTestPinName(loc1) << "," << p->electricalTestPinName(loc2) << ")";
|
||||||
|
if (electricalTestString != "")
|
||||||
|
{
|
||||||
|
electricalTestString.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
electricalTestString.append(p->electricalTestPinName(loc1));
|
||||||
|
electricalTestString.append(" shorted to ");
|
||||||
|
electricalTestString.append(p->electricalTestPinName(loc2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerReadStatusChanged(ReadStatus newStatus)
|
||||||
|
{
|
||||||
|
switch (newStatus)
|
||||||
|
{
|
||||||
|
case ReadComplete:
|
||||||
|
QMessageBox::information(this, "Read complete", "The read operation finished.");
|
||||||
|
break;
|
||||||
|
case ReadError:
|
||||||
|
QMessageBox::warning(this, "Read error", "An error occurred reading from the SIMM.");
|
||||||
|
break;
|
||||||
|
case ReadCancelled:
|
||||||
|
QMessageBox::warning(this, "Read cancelled", "The read operation was cancelled.");
|
||||||
|
break;
|
||||||
|
case ReadTimedOut:
|
||||||
|
QMessageBox::warning(this, "Read timed out", "The read operation timed out.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerReadTotalLengthChanged(uint32_t totalLen)
|
||||||
|
{
|
||||||
|
ui->progressBar->setMaximum((int)totalLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerReadCompletionLengthChanged(uint32_t len)
|
||||||
|
{
|
||||||
|
ui->progressBar->setValue((int)len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerIdentifyStatusChanged(IdentificationStatus newStatus)
|
||||||
|
{
|
||||||
|
switch (newStatus)
|
||||||
|
{
|
||||||
|
case IdentificationComplete:
|
||||||
|
{
|
||||||
|
QString identifyString = "The chips identified themselves as:";
|
||||||
|
for (int x = 0; x < 4; x++)
|
||||||
|
{
|
||||||
|
QString thisString;
|
||||||
|
uint8_t manufacturer = 0;
|
||||||
|
uint8_t device = 0;
|
||||||
|
p->GetChipIdentity(x, &manufacturer, &device);
|
||||||
|
thisString.sprintf("\nIC%d: Manufacturer 0x%02X, Device 0x%02X", (x + 1), manufacturer, device);
|
||||||
|
identifyString.append(thisString);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::information(this, "Identification complete", identifyString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IdentificationError:
|
||||||
|
QMessageBox::warning(this, "Identification error", "An error occurred identifying the chips on the SIMM.");
|
||||||
|
break;
|
||||||
|
case IdentificationTimedOut:
|
||||||
|
QMessageBox::warning(this, "Identification timed out", "The identification operation timed out.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerFirmwareFlashStatusChanged(FirmwareFlashStatus newStatus)
|
||||||
|
{
|
||||||
|
switch (newStatus)
|
||||||
|
{
|
||||||
|
case FirmwareFlashComplete:
|
||||||
|
QMessageBox::information(this, "Firmware update complete", "The firmware update operation finished.");
|
||||||
|
break;
|
||||||
|
case FirmwareFlashError:
|
||||||
|
QMessageBox::warning(this, "Firmware update error", "An error occurred writing firmware to the device.");
|
||||||
|
break;
|
||||||
|
case FirmwareFlashCancelled:
|
||||||
|
QMessageBox::warning(this, "Firmware update cancelled", "The firmware update was cancelled.");
|
||||||
|
break;
|
||||||
|
case FirmwareFlashTimedOut:
|
||||||
|
QMessageBox::warning(this, "Firmware update timed out", "The firmware update operation timed out.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerFirmwareFlashTotalLengthChanged(uint32_t totalLen)
|
||||||
|
{
|
||||||
|
ui->progressBar->setMaximum((int)totalLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::programmerFirmwareFlashCompletionLengthChanged(uint32_t len)
|
||||||
|
{
|
||||||
|
ui->progressBar->setValue((int)len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::startOperation_updateButtons()
|
||||||
|
{
|
||||||
|
ui->writeToSIMMButton->setEnabled(false);
|
||||||
|
ui->readFromSIMMButton->setEnabled(false);
|
||||||
|
ui->identifyButton->setEnabled(false);
|
||||||
|
ui->electricalTestButton->setEnabled(false);
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
ui->progressBar->setEnabled(true);
|
||||||
|
ui->cancelButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::endOperation_updateButtons()
|
||||||
|
{
|
||||||
|
ui->writeToSIMMButton->setEnabled(writeFileValid);
|
||||||
|
ui->readFromSIMMButton->setEnabled(readFileValid);
|
||||||
|
|
||||||
|
ui->identifyButton->setEnabled(true);
|
||||||
|
ui->electricalTestButton->setEnabled(true);
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
ui->progressBar->setEnabled(false);
|
||||||
|
ui->cancelButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_actionUpdate_firmware_triggered()
|
||||||
|
{
|
||||||
|
QString filename = QFileDialog::getOpenFileName(this, "Select a firmware image:");
|
||||||
|
if (!filename.isNull())
|
||||||
|
{
|
||||||
|
p->FlashFirmware(filename);
|
||||||
|
qDebug() << "Updating firmware...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_identifyButton_clicked()
|
||||||
|
{
|
||||||
|
p->IdentifySIMMChips();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::portDiscovered(const QextPortInfo & info)
|
||||||
|
{
|
||||||
|
qDebug() << info.portName << "discovered";
|
||||||
|
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
if (info.portName.startsWith("COM"))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// TODO: Do checking for valid USB ID?
|
||||||
|
|
||||||
|
if ((info.vendorID == 0x03EB) && (info.productID == 0x204B))
|
||||||
|
{
|
||||||
|
ui->portList->addItem(QString("%1 (Programmer)").arg(info.portName), QVariant(info.portName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->portList->addItem(info.portName, QVariant(info.portName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::portRemoved(const QextPortInfo & info)
|
||||||
|
{
|
||||||
|
qDebug() << info.portName << "removed";
|
||||||
|
|
||||||
|
for (int x = ui->portList->count() - 1; x >= 0; x--)
|
||||||
|
{
|
||||||
|
if (ui->portList->itemData(x) == info.portName)
|
||||||
|
{
|
||||||
|
ui->portList->removeItem(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
mainwindow.h
Normal file
65
mainwindow.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <qextserialenumerator.h>
|
||||||
|
#include "programmer.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_selectWriteFileButton_clicked();
|
||||||
|
void on_selectReadFileButton_clicked();
|
||||||
|
|
||||||
|
void on_writeToSIMMButton_clicked();
|
||||||
|
void on_readFromSIMMButton_clicked();
|
||||||
|
|
||||||
|
void on_chosenWriteFile_textEdited(const QString &newText);
|
||||||
|
|
||||||
|
void programmerWriteStatusChanged(WriteStatus newStatus);
|
||||||
|
void programmerWriteTotalLengthChanged(uint32_t totalLen);
|
||||||
|
void programmerWriteCompletionLengthChanged(uint32_t len);
|
||||||
|
|
||||||
|
void programmerElectricalTestStatusChanged(ElectricalTestStatus newStatus);
|
||||||
|
void programmerElectricalTestLocation(uint8_t loc1, uint8_t loc2);
|
||||||
|
|
||||||
|
void programmerReadStatusChanged(ReadStatus newStatus);
|
||||||
|
void programmerReadTotalLengthChanged(uint32_t totalLen);
|
||||||
|
void programmerReadCompletionLengthChanged(uint32_t len);
|
||||||
|
|
||||||
|
void programmerIdentifyStatusChanged(IdentificationStatus newStatus);
|
||||||
|
|
||||||
|
void programmerFirmwareFlashStatusChanged(FirmwareFlashStatus newStatus);
|
||||||
|
void programmerFirmwareFlashTotalLengthChanged(uint32_t totalLen);
|
||||||
|
void programmerFirmwareFlashCompletionLengthChanged(uint32_t len);
|
||||||
|
|
||||||
|
void on_electricalTestButton_clicked();
|
||||||
|
|
||||||
|
void startOperation_updateButtons();
|
||||||
|
void endOperation_updateButtons();
|
||||||
|
|
||||||
|
void on_actionUpdate_firmware_triggered();
|
||||||
|
|
||||||
|
void on_identifyButton_clicked();
|
||||||
|
|
||||||
|
void portDiscovered(const QextPortInfo & info);
|
||||||
|
void portRemoved(const QextPortInfo & info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
bool writeFileValid;
|
||||||
|
bool readFileValid;
|
||||||
|
QString electricalTestString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
318
mainwindow.ui
Normal file
318
mainwindow.ui
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>557</width>
|
||||||
|
<height>403</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<widget class="QWidget" name="controlPage">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="portLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Port:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="portList"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="writeGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Write file to SIMM</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="chosenWriteFile">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="selectWriteFileButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select file...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="writeToSIMMButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Write to SIMM</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="readGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Read from SIMM to file</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="chosenReadFile">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="selectReadFileButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select file...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="readFromSIMMButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Read from SIMM</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="miscGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Miscellaneous</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="identifyButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Identify chips</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="electricalTestButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Electrical test</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="statusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Status label:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="progressLayout">
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="cancelButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_2"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>557</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuAdvanced">
|
||||||
|
<property name="title">
|
||||||
|
<string>Advanced</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionUpdate_firmware"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuAdvanced"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="mainToolBar">
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionUpdate_firmware">
|
||||||
|
<property name="text">
|
||||||
|
<string>Update firmware...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>actionQuit</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>278</x>
|
||||||
|
<y>201</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
776
programmer.cpp
Normal file
776
programmer.cpp
Normal file
|
@ -0,0 +1,776 @@
|
||||||
|
#include "programmer.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
typedef enum ProgrammerCommandState
|
||||||
|
{
|
||||||
|
WaitingForNextCommand = 0,
|
||||||
|
|
||||||
|
WriteSIMMWaitingEraseReply,
|
||||||
|
WriteSIMMWaitingWriteReply,
|
||||||
|
WriteSIMMWaitingFinishReply,
|
||||||
|
WriteSIMMWaitingWriteMoreReply,
|
||||||
|
|
||||||
|
ElectricalTestWaitingStartReply,
|
||||||
|
ElectricalTestWaitingNextStatus,
|
||||||
|
ElectricalTestWaitingFirstFail,
|
||||||
|
ElectricalTestWaitingSecondFail,
|
||||||
|
|
||||||
|
ReadSIMMWaitingStartReply,
|
||||||
|
ReadSIMMWaitingData,
|
||||||
|
ReadSIMMWaitingStatusReply,
|
||||||
|
|
||||||
|
BootloaderStateAwaitingOKReply,
|
||||||
|
BootloaderStateAwaitingReply,
|
||||||
|
BootloaderStateAwaitingOKReplyToBootloader,
|
||||||
|
BootloaderStateAwaitingReplyToBootloader,
|
||||||
|
|
||||||
|
IdentificationAwaitingOKReply,
|
||||||
|
IdentificationWaitingData,
|
||||||
|
IdentificationAwaitingDoneReply,
|
||||||
|
|
||||||
|
BootloaderEraseProgramAwaitingStartOKReply,
|
||||||
|
BootloaderEraseProgramWaitingFinishReply,
|
||||||
|
BootloaderEraseProgramWaitingWriteMoreReply,
|
||||||
|
BootloaderEraseProgramWaitingWriteReply
|
||||||
|
} ProgrammerCommandState;
|
||||||
|
|
||||||
|
typedef enum ProgrammerCommand
|
||||||
|
{
|
||||||
|
EnterWaitingMode = 0,
|
||||||
|
DoElectricalTest,
|
||||||
|
IdentifyChips,
|
||||||
|
ReadByte,
|
||||||
|
ReadChips,
|
||||||
|
EraseChips,
|
||||||
|
WriteChips,
|
||||||
|
GetBootloaderState,
|
||||||
|
EnterBootloader,
|
||||||
|
EnterProgrammer,
|
||||||
|
BootloaderEraseAndWriteProgram
|
||||||
|
} ProgrammerCommand;
|
||||||
|
|
||||||
|
typedef enum ProgrammerReply
|
||||||
|
{
|
||||||
|
CommandReplyOK,
|
||||||
|
CommandReplyError,
|
||||||
|
CommandReplyInvalid
|
||||||
|
} ProgrammerReply;
|
||||||
|
|
||||||
|
typedef enum ComputerReadReply
|
||||||
|
{
|
||||||
|
ComputerReadOK,
|
||||||
|
ComputerReadCancel
|
||||||
|
} ComputerReadReply;
|
||||||
|
|
||||||
|
typedef enum ProgrammerReadReply
|
||||||
|
{
|
||||||
|
ProgrammerReadOK,
|
||||||
|
ProgrammerReadError,
|
||||||
|
ProgrammerReadMoreData,
|
||||||
|
ProgrammerReadFinished,
|
||||||
|
ProgrammerReadConfirmCancel
|
||||||
|
} ProgrammerReadReply;
|
||||||
|
|
||||||
|
typedef enum ComputerWriteReply
|
||||||
|
{
|
||||||
|
ComputerWriteMore,
|
||||||
|
ComputerWriteFinish,
|
||||||
|
ComputerWriteCancel
|
||||||
|
} ComputerWriteReply;
|
||||||
|
|
||||||
|
typedef enum ProgrammerWriteReply
|
||||||
|
{
|
||||||
|
ProgrammerWriteOK,
|
||||||
|
ProgrammerWriteError,
|
||||||
|
ProgrammerWriteConfirmCancel
|
||||||
|
} ProgrammerWriteReply;
|
||||||
|
|
||||||
|
typedef enum ProgrammerIdentifyReply
|
||||||
|
{
|
||||||
|
ProgrammerIdentifyDone
|
||||||
|
} ProgrammerIdentifyReply;
|
||||||
|
|
||||||
|
typedef enum ProgrammerElectricalTestReply
|
||||||
|
{
|
||||||
|
ProgrammerElectricalTestFail,
|
||||||
|
ProgrammerElectricalTestDone
|
||||||
|
} ProgrammerElectricalTestReply;
|
||||||
|
|
||||||
|
typedef enum BootloaderStateReply
|
||||||
|
{
|
||||||
|
BootloaderStateInBootloader,
|
||||||
|
BootloaderStateInProgrammer
|
||||||
|
} BootloaderStateReply;
|
||||||
|
|
||||||
|
typedef enum ProgrammerBootloaderEraseWriteReply
|
||||||
|
{
|
||||||
|
BootloaderWriteOK,
|
||||||
|
BootloaderWriteError,
|
||||||
|
BootloaderWriteConfirmCancel
|
||||||
|
} ProgrammerBootloaderEraseWriteReply;
|
||||||
|
|
||||||
|
typedef enum ComputerBootloaderEraseWriteRequest
|
||||||
|
{
|
||||||
|
ComputerBootloaderWriteMore = 0,
|
||||||
|
ComputerBootloaderFinish,
|
||||||
|
ComputerBootloaderCancel
|
||||||
|
} ComputerBootloaderEraseWriteRequest;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define WRITE_CHUNK_SIZE 1024
|
||||||
|
#define READ_CHUNK_SIZE 1024
|
||||||
|
#define FIRMWARE_CHUNK_SIZE 1024
|
||||||
|
|
||||||
|
static ProgrammerCommandState curState = WaitingForNextCommand;
|
||||||
|
|
||||||
|
// After identifying that we're in the main program, what will be the command
|
||||||
|
// we will send and the state we will be waiting in?
|
||||||
|
static ProgrammerCommandState nextState = WaitingForNextCommand;
|
||||||
|
static uint8_t nextSendByte = 0;
|
||||||
|
|
||||||
|
Programmer::Programmer(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
serialPort = new QextSerialPort("\\\\.\\COM13", QextSerialPort::EventDriven);
|
||||||
|
connect(serialPort, SIGNAL(readyRead()), SLOT(dataReady()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Programmer::~Programmer()
|
||||||
|
{
|
||||||
|
if (serialPort->isOpen())
|
||||||
|
{
|
||||||
|
serialPort->close();
|
||||||
|
}
|
||||||
|
delete serialPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::ReadSIMMToFile(QString filename)
|
||||||
|
{
|
||||||
|
readFile = new QFile(filename);
|
||||||
|
readFile->open(QFile::WriteOnly);
|
||||||
|
lenRead = 0;
|
||||||
|
|
||||||
|
emit readTotalLengthChanged(2 * 1024 * 1024);
|
||||||
|
emit readCompletionLengthChanged(lenRead);
|
||||||
|
|
||||||
|
startProgrammerCommand(ReadChips, ReadSIMMWaitingStartReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::WriteFileToSIMM(QString filename)
|
||||||
|
{
|
||||||
|
writeFile = new QFile(filename);
|
||||||
|
if (!writeFile->open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit writeStatusChanged(WriteError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lenWritten = 0;
|
||||||
|
writeLenRemaining = writeFile->size();
|
||||||
|
emit writeTotalLengthChanged(writeLenRemaining);
|
||||||
|
emit writeCompletionLengthChanged(lenWritten);
|
||||||
|
|
||||||
|
startProgrammerCommand(EraseChips, WriteSIMMWaitingEraseReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::sendByte(uint8_t b)
|
||||||
|
{
|
||||||
|
serialPort->write((const char *)&b, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Programmer::readByte()
|
||||||
|
{
|
||||||
|
uint8_t returnVal;
|
||||||
|
serialPort->read((char *)&returnVal, 1);
|
||||||
|
// TODO: Error checking if read fails?
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::dataReady()
|
||||||
|
{
|
||||||
|
while (!serialPort->atEnd())
|
||||||
|
{
|
||||||
|
handleChar(readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::handleChar(uint8_t c)
|
||||||
|
{
|
||||||
|
switch (curState)
|
||||||
|
{
|
||||||
|
case WaitingForNextCommand:
|
||||||
|
// Not expecting anything. Ignore it.
|
||||||
|
break;
|
||||||
|
case WriteSIMMWaitingEraseReply:
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case CommandReplyOK:
|
||||||
|
sendByte(WriteChips);
|
||||||
|
curState = WriteSIMMWaitingWriteReply;
|
||||||
|
qDebug() << "Chips erased. Now asking to start writing...";
|
||||||
|
emit writeStatusChanged(WriteEraseComplete);
|
||||||
|
break;
|
||||||
|
case CommandReplyError:
|
||||||
|
qDebug() << "Error erasing chips.";
|
||||||
|
writeFile->close();
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit writeStatusChanged(WriteEraseFailed);
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WriteSIMMWaitingWriteReply:
|
||||||
|
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.";
|
||||||
|
writeFile->close();
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit writeStatusChanged(WriteError);
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case WriteSIMMWaitingWriteMoreReply:
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ProgrammerWriteOK:
|
||||||
|
{
|
||||||
|
qDebug() << "Programmer replied OK to send 1024 bytes of data! Sending...";
|
||||||
|
// Write the next chunk of data to the SIMM...
|
||||||
|
|
||||||
|
int chunkSize = WRITE_CHUNK_SIZE;
|
||||||
|
if (writeLenRemaining < WRITE_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
chunkSize = writeLenRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the chunk from the file!
|
||||||
|
QByteArray thisChunk = writeFile->read(chunkSize);
|
||||||
|
|
||||||
|
// If it isn't a WRITE_CHUNK_SIZE chunk, pad the rest of it with 0xFFs (unprogrammed bytes)
|
||||||
|
// so the total chunk size is WRITE_CHUNK_SIZE, since that's what the programmer board expects.
|
||||||
|
for (int x = writeLenRemaining; x < WRITE_CHUNK_SIZE; x++)
|
||||||
|
{
|
||||||
|
thisChunk.append(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the chunk out (it's asynchronous so will return immediately)
|
||||||
|
serialPort->write(thisChunk);
|
||||||
|
|
||||||
|
// OK, now we're waiting to hear back from the programmer on the result
|
||||||
|
qDebug() << "Waiting for status reply...";
|
||||||
|
curState = WriteSIMMWaitingWriteReply;
|
||||||
|
writeLenRemaining -= chunkSize;
|
||||||
|
lenWritten += chunkSize;
|
||||||
|
emit writeCompletionLengthChanged(lenWritten);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ProgrammerWriteError:
|
||||||
|
default:
|
||||||
|
qDebug() << "Error writing to chips.";
|
||||||
|
writeFile->close();
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit writeStatusChanged(WriteError);
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WriteSIMMWaitingFinishReply:
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ProgrammerWriteOK:
|
||||||
|
writeFile->close();
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
qDebug() << "Write success at end";
|
||||||
|
emit writeStatusChanged(WriteComplete);
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
case ProgrammerWriteError:
|
||||||
|
default:
|
||||||
|
qDebug() << "Write failure at end";
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
writeFile->close();
|
||||||
|
emit writeStatusChanged(WriteError);
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ELECTRICAL TEST STATE HANDLERS
|
||||||
|
|
||||||
|
case ElectricalTestWaitingStartReply:
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case CommandReplyOK:
|
||||||
|
curState = ElectricalTestWaitingNextStatus;
|
||||||
|
emit electricalTestStatusChanged(ElectricalTestStarted);
|
||||||
|
electricalTestErrorCounter = 0;
|
||||||
|
break;
|
||||||
|
case CommandReplyError:
|
||||||
|
case CommandReplyInvalid:
|
||||||
|
default:
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit electricalTestStatusChanged(ElectricalTestCouldntStart);
|
||||||
|
serialPort->close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ElectricalTestWaitingNextStatus:
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ProgrammerElectricalTestDone:
|
||||||
|
if (electricalTestErrorCounter > 0)
|
||||||
|
{
|
||||||
|
emit electricalTestStatusChanged(ElectricalTestFailed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit electricalTestStatusChanged(ElectricalTestPassed);
|
||||||
|
}
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
break;
|
||||||
|
case ProgrammerElectricalTestFail:
|
||||||
|
electricalTestErrorCounter++;
|
||||||
|
curState = ElectricalTestWaitingFirstFail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ElectricalTestWaitingFirstFail:
|
||||||
|
electricalTestFirstErrorLoc = c;
|
||||||
|
curState = ElectricalTestWaitingSecondFail;
|
||||||
|
break;
|
||||||
|
case ElectricalTestWaitingSecondFail:
|
||||||
|
emit electricalTestFailLocation(electricalTestFirstErrorLoc, c);
|
||||||
|
curState = ElectricalTestWaitingNextStatus;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// READ SIMM STATE HANDLERS
|
||||||
|
case ReadSIMMWaitingStartReply:
|
||||||
|
curState = ReadSIMMWaitingData;
|
||||||
|
readChunkLenRemaining = READ_CHUNK_SIZE;
|
||||||
|
break;
|
||||||
|
case ReadSIMMWaitingData:
|
||||||
|
readFile->write((const char *)&c, 1);
|
||||||
|
lenRead++;
|
||||||
|
if (--readChunkLenRemaining == 0)
|
||||||
|
{
|
||||||
|
emit readCompletionLengthChanged(lenRead);
|
||||||
|
qDebug() << "Received a chunk of data";
|
||||||
|
sendByte(ComputerReadOK);
|
||||||
|
curState = ReadSIMMWaitingStatusReply;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ReadSIMMWaitingStatusReply:
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ProgrammerReadFinished:
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
readFile->close();
|
||||||
|
emit readStatusChanged(ReadComplete);
|
||||||
|
break;
|
||||||
|
case ProgrammerReadConfirmCancel:
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
readFile->close();
|
||||||
|
emit readStatusChanged(ReadCancelled);
|
||||||
|
break;
|
||||||
|
case ProgrammerReadMoreData:
|
||||||
|
curState = ReadSIMMWaitingData;
|
||||||
|
readChunkLenRemaining = READ_CHUNK_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// BOOTLOADER STATE HANDLERS
|
||||||
|
case BootloaderStateAwaitingOKReply:
|
||||||
|
if (c == CommandReplyOK)
|
||||||
|
{
|
||||||
|
// Good to go, now we're waiting for the "in programmer" or "in bootloader" reply.
|
||||||
|
curState = BootloaderStateAwaitingReply;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
qDebug() << "Unable to enter programmer mode";
|
||||||
|
// TODO: Error out somehow
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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.";
|
||||||
|
sendByte(EnterProgrammer);
|
||||||
|
serialPort->close();
|
||||||
|
{
|
||||||
|
QMutex mutex;
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
QWaitCondition waitCondition;
|
||||||
|
waitCondition.wait(&mutex, 5000);
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
serialPort->open(QextSerialPort::ReadWrite);
|
||||||
|
curState = nextState;
|
||||||
|
sendByte(nextSendByte);
|
||||||
|
break;
|
||||||
|
case BootloaderStateInProgrammer:
|
||||||
|
// Good to go...
|
||||||
|
// So change to the next state and send out the next command
|
||||||
|
// to begin whatever sequence of events we expected.
|
||||||
|
qDebug() << "Already in programmer. Good! Do the command now...";
|
||||||
|
curState = nextState;
|
||||||
|
sendByte(nextSendByte);
|
||||||
|
break;
|
||||||
|
// TODO: Otherwise, raise an error?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BootloaderStateAwaitingOKReplyToBootloader:
|
||||||
|
if (c == CommandReplyOK)
|
||||||
|
{
|
||||||
|
// Good to go, now we're waiting for the "in programmer" or "in bootloader" reply.
|
||||||
|
curState = BootloaderStateAwaitingReplyToBootloader;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
qDebug() << "Unable to enter bootloader mode";
|
||||||
|
// TODO: Error out somehow
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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.";
|
||||||
|
sendByte(EnterBootloader);
|
||||||
|
serialPort->close();
|
||||||
|
{
|
||||||
|
QMutex mutex;
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
QWaitCondition waitCondition;
|
||||||
|
waitCondition.wait(&mutex, 5000);
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
serialPort->open(QextSerialPort::ReadWrite);
|
||||||
|
curState = nextState;
|
||||||
|
sendByte(nextSendByte);
|
||||||
|
break;
|
||||||
|
case BootloaderStateInBootloader:
|
||||||
|
// Good to go...
|
||||||
|
// So change to the next state and send out the next command
|
||||||
|
// to begin whatever sequence of events we expected.
|
||||||
|
qDebug() << "Already in bootloader. Good! Do the command now...";
|
||||||
|
curState = nextState;
|
||||||
|
sendByte(nextSendByte);
|
||||||
|
break;
|
||||||
|
// TODO: Otherwise, raise an error?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// IDENTIFICATION STATE HANDLERS
|
||||||
|
case IdentificationAwaitingOKReply:
|
||||||
|
if (c == CommandReplyOK)
|
||||||
|
{
|
||||||
|
// Good to go, now waiting for identification data
|
||||||
|
curState = IdentificationWaitingData;
|
||||||
|
identificationCounter = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit identificationStatusChanged(IdentificationError);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IdentificationWaitingData:
|
||||||
|
if (identificationCounter & 1) // device ID?
|
||||||
|
{
|
||||||
|
chipDeviceIDs[identificationCounter/2] = c;
|
||||||
|
}
|
||||||
|
else // manufacturer ID?
|
||||||
|
{
|
||||||
|
chipManufacturerIDs[identificationCounter/2] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done?
|
||||||
|
if (++identificationCounter >= 8)
|
||||||
|
{
|
||||||
|
curState = IdentificationAwaitingDoneReply;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IdentificationAwaitingDoneReply:
|
||||||
|
if (c == ProgrammerIdentifyDone)
|
||||||
|
{
|
||||||
|
emit identificationStatusChanged(IdentificationComplete);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit identificationStatusChanged(IdentificationError);
|
||||||
|
}
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// WRITE BOOTLOADER PROGRAM STATE HANDLERS
|
||||||
|
case BootloaderEraseProgramAwaitingStartOKReply:
|
||||||
|
if (c == CommandReplyOK)
|
||||||
|
{
|
||||||
|
sendByte(ComputerBootloaderWriteMore);
|
||||||
|
curState = BootloaderEraseProgramWaitingWriteMoreReply;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashError);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
firmwareFile->close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BootloaderEraseProgramWaitingFinishReply:
|
||||||
|
if (c == BootloaderWriteOK)
|
||||||
|
{
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashComplete);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
firmwareFile->close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashError);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
firmwareFile->close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BootloaderEraseProgramWaitingWriteMoreReply:
|
||||||
|
if (c == BootloaderWriteOK)
|
||||||
|
{
|
||||||
|
// Send the next chunk of data
|
||||||
|
qDebug() << "Bootloader replied OK to send 1024 bytes of data! Sending...";
|
||||||
|
int chunkSize = FIRMWARE_CHUNK_SIZE;
|
||||||
|
if (firmwareLenRemaining < FIRMWARE_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
chunkSize = firmwareLenRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the chunk from the file!
|
||||||
|
QByteArray thisChunk = firmwareFile->read(chunkSize);
|
||||||
|
|
||||||
|
// If it isn't FIRMWARE_CHUNK_SIZE, pad the rest with 0xFF
|
||||||
|
// (unprogrammed bytes)
|
||||||
|
for (int x = firmwareLenRemaining; x < FIRMWARE_CHUNK_SIZE; x++)
|
||||||
|
{
|
||||||
|
thisChunk.append(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the chunk out (it's asynchronous so will return immediately)
|
||||||
|
serialPort->write(thisChunk);
|
||||||
|
|
||||||
|
// OK, now we're waiting to hear back from the programmer on the result
|
||||||
|
qDebug() << "Waiting for status reply...";
|
||||||
|
curState = BootloaderEraseProgramWaitingWriteReply;
|
||||||
|
firmwareLenRemaining -= chunkSize;
|
||||||
|
firmwareLenWritten += chunkSize;
|
||||||
|
emit firmwareFlashCompletionLengthChanged(firmwareLenWritten);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashError);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
firmwareFile->close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BootloaderEraseProgramWaitingWriteReply:
|
||||||
|
if (c == CommandReplyOK)
|
||||||
|
{
|
||||||
|
// Either ask to send the next chunk, or send a "finish" response
|
||||||
|
if (firmwareLenRemaining > 0)
|
||||||
|
{
|
||||||
|
sendByte(ComputerBootloaderWriteMore);
|
||||||
|
curState = BootloaderEraseProgramWaitingWriteMoreReply;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendByte(ComputerBootloaderFinish);
|
||||||
|
curState = BootloaderEraseProgramWaitingFinishReply;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashError);
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
serialPort->close();
|
||||||
|
firmwareFile->close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::RunElectricalTest()
|
||||||
|
{
|
||||||
|
startProgrammerCommand(DoElectricalTest, ElectricalTestWaitingStartReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Programmer::electricalTestPinName(uint8_t index)
|
||||||
|
{
|
||||||
|
if (index <= LAST_ADDRESS_LINE_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
return QString().sprintf("A%d", index - FIRST_ADDRESS_LINE_FAIL_INDEX);
|
||||||
|
}
|
||||||
|
else if (index <= LAST_DATA_LINE_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
// The byte ordering is backwards to the labeling, so I have to fix that.
|
||||||
|
// Reverse the byte ordering so we have the correct number in terms of how
|
||||||
|
// D0 to D31 are labeled...
|
||||||
|
index = index - FIRST_DATA_LINE_FAIL_INDEX;
|
||||||
|
if (index < 8)
|
||||||
|
{
|
||||||
|
index = index + 24;
|
||||||
|
}
|
||||||
|
else if (index < 16)
|
||||||
|
{
|
||||||
|
index = index + 8;
|
||||||
|
}
|
||||||
|
else if (index < 24)
|
||||||
|
{
|
||||||
|
index = index - 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = index - 24;
|
||||||
|
}
|
||||||
|
return QString().sprintf("D%d", index);
|
||||||
|
}
|
||||||
|
else if (index == CS_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
return "CS";
|
||||||
|
}
|
||||||
|
else if (index == OE_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
return "OE";
|
||||||
|
}
|
||||||
|
else if (index == WE_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
return "WE";
|
||||||
|
}
|
||||||
|
else if (index == GROUND_FAIL_INDEX)
|
||||||
|
{
|
||||||
|
return "GND";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::IdentifySIMMChips()
|
||||||
|
{
|
||||||
|
startProgrammerCommand(IdentifyChips, IdentificationAwaitingOKReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::GetChipIdentity(int chipIndex, uint8_t *manufacturer, uint8_t *device)
|
||||||
|
{
|
||||||
|
if ((chipIndex >= 0) && (chipIndex < 4))
|
||||||
|
{
|
||||||
|
*manufacturer = chipManufacturerIDs[chipIndex];
|
||||||
|
*device = chipDeviceIDs[chipIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*manufacturer = 0;
|
||||||
|
*device = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Programmer::FlashFirmware(QString filename)
|
||||||
|
{
|
||||||
|
firmwareFile = new QFile(filename);
|
||||||
|
if (!firmwareFile->open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
curState = WaitingForNextCommand;
|
||||||
|
emit firmwareFlashStatusChanged(FirmwareFlashError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
firmwareLenWritten = 0;
|
||||||
|
firmwareLenRemaining = firmwareFile->size();
|
||||||
|
emit firmwareFlashTotalLengthChanged(firmwareLenRemaining);
|
||||||
|
emit firmwareFlashCompletionLengthChanged(firmwareLenWritten);
|
||||||
|
|
||||||
|
startBootloaderCommand(BootloaderEraseAndWriteProgram, BootloaderEraseProgramAwaitingStartOKReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begins a command by opening the serial port, making sure we're in the PROGRAMMER
|
||||||
|
// rather than the bootloader, then sending a command and setting a new command state.
|
||||||
|
// TODO: When it fails, this needs to carry errors over somehow.
|
||||||
|
// newState is really just a ProgrammerCommandState but in order to keep
|
||||||
|
// ProgrammerCommandState private, I did it this way.
|
||||||
|
void Programmer::startProgrammerCommand(uint8_t commandByte, uint32_t newState)
|
||||||
|
{
|
||||||
|
nextState = (ProgrammerCommandState)newState;
|
||||||
|
nextSendByte = commandByte;
|
||||||
|
|
||||||
|
curState = BootloaderStateAwaitingOKReply;
|
||||||
|
serialPort->open(QextSerialPort::ReadWrite);
|
||||||
|
sendByte(GetBootloaderState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begins a command by opening the serial port, making sure we're in the BOOTLOADER
|
||||||
|
// rather than the programmer, then sending a command and setting a new command state.
|
||||||
|
// TODO: When it fails, this needs to carry errors over somehow.
|
||||||
|
// newState is really just a ProgrammerCommandState but in order to keep
|
||||||
|
// ProgrammerCommandState private, I did it this way.
|
||||||
|
void Programmer::startBootloaderCommand(uint8_t commandByte, uint32_t newState)
|
||||||
|
{
|
||||||
|
nextState = (ProgrammerCommandState)newState;
|
||||||
|
nextSendByte = commandByte;
|
||||||
|
|
||||||
|
curState = BootloaderStateAwaitingOKReplyToBootloader;
|
||||||
|
serialPort->open(QextSerialPort::ReadWrite);
|
||||||
|
sendByte(GetBootloaderState);
|
||||||
|
}
|
125
programmer.h
Normal file
125
programmer.h
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#ifndef PROGRAMMER_H
|
||||||
|
#define PROGRAMMER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <qextserialport.h>
|
||||||
|
|
||||||
|
typedef enum ReadStatus
|
||||||
|
{
|
||||||
|
ReadComplete,
|
||||||
|
ReadError,
|
||||||
|
ReadCancelled,
|
||||||
|
ReadTimedOut
|
||||||
|
} ReadStatus;
|
||||||
|
|
||||||
|
typedef enum WriteStatus
|
||||||
|
{
|
||||||
|
WriteComplete,
|
||||||
|
WriteError,
|
||||||
|
WriteCancelled,
|
||||||
|
WriteEraseComplete,
|
||||||
|
WriteEraseFailed,
|
||||||
|
WriteTimedOut
|
||||||
|
} WriteStatus;
|
||||||
|
|
||||||
|
typedef enum ElectricalTestStatus
|
||||||
|
{
|
||||||
|
ElectricalTestStarted,
|
||||||
|
ElectricalTestPassed,
|
||||||
|
ElectricalTestFailed,
|
||||||
|
ElectricalTestTimedOut,
|
||||||
|
ElectricalTestCouldntStart
|
||||||
|
} ElectricalTestStatus;
|
||||||
|
|
||||||
|
typedef enum IdentificationStatus
|
||||||
|
{
|
||||||
|
IdentificationComplete,
|
||||||
|
IdentificationError,
|
||||||
|
IdentificationTimedOut
|
||||||
|
} IdentificationStatus;
|
||||||
|
|
||||||
|
typedef enum FirmwareFlashStatus
|
||||||
|
{
|
||||||
|
FirmwareFlashComplete,
|
||||||
|
FirmwareFlashError,
|
||||||
|
FirmwareFlashCancelled,
|
||||||
|
FirmwareFlashTimedOut
|
||||||
|
} FirmwareFlashStatus;
|
||||||
|
|
||||||
|
// Electrical test indexes
|
||||||
|
#define GROUND_FAIL_INDEX 0xFF
|
||||||
|
|
||||||
|
#define FIRST_ADDRESS_LINE_FAIL_INDEX 0
|
||||||
|
#define LAST_ADDRESS_LINE_FAIL_INDEX (FIRST_ADDRESS_LINE_FAIL_INDEX + 20)
|
||||||
|
#define FIRST_DATA_LINE_FAIL_INDEX (LAST_ADDRESS_LINE_FAIL_INDEX + 1)
|
||||||
|
#define LAST_DATA_LINE_FAIL_INDEX (FIRST_DATA_LINE_FAIL_INDEX + 31)
|
||||||
|
#define CS_FAIL_INDEX (LAST_DATA_LINE_FAIL_INDEX + 1)
|
||||||
|
#define OE_FAIL_INDEX (CS_FAIL_INDEX + 1)
|
||||||
|
#define WE_FAIL_INDEX (OE_FAIL_INDEX + 1)
|
||||||
|
|
||||||
|
class Programmer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Programmer(QObject *parent = 0);
|
||||||
|
virtual ~Programmer();
|
||||||
|
void ReadSIMMToFile(QString filename);
|
||||||
|
void WriteFileToSIMM(QString filename);
|
||||||
|
void RunElectricalTest();
|
||||||
|
QString electricalTestPinName(uint8_t index);
|
||||||
|
void IdentifySIMMChips();
|
||||||
|
void GetChipIdentity(int chipIndex, uint8_t *manufacturer, uint8_t *device);
|
||||||
|
void FlashFirmware(QString filename);
|
||||||
|
signals:
|
||||||
|
void readStatusChanged(ReadStatus status);
|
||||||
|
void readTotalLengthChanged(uint32_t total);
|
||||||
|
void readCompletionLengthChanged(uint32_t total);
|
||||||
|
|
||||||
|
void writeStatusChanged(WriteStatus status);
|
||||||
|
void writeTotalLengthChanged(uint32_t total);
|
||||||
|
void writeCompletionLengthChanged(uint32_t len);
|
||||||
|
|
||||||
|
void electricalTestStatusChanged(ElectricalTestStatus status);
|
||||||
|
void electricalTestFailLocation(uint8_t loc1, uint8_t loc2);
|
||||||
|
|
||||||
|
void identificationStatusChanged(IdentificationStatus status);
|
||||||
|
|
||||||
|
void firmwareFlashStatusChanged(FirmwareFlashStatus status);
|
||||||
|
void firmwareFlashTotalLengthChanged(uint32_t total);
|
||||||
|
void firmwareFlashCompletionLengthChanged(uint32_t total);
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private:
|
||||||
|
QFile *readFile;
|
||||||
|
QFile *writeFile;
|
||||||
|
QFile *firmwareFile;
|
||||||
|
|
||||||
|
QextSerialPort *serialPort;
|
||||||
|
void sendByte(uint8_t b);
|
||||||
|
uint8_t readByte();
|
||||||
|
void handleChar(uint8_t c);
|
||||||
|
|
||||||
|
uint32_t writeLenRemaining;
|
||||||
|
uint32_t lenWritten;
|
||||||
|
uint32_t electricalTestErrorCounter;
|
||||||
|
uint8_t electricalTestFirstErrorLoc;
|
||||||
|
|
||||||
|
uint32_t readChunkLenRemaining;
|
||||||
|
uint32_t lenRead;
|
||||||
|
|
||||||
|
int identificationCounter;
|
||||||
|
uint8_t chipManufacturerIDs[4];
|
||||||
|
uint8_t chipDeviceIDs[4];
|
||||||
|
|
||||||
|
uint32_t firmwareLenRemaining;
|
||||||
|
uint32_t firmwareLenWritten;
|
||||||
|
|
||||||
|
void startProgrammerCommand(uint8_t commandByte, uint32_t newState);
|
||||||
|
void startBootloaderCommand(uint8_t commandByte, uint32_t newState);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void dataReady();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PROGRAMMER_H
|
21
usbprogrammerfinder.h
Normal file
21
usbprogrammerfinder.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef USBPROGRAMMERFINDER_H
|
||||||
|
#define USBPROGRAMMERFINDER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#define USB_PROGRAMMER_VID 0x03EB
|
||||||
|
#define USB_PROGRAMMER_PID 0x204B
|
||||||
|
|
||||||
|
class USBProgrammerFinder : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit USBProgrammerFinder(QObject *parent = 0);
|
||||||
|
QString getSerialPortName();
|
||||||
|
signals:
|
||||||
|
void programmerPresenceChanged(bool);
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USBPROGRAMMERFINDER_H
|
32
usbprogrammerfinder_win.cpp
Normal file
32
usbprogrammerfinder_win.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//#ifdef Q_WS_WIN
|
||||||
|
|
||||||
|
#include "usbprogrammerfinder.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
//#include <tchar.h>
|
||||||
|
|
||||||
|
USBProgrammerFinder::USBProgrammerFinder(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString USBProgrammerFinder::getSerialPortName()
|
||||||
|
{
|
||||||
|
/*//GUID_
|
||||||
|
HDEVINFO result = SetupDiGetClassDevs(NULL, L"USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
||||||
|
|
||||||
|
if (result != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QString::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();*/
|
||||||
|
|
||||||
|
return "COM13";
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endif
|
Loading…
Reference in New Issue
Block a user