diff --git a/ground/openpilotgcs/src/plugins/setupwizard/pages/autoupdatepage.cpp b/ground/openpilotgcs/src/plugins/setupwizard/pages/autoupdatepage.cpp
index 57a6b7723..7c3b9fc63 100644
--- a/ground/openpilotgcs/src/plugins/setupwizard/pages/autoupdatepage.cpp
+++ b/ground/openpilotgcs/src/plugins/setupwizard/pages/autoupdatepage.cpp
@@ -40,8 +40,13 @@ void AutoUpdatePage::updateStatus(uploader::AutoUpdateStep status, QVariant valu
switch (status) {
case uploader::WAITING_DISCONNECT:
getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint);
+ getWizard()->setWindowIcon(qApp->windowIcon());
disableButtons();
+ getWizard()->show();
ui->statusLabel->setText("Waiting for all OP boards to be disconnected");
+ // TODO get rid of magic number 20s
+ ui->levellinProgressBar->setMaximum(20);
+ ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::WAITING_CONNECT:
getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
@@ -49,6 +54,8 @@ void AutoUpdatePage::updateStatus(uploader::AutoUpdateStep status, QVariant valu
disableButtons();
getWizard()->show();
ui->statusLabel->setText("Please connect the board to the USB port (don't use external supply)");
+ // TODO get rid of magic number 20s
+ ui->levellinProgressBar->setMaximum(20);
ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::JUMP_TO_BL:
@@ -60,6 +67,7 @@ void AutoUpdatePage::updateStatus(uploader::AutoUpdateStep status, QVariant valu
break;
case uploader::UPLOADING_FW:
ui->statusLabel->setText("Uploading firmware");
+ ui->levellinProgressBar->setMaximum(100);
ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::UPLOADING_DESC:
@@ -77,7 +85,11 @@ void AutoUpdatePage::updateStatus(uploader::AutoUpdateStep status, QVariant valu
getWizard()->setWindowIcon(qApp->windowIcon());
enableButtons(true);
getWizard()->show();
- ui->statusLabel->setText("Something went wrong, you will have to manually upgrade the board using the uploader plugin");
+ QString msg = value.toString();
+ if (msg.isEmpty()) {
+ msg = "Something went wrong, you will have to manually upgrade the board using the uploader plugin";
+ }
+ ui->statusLabel->setText(msg);
break;
}
}
diff --git a/ground/openpilotgcs/src/plugins/uploader/uploader.ui b/ground/openpilotgcs/src/plugins/uploader/uploader.ui
index 1143f5e1f..f0423a68a 100644
--- a/ground/openpilotgcs/src/plugins/uploader/uploader.ui
+++ b/ground/openpilotgcs/src/plugins/uploader/uploader.ui
@@ -47,7 +47,16 @@
0
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
@@ -277,7 +286,7 @@ Rescue is possible in USB mode only.
0
- false
+ true
diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp
index 63858419d..3e922afcd 100644
--- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp
+++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp
@@ -35,6 +35,7 @@
#define DFU_DEBUG true
+const int UploaderGadgetWidget::BOARD_EVENT_TIMEOUT = 20000;
const int UploaderGadgetWidget::AUTOUPDATE_CLOSE_TIMEOUT = 7000;
TimedDialog::TimedDialog(const QString &title, const QString &labelText, int timeout, QWidget *parent, Qt::WindowFlags flags) :
@@ -75,6 +76,48 @@ void TimedDialog::perform()
}
}
+ConnectionWaiter::ConnectionWaiter(int targetDeviceCount, int timeout, QWidget *parent) : QObject(parent), eventLoop(this), timer(this), timeout(timeout), elapsed(0), targetDeviceCount(targetDeviceCount), result(ConnectionWaiter::Ok)
+{
+}
+
+int ConnectionWaiter::exec() {
+ connect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(deviceEvent()));
+ connect(USBMonitor::instance(), SIGNAL(deviceRemoved(USBPortInfo)), this, SLOT(deviceEvent()));
+
+ connect(&timer, SIGNAL(timeout()), this, SLOT(perform()));
+ timer.start(1000);
+
+ emit timeChanged(0);
+ eventLoop.exec();
+
+ return result;
+}
+
+void ConnectionWaiter::quit() {
+ disconnect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)), this, SLOT(deviceEvent()));
+ disconnect(USBMonitor::instance(), SIGNAL(deviceRemoved(USBPortInfo)), this, SLOT(deviceEvent()));
+ timer.stop();
+ eventLoop.exit();
+}
+
+void ConnectionWaiter::perform()
+{
+ ++elapsed;
+ emit timeChanged(elapsed);
+ int remaining = timeout - elapsed * 1000;
+ if (remaining <= 0) {
+ result = ConnectionWaiter::TimedOut;
+ quit();
+ }
+}
+
+void ConnectionWaiter::deviceEvent()
+{
+ if (USBMonitor::instance()->availableDevices(0x20a0, -1, -1, -1).length() == targetDeviceCount) {
+ quit();
+ }
+}
+
UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
{
m_config = new Ui_UploaderWidget();
@@ -82,9 +125,8 @@ UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
currentStep = IAP_STATE_READY;
resetOnly = false;
dfu = NULL;
- m_timer = 0;
- m_progress = 0;
msg = new QErrorMessage(this);
+
// Listen to autopilot connection events
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
TelemetryManager *telMngr = pm->getObject();
@@ -124,7 +166,6 @@ UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
}
}
-
bool sortPorts(const QSerialPortInfo &s1, const QSerialPortInfo &s2)
{
return s1.portName() < s2.portName();
@@ -569,31 +610,25 @@ bool UploaderGadgetWidget::autoUpdate()
delete dfu;
dfu = NULL;
}
- QEventLoop loop;
- QTimer timer;
- timer.setSingleShot(true);
- connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
- while (USBMonitor::instance()->availableDevices(0x20a0, -1, -1, -1).length() > 0) {
- emit autoUpdateSignal(WAITING_DISCONNECT, QVariant());
- if (QMessageBox::warning(this, tr("OpenPilot Uploader"), tr("Please disconnect your OpenPilot board"), QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Cancel) {
- emit autoUpdateSignal(FAILURE, QVariant());
+
+ if (USBMonitor::instance()->availableDevices(0x20a0, -1, -1, -1).length() > 0) {
+ // wait for all boards to be disconnected
+ ConnectionWaiter waiter(0, BOARD_EVENT_TIMEOUT);
+ connect(&waiter, SIGNAL(timeChanged(int)), this, SLOT(autoUpdateDisconnectProgress(int)));
+ if (waiter.exec() == ConnectionWaiter::TimedOut) {
+ emit autoUpdateSignal(FAILURE, QVariant(tr("Timed out while waiting for all boards to be disconnected!")));
return false;
}
- sleep(500);
}
- emit autoUpdateSignal(WAITING_CONNECT, 0);
- autoUpdateConnectTimeout = 0;
- m_timer = new QTimer(this);
- connect(m_timer, SIGNAL(timeout()), this, SLOT(performAuto()));
- m_timer->start(1000);
- connect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)), &m_eventloop, SLOT(quit()));
- m_eventloop.exec();
- if (!m_timer->isActive()) {
- m_timer->stop();
- emit autoUpdateSignal(FAILURE, QVariant());
+
+ // wait for a board to connect
+ ConnectionWaiter waiter(1, BOARD_EVENT_TIMEOUT);
+ connect(&waiter, SIGNAL(timeChanged(int)), this, SLOT(autoUpdateConnectProgress(int)));
+ if (waiter.exec() == ConnectionWaiter::TimedOut) {
+ emit autoUpdateSignal(FAILURE, QVariant(tr("Timed out while waiting for a board to be connected!")));
return false;
}
- m_timer->stop();
+
dfu = new DFUObject(DFU_DEBUG, false, QString());
dfu->AbortOperation();
emit autoUpdateSignal(JUMP_TO_BL, QVariant());
@@ -618,6 +653,7 @@ bool UploaderGadgetWidget::autoUpdate()
emit autoUpdateSignal(FAILURE, QVariant());
return false;
}
+
QString filename;
emit autoUpdateSignal(LOADING_FW, QVariant());
switch (dfu->devices[0].ID) {
@@ -654,9 +690,10 @@ bool UploaderGadgetWidget::autoUpdate()
emit autoUpdateSignal(FAILURE, QVariant());
return false;
}
+ QEventLoop eventLoop;
firmware = file.readAll();
connect(dfu, SIGNAL(progressUpdated(int)), this, SLOT(autoUpdateProgress(int)));
- connect(dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &m_eventloop, SLOT(quit()));
+ connect(dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &eventLoop, SLOT(quit()));
emit autoUpdateSignal(UPLOADING_FW, QVariant());
if (!dfu->enterDFU(0)) {
emit autoUpdateSignal(FAILURE, QVariant());
@@ -667,7 +704,7 @@ bool UploaderGadgetWidget::autoUpdate()
emit autoUpdateSignal(FAILURE, QVariant());
return false;
}
- m_eventloop.exec();
+ eventLoop.exec();
QByteArray desc = firmware.right(100);
emit autoUpdateSignal(UPLOADING_DESC, QVariant());
if (dfu->UploadDescription(desc) != OP_DFU::Last_operation_Success) {
@@ -679,11 +716,26 @@ bool UploaderGadgetWidget::autoUpdate()
return true;
}
-void UploaderGadgetWidget::autoUpdateProgress(int value)
+void UploaderGadgetWidget::autoUpdateDisconnectProgress(int value)
+{
+ emit autoUpdateSignal(WAITING_DISCONNECT, value);
+}
+
+void UploaderGadgetWidget::autoUpdateConnectProgress(int value)
+{
+ emit autoUpdateSignal(WAITING_CONNECT, value);
+}
+
+void UploaderGadgetWidget::autoUpdateFlashProgress(int value)
{
emit autoUpdateSignal(UPLOADING_FW, value);
}
+void UploaderGadgetWidget::autoUpdateProgress(int value)
+{
+ autoUpdateFlashProgress(value);
+}
+
/**
Attempt a guided procedure to put both boards in BL mode when
the system is not bootable
@@ -798,16 +850,6 @@ void UploaderGadgetWidget::systemRescue()
currentStep = IAP_STATE_BOOTLOADER;
}
-void UploaderGadgetWidget::performAuto()
-{
- ++autoUpdateConnectTimeout;
- emit autoUpdateSignal(WAITING_CONNECT, autoUpdateConnectTimeout * 5);
- if (autoUpdateConnectTimeout == 20) {
- m_timer->stop();
- m_eventloop.exit();
- }
-}
-
void UploaderGadgetWidget::uploadStarted()
{
m_config->haltButton->setEnabled(false);
@@ -852,6 +894,7 @@ void UploaderGadgetWidget::startAutoUpdate()
m_config->splitter->setEnabled(false);
m_config->autoUpdateGroupBox->setVisible(true);
m_config->autoUpdateOkButton->setEnabled(false);
+
connect(this, SIGNAL(autoUpdateSignal(uploader::AutoUpdateStep, QVariant)), this, SLOT(autoUpdateStatus(uploader::AutoUpdateStep, QVariant)));
autoUpdate();
}
@@ -860,14 +903,13 @@ void UploaderGadgetWidget::finishAutoUpdate()
{
disconnect(this, SIGNAL(autoUpdateSignal(uploader::AutoUpdateStep, QVariant)), this, SLOT(autoUpdateStatus(uploader::AutoUpdateStep, QVariant)));
m_config->autoUpdateOkButton->setEnabled(true);
- connect(&autoUpdateCloseTimer, SIGNAL(timeout()), this, SLOT(closeAutoUpdate()));
- autoUpdateCloseTimer.start(AUTOUPDATE_CLOSE_TIMEOUT);
+
+ // wait a bit and "close" auto update
+ QTimer::singleShot(AUTOUPDATE_CLOSE_TIMEOUT, this, SLOT(closeAutoUpdate()));
}
void UploaderGadgetWidget::closeAutoUpdate()
{
- autoUpdateCloseTimer.stop();
- disconnect(&autoUpdateCloseTimer, SIGNAL(timeout()), this, SLOT(closeAutoUpdate()));
m_config->autoUpdateGroupBox->setVisible(false);
m_config->buttonFrame->setEnabled(true);
m_config->splitter->setEnabled(true);
@@ -875,13 +917,22 @@ void UploaderGadgetWidget::closeAutoUpdate()
void UploaderGadgetWidget::autoUpdateStatus(uploader::AutoUpdateStep status, QVariant value)
{
+ QString msg;
+ int remaining;
switch (status) {
case uploader::WAITING_DISCONNECT:
m_config->autoUpdateLabel->setText("Waiting for all OpenPilot boards to be disconnected from USB.");
+ m_config->autoUpdateProgressBar->setMaximum(BOARD_EVENT_TIMEOUT / 1000);
+ m_config->autoUpdateProgressBar->setValue(value.toInt());
+ remaining = m_config->autoUpdateProgressBar->maximum() - m_config->autoUpdateProgressBar->value();
+ m_config->autoUpdateProgressBar->setFormat(tr("Timing out in %1 seconds").arg(remaining));
break;
case uploader::WAITING_CONNECT:
m_config->autoUpdateLabel->setText("Please connect the OpenPilot board to the USB port.");
+ m_config->autoUpdateProgressBar->setMaximum(BOARD_EVENT_TIMEOUT / 1000);
m_config->autoUpdateProgressBar->setValue(value.toInt());
+ remaining = m_config->autoUpdateProgressBar->maximum() - m_config->autoUpdateProgressBar->value();
+ m_config->autoUpdateProgressBar->setFormat(tr("Timing out in %1 seconds").arg(remaining));
break;
case uploader::JUMP_TO_BL:
m_config->autoUpdateProgressBar->setValue(0);
@@ -892,6 +943,8 @@ void UploaderGadgetWidget::autoUpdateStatus(uploader::AutoUpdateStep status, QVa
break;
case uploader::UPLOADING_FW:
m_config->autoUpdateLabel->setText("Uploading firmware to the board.");
+ m_config->autoUpdateProgressBar->setFormat("%p%");
+ m_config->autoUpdateProgressBar->setMaximum(100);
m_config->autoUpdateProgressBar->setValue(value.toInt());
break;
case uploader::UPLOADING_DESC:
@@ -901,11 +954,18 @@ void UploaderGadgetWidget::autoUpdateStatus(uploader::AutoUpdateStep status, QVa
m_config->autoUpdateLabel->setText("Rebooting the board.");
break;
case uploader::SUCCESS:
- m_config->autoUpdateLabel->setText("Board was updated successfully, press OK to finish.");
+ m_config->autoUpdateProgressBar->setValue(m_config->autoUpdateProgressBar->maximum());
+ msg = tr("Board was updated successfully.") + " " + tr("Press OK to finish.");
+ m_config->autoUpdateLabel->setText(QString("%1").arg(msg));
finishAutoUpdate();
break;
case uploader::FAILURE:
- m_config->autoUpdateLabel->setText("Something went wrong, you will have to manually upgrade the board. Press OK to continue.");
+ QString msg = value.toString();
+ if (msg.isEmpty()) {
+ msg = "Something went wrong, you will have to manually upgrade the board.";
+ }
+ msg += " " + tr("Press OK to finish.");
+ m_config->autoUpdateLabel->setText(QString("%1").arg(msg));
finishAutoUpdate();
break;
}
@@ -936,17 +996,8 @@ UploaderGadgetWidget::~UploaderGadgetWidget()
delete qw;
qw = 0;
}
- if (m_progress) {
- delete m_progress;
- m_progress = 0;
- }
- if (m_timer) {
- delete m_timer;
- m_timer = 0;
- }
}
-
/**
Shows a message box with an error string.
diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h
index baccc5ae7..f5335ef16 100644
--- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h
+++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.h
@@ -81,6 +81,38 @@ private:
QProgressBar *bar;
};
+// A helper class to wait for board connection and disconnection events
+// until a the desired number of connected boards is found
+// or until a timeout is reached
+class ConnectionWaiter: public QObject {
+ Q_OBJECT
+
+public:
+ ConnectionWaiter(int targetDeviceCount, int timeout, QWidget *parent = 0);
+
+ enum DialogCode { Ok, TimedOut };
+
+public slots:
+ int exec();
+ void quit();
+
+signals:
+ void timeChanged(int elapsed);
+
+private slots:
+ void perform();
+ void deviceEvent();
+
+private:
+ QEventLoop eventLoop;
+ QTimer timer;
+ // timeour in ms
+ int timeout;
+ // elapsed time in seconds
+ int elapsed;
+ int targetDeviceCount;
+ int result;
+};
class UPLOADER_EXPORT UploaderGadgetWidget : public QWidget {
Q_OBJECT
@@ -88,6 +120,9 @@ class UPLOADER_EXPORT UploaderGadgetWidget : public QWidget {
public:
UploaderGadgetWidget(QWidget *parent = 0);
~UploaderGadgetWidget();
+
+ static const int BOARD_EVENT_TIMEOUT;
+
void log(QString str);
bool autoUpdateCapable();
@@ -97,7 +132,11 @@ public slots:
void populate();
void openHelp();
bool autoUpdate();
+ void autoUpdateDisconnectProgress(int);
+ void autoUpdateConnectProgress(int);
+ // autoUpdateProgress is deprecated: use autoUpdateFlashProgress instead
void autoUpdateProgress(int);
+ void autoUpdateFlashProgress(int);
signals:
void autoUpdateSignal(uploader::AutoUpdateStep, QVariant);
@@ -109,17 +148,13 @@ private:
bool resetOnly;
void clearLog();
QString getPortDevice(const QString &friendName);
- QProgressDialog *m_progress;
- QTimer *m_timer;
QLineEdit *openFileNameLE;
- QEventLoop m_eventloop;
QErrorMessage *msg;
void connectSignalSlot(QWidget *widget);
- int autoUpdateConnectTimeout;
FlightStatus *getFlightStatus();
void bootButtonsSetEnable(bool enabled);
static const int AUTOUPDATE_CLOSE_TIMEOUT;
- QTimer autoUpdateCloseTimer;
+
private slots:
void onPhysicalHWConnect();
void versionMatchCheck();
@@ -134,7 +169,6 @@ private slots:
void commonSystemBoot(bool safeboot = false, bool erase = false);
void systemRescue();
void getSerialPorts();
- void performAuto();
void uploadStarted();
void uploadEnded(bool succeed);
void downloadStarted();