Initial import of SIMM programmer code into Git
This commit is contained in:
commit
348d6121f4
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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