1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-21 11:54:15 +01:00

OP-1628 Added special handling for OPLink boards and Upgrade/Reboot functionality.

This commit is contained in:
m_thread 2015-02-02 00:14:02 +01:00
parent 76b209c820
commit 31a6a32fce
6 changed files with 278 additions and 98 deletions

View File

@ -0,0 +1,90 @@
/**
******************************************************************************
*
* @file oplinkwatchdog.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @addtogroup [Group]
* @{
* @addtogroup OPLinkWatchdog
* @{
* @brief [Brief]
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "oplinkwatchdog.h"
#include "extensionsystem/pluginmanager.h"
#include "uavobjects/uavobjectmanager.h"
#include "oplinkstatus.h"
#include <QDebug>
OPLinkWatchdog::OPLinkWatchdog() : QObject(),
m_isConnected(false)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
Q_ASSERT(pm);
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
Q_ASSERT(objManager);
m_oplinkStatus = OPLinkStatus::GetInstance(objManager);
Q_ASSERT(m_oplinkStatus);
connect(m_oplinkStatus, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(onOPLinkStatusUpdate()));
m_watchdog = new QTimer(this);
connect(m_watchdog, SIGNAL(timeout()), this, SLOT(onTimeout()));
onOPLinkStatusUpdate();
}
OPLinkWatchdog::~OPLinkWatchdog()
{
}
void OPLinkWatchdog::onOPLinkStatusUpdate()
{
m_watchdog->stop();
quint8 type = m_oplinkStatus->getBoardType();
if (!m_isConnected) {
switch (type) {
case 3:
m_oplinkType = OPLINK_STANDALONE;
m_isConnected = true;
emit connected();
emit standaloneConnected();
break;
case 9:
m_oplinkType = OPLINK_REVOLUTION;
m_isConnected = true;
emit connected();
emit revolutionConnected();
break;
default:
m_isConnected = false;
m_oplinkType = OPLINK_UNKNOWN;
return;
}
qDebug() << "OPLink connected";
}
m_watchdog->start(m_oplinkStatus->getMetadata().flightTelemetryUpdatePeriod * 3);
}
void OPLinkWatchdog::onTimeout()
{
if (m_isConnected) {
m_isConnected = false;
m_oplinkType = OPLINK_UNKNOWN;
qDebug() << "OPLink disconnected";
emit disconnected();
}
}

View File

@ -0,0 +1,64 @@
/**
******************************************************************************
*
* @file oplinkwatchdog.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @addtogroup [Group]
* @{
* @addtogroup OPLinkWatchdog
* @{
* @brief [Brief]
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef OPLINKWATCHDOG_H
#define OPLINKWATCHDOG_H
#include <QTimer>
class OPLinkStatus;
class OPLinkWatchdog : public QObject {
Q_OBJECT
public:
enum OPLinkType {
OPLINK_STANDALONE,
OPLINK_REVOLUTION,
OPLINK_UNKNOWN
};
OPLinkWatchdog();
~OPLinkWatchdog();
bool isConnected() const { return m_isConnected; }
OPLinkWatchdog::OPLinkType oplinkType() const { return m_oplinkType; }
signals:
void connected();
void standaloneConnected();
void revolutionConnected();
void disconnected();
private slots:
void onOPLinkStatusUpdate();
void onTimeout();
private:
bool m_isConnected;
OPLinkType m_oplinkType;
QTimer* m_watchdog;
OPLinkStatus* m_oplinkStatus;
};
#endif // OPLINKWATCHDOG_H

View File

@ -31,7 +31,8 @@ HEADERS += uploadergadget.h \
runningdevicewidget.h \ runningdevicewidget.h \
uploader_global.h \ uploader_global.h \
enums.h \ enums.h \
rebootdialog.h rebootdialog.h \
oplinkwatchdog.h
SOURCES += uploadergadget.cpp \ SOURCES += uploadergadget.cpp \
uploadergadgetconfiguration.cpp \ uploadergadgetconfiguration.cpp \
@ -46,7 +47,8 @@ SOURCES += uploadergadget.cpp \
SSP/qssp.cpp \ SSP/qssp.cpp \
SSP/qsspt.cpp \ SSP/qsspt.cpp \
runningdevicewidget.cpp \ runningdevicewidget.cpp \
rebootdialog.cpp rebootdialog.cpp \
oplinkwatchdog.cpp
OTHER_FILES += Uploader.pluginspec OTHER_FILES += Uploader.pluginspec

View File

@ -27,8 +27,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>794</width> <width>778</width>
<height>505</height> <height>615</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
@ -311,6 +311,9 @@ through serial or USB)</string>
<property name="text"> <property name="text">
<string>Progress</string> <string>Progress</string>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -27,6 +27,7 @@
#include "uploadergadgetwidget.h" #include "uploadergadgetwidget.h"
#include "flightstatus.h" #include "flightstatus.h"
#include "oplinkstatus.h"
#include "delay.h" #include "delay.h"
#include "devicewidget.h" #include "devicewidget.h"
#include "runningdevicewidget.h" #include "runningdevicewidget.h"
@ -138,9 +139,10 @@ UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
{ {
m_config = new Ui_UploaderWidget(); m_config = new Ui_UploaderWidget();
m_config->setupUi(this); m_config->setupUi(this);
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
resetOnly = false; m_resetOnly = false;
dfu = NULL; m_dfu = NULL;
m_autoupdateClosing = false;
// Listen to autopilot connection events // Listen to autopilot connection events
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
@ -230,7 +232,6 @@ void UploaderGadgetWidget::connectSignalSlot(QWidget *widget)
FlightStatus *UploaderGadgetWidget::getFlightStatus() FlightStatus *UploaderGadgetWidget::getFlightStatus()
{ {
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
Q_ASSERT(pm); Q_ASSERT(pm);
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
Q_ASSERT(objManager); Q_ASSERT(objManager);
@ -245,7 +246,7 @@ void UploaderGadgetWidget::bootButtonsSetEnable(bool enabled)
m_config->safeBootButton->setEnabled(enabled); m_config->safeBootButton->setEnabled(enabled);
// this feature is supported only on BL revision >= 4 // this feature is supported only on BL revision >= 4
bool isBL4 = ((dfu != NULL) && (dfu->devices[0].BL_Version >= 4)); bool isBL4 = ((m_dfu != NULL) && (m_dfu->devices[0].BL_Version >= 4));
m_config->eraseBootButton->setEnabled(isBL4 && enabled); m_config->eraseBootButton->setEnabled(isBL4 && enabled);
} }
@ -292,7 +293,7 @@ void UploaderGadgetWidget::onAutopilotDisconnect()
m_config->haltButton->setEnabled(false); m_config->haltButton->setEnabled(false);
m_config->resetButton->setEnabled(false); m_config->resetButton->setEnabled(false);
bootButtonsSetEnable(true); bootButtonsSetEnable(true);
if (currentStep == IAP_STATE_BOOTLOADER) { if (m_currentIAPStep == IAP_STATE_BOOTLOADER) {
m_config->rescueButton->setEnabled(false); m_config->rescueButton->setEnabled(false);
m_config->telemetryLink->setEnabled(false); m_config->telemetryLink->setEnabled(false);
} else { } else {
@ -322,7 +323,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVObject *fwIAP = dynamic_cast<UAVDataObject *>(objManager->getObject("FirmwareIAPObj")); UAVObject *fwIAP = dynamic_cast<UAVDataObject *>(objManager->getObject("FirmwareIAPObj"));
switch (currentStep) { switch (m_currentIAPStep) {
case IAP_STATE_READY: case IAP_STATE_READY:
m_config->haltButton->setEnabled(false); m_config->haltButton->setEnabled(false);
getSerialPorts(); // Useful in case a new serial port appeared since the initial list, getSerialPorts(); // Useful in case a new serial port appeared since the initial list,
@ -332,7 +333,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
fwIAP->getField("BoardRevision")->setDouble(0); fwIAP->getField("BoardRevision")->setDouble(0);
fwIAP->getField("BoardType")->setDouble(0); fwIAP->getField("BoardType")->setDouble(0);
connect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool))); connect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
currentStep = IAP_STATE_STEP_1; m_currentIAPStep = IAP_STATE_STEP_1;
clearLog(); clearLog();
log("IAP Step 1"); log("IAP Step 1");
fwIAP->updated(); fwIAP->updated();
@ -342,7 +343,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
if (!success) { if (!success) {
log("Oops, failure step 1"); log("Oops, failure step 1");
log("Reset did NOT happen"); log("Reset did NOT happen");
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool))); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
m_config->haltButton->setEnabled(true); m_config->haltButton->setEnabled(true);
emit progressUpdate(FAILURE, QVariant()); emit progressUpdate(FAILURE, QVariant());
@ -351,7 +352,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
} }
sleep(600); sleep(600);
fwIAP->getField("Command")->setValue("2233"); fwIAP->getField("Command")->setValue("2233");
currentStep = IAP_STATE_STEP_2; m_currentIAPStep = IAP_STATE_STEP_2;
log("IAP Step 2"); log("IAP Step 2");
fwIAP->updated(); fwIAP->updated();
emit progressUpdate(JUMP_TO_BL, QVariant(2)); emit progressUpdate(JUMP_TO_BL, QVariant(2));
@ -360,7 +361,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
if (!success) { if (!success) {
log("Oops, failure step 2"); log("Oops, failure step 2");
log("Reset did NOT happen"); log("Reset did NOT happen");
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool))); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
m_config->haltButton->setEnabled(true); m_config->haltButton->setEnabled(true);
emit progressUpdate(FAILURE, QVariant()); emit progressUpdate(FAILURE, QVariant());
@ -369,14 +370,14 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
} }
sleep(600); sleep(600);
fwIAP->getField("Command")->setValue("3344"); fwIAP->getField("Command")->setValue("3344");
currentStep = IAP_STEP_RESET; m_currentIAPStep = IAP_STEP_RESET;
log("IAP Step 3"); log("IAP Step 3");
emit progressUpdate(JUMP_TO_BL, QVariant(3)); emit progressUpdate(JUMP_TO_BL, QVariant(3));
fwIAP->updated(); fwIAP->updated();
break; break;
case IAP_STEP_RESET: case IAP_STEP_RESET:
{ {
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
if (!success) { if (!success) {
log("Oops, failure step 3"); log("Oops, failure step 3");
log("Reset did NOT happen"); log("Reset did NOT happen");
@ -407,36 +408,36 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool))); disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
currentStep = IAP_STATE_BOOTLOADER; m_currentIAPStep = IAP_STATE_BOOTLOADER;
// Tell the mainboard to get into bootloader state: // Tell the mainboard to get into bootloader state:
log("Detecting devices, please wait a few seconds..."); log("Detecting devices, please wait a few seconds...");
if (!dfu) { if (!m_dfu) {
if (dlj.startsWith("USB")) { if (dlj.startsWith("USB")) {
dfu = new DFUObject(DFU_DEBUG, false, QString()); m_dfu = new DFUObject(DFU_DEBUG, false, QString());
} else { } else {
dfu = new DFUObject(DFU_DEBUG, true, getPortDevice(dli)); m_dfu = new DFUObject(DFU_DEBUG, true, getPortDevice(dli));
} }
} }
if (!dfu->ready()) { if (!m_dfu->ready()) {
log("Could not enter DFU mode."); log("Could not enter DFU mode.");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
m_config->boardStatus->setText(tr("Bootloader?")); m_config->boardStatus->setText(tr("Bootloader?"));
m_config->haltButton->setEnabled(true); m_config->haltButton->setEnabled(true);
emit progressUpdate(FAILURE, QVariant()); emit progressUpdate(FAILURE, QVariant());
emit bootloaderFailed(); emit bootloaderFailed();
return; return;
} }
dfu->AbortOperation(); m_dfu->AbortOperation();
if (!dfu->enterDFU(0)) { if (!m_dfu->enterDFU(0)) {
log("Could not enter DFU mode."); log("Could not enter DFU mode.");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
m_config->boardStatus->setText(tr("Bootloader?")); m_config->boardStatus->setText(tr("Bootloader?"));
emit progressUpdate(FAILURE, QVariant()); emit progressUpdate(FAILURE, QVariant());
emit bootloaderFailed(); emit bootloaderFailed();
@ -444,12 +445,12 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
} }
sleep(500); sleep(500);
dfu->findDevices(); m_dfu->findDevices();
log(QString("Found %1 device(s).").arg(QString::number(dfu->numberOfDevices))); log(QString("Found %1 device(s).").arg(QString::number(m_dfu->numberOfDevices)));
if (dfu->numberOfDevices < 0 || dfu->numberOfDevices > 3) { if (m_dfu->numberOfDevices < 0 || m_dfu->numberOfDevices > 3) {
log("Inconsistent number of devices! Aborting"); log("Inconsistent number of devices! Aborting");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
emit progressUpdate(FAILURE, QVariant()); emit progressUpdate(FAILURE, QVariant());
emit bootloaderFailed(); emit bootloaderFailed();
@ -461,11 +462,11 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
m_config->systemElements->removeTab(0); m_config->systemElements->removeTab(0);
delete qw; delete qw;
} }
for (int i = 0; i < dfu->numberOfDevices; i++) { for (int i = 0; i < m_dfu->numberOfDevices; i++) {
DeviceWidget *dw = new DeviceWidget(this); DeviceWidget *dw = new DeviceWidget(this);
connectSignalSlot(dw); connectSignalSlot(dw);
dw->setDeviceID(i); dw->setDeviceID(i);
dw->setDfu(dfu); dw->setDfu(m_dfu);
dw->populate(); dw->populate();
m_config->systemElements->addTab(dw, tr("Device") + QString::number(i)); m_config->systemElements->addTab(dw, tr("Device") + QString::number(i));
} }
@ -477,8 +478,8 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
emit progressUpdate(JUMP_TO_BL, QVariant(5)); emit progressUpdate(JUMP_TO_BL, QVariant(5));
emit bootloaderSuccess(); emit bootloaderSuccess();
if (resetOnly) { if (m_resetOnly) {
resetOnly = false; m_resetOnly = false;
delay::msleep(3500); delay::msleep(3500);
systemBoot(); systemBoot();
break; break;
@ -518,10 +519,10 @@ void UploaderGadgetWidget::systemReset()
// The board can not be reset when in armed state. // The board can not be reset when in armed state.
// If board is armed, or arming. Show message with notice. // If board is armed, or arming. Show message with notice.
if (status->getArmed() == FlightStatus::ARMED_DISARMED) { if (status->getArmed() == FlightStatus::ARMED_DISARMED) {
resetOnly = true; m_resetOnly = true;
if (dfu) { if (m_dfu) {
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
} }
clearLog(); clearLog();
log("Board Reset initiated."); log("Board Reset initiated.");
@ -618,31 +619,31 @@ void UploaderGadgetWidget::commonSystemBoot(bool safeboot, bool erase)
log("Attempting to boot the system through " + devName + "."); log("Attempting to boot the system through " + devName + ".");
repaint(); repaint();
if (!dfu) { if (!m_dfu) {
if (devName == "USB") { if (devName == "USB") {
dfu = new DFUObject(DFU_DEBUG, false, QString()); m_dfu = new DFUObject(DFU_DEBUG, false, QString());
} else { } else {
dfu = new DFUObject(DFU_DEBUG, true, getPortDevice(devName)); m_dfu = new DFUObject(DFU_DEBUG, true, getPortDevice(devName));
} }
} }
dfu->AbortOperation(); m_dfu->AbortOperation();
if (!dfu->enterDFU(0)) { if (!m_dfu->enterDFU(0)) {
log("Could not enter DFU mode."); log("Could not enter DFU mode.");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
bootButtonsSetEnable(true); bootButtonsSetEnable(true);
m_config->rescueButton->setEnabled(true); // Boot not possible, maybe Rescue OK? m_config->rescueButton->setEnabled(true); // Boot not possible, maybe Rescue OK?
emit bootFailed(); emit bootFailed();
return; return;
} }
log("Booting system..."); log("Booting system...");
dfu->JumpToApp(safeboot, erase); m_dfu->JumpToApp(safeboot, erase);
// Restart the polling thread // Restart the polling thread
cm->resumePolling(); cm->resumePolling();
m_config->rescueButton->setEnabled(true); m_config->rescueButton->setEnabled(true);
m_config->telemetryLink->setEnabled(true); m_config->telemetryLink->setEnabled(true);
m_config->boardStatus->setText(tr("Running")); m_config->boardStatus->setText(tr("Running"));
if (currentStep == IAP_STATE_BOOTLOADER) { if (m_currentIAPStep == IAP_STATE_BOOTLOADER) {
// Freeze the tabs, they are not useful anymore and their buttons // Freeze the tabs, they are not useful anymore and their buttons
// will cause segfaults or weird stuff if we use them. // will cause segfaults or weird stuff if we use them.
for (int i = 0; i < m_config->systemElements->count(); i++) { for (int i = 0; i < m_config->systemElements->count(); i++) {
@ -657,11 +658,11 @@ void UploaderGadgetWidget::commonSystemBoot(bool safeboot, bool erase)
} }
} }
} }
currentStep = IAP_STATE_READY; m_currentIAPStep = IAP_STATE_READY;
log("You can now reconnect telemetry..."); log("You can now reconnect telemetry...");
delete dfu; // Frees up the USB/Serial port too delete m_dfu; // Frees up the USB/Serial port too
emit bootSuccess(); emit bootSuccess();
dfu = NULL; m_dfu = NULL;
} }
bool UploaderGadgetWidget::autoUpdateCapable() bool UploaderGadgetWidget::autoUpdateCapable()
@ -671,8 +672,15 @@ bool UploaderGadgetWidget::autoUpdateCapable()
bool UploaderGadgetWidget::autoUpdate(bool erase) bool UploaderGadgetWidget::autoUpdate(bool erase)
{ {
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); if (m_oplinkwatchdog.isConnected() &&
m_oplinkwatchdog.oplinkType() == OPLinkWatchdog::OPLINK_STANDALONE) {
emit progressUpdate(FAILURE, QVariant(tr("To upgrade OPLink board please disconnect it from the USB port, "
"press the Upgrade again button and follow instructions on screen.")));
emit autoUpdateFailed();
return false;
}
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
Q_ASSERT(pluginManager); Q_ASSERT(pluginManager);
TelemetryManager *telemetryManager = pluginManager->getObject<TelemetryManager>(); TelemetryManager *telemetryManager = pluginManager->getObject<TelemetryManager>();
Q_ASSERT(telemetryManager); Q_ASSERT(telemetryManager);
@ -717,20 +725,20 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
disconnect(this, SIGNAL(bootloaderFailed()), &eventLoop, SLOT(fail())); disconnect(this, SIGNAL(bootloaderFailed()), &eventLoop, SLOT(fail()));
} }
if (dfu) { if (m_dfu) {
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
} }
Core::ConnectionManager *connectionManager = Core::ICore::instance()->connectionManager(); Core::ConnectionManager *connectionManager = Core::ICore::instance()->connectionManager();
dfu = new DFUObject(DFU_DEBUG, false, QString()); m_dfu = new DFUObject(DFU_DEBUG, false, QString());
dfu->AbortOperation(); m_dfu->AbortOperation();
emit progressUpdate(JUMP_TO_BL, QVariant()); emit progressUpdate(JUMP_TO_BL, QVariant());
if (!dfu->enterDFU(0) || !dfu->findDevices() || if (!m_dfu->enterDFU(0) || !m_dfu->findDevices() ||
(dfu->numberOfDevices != 1) || dfu->numberOfDevices > 5) { (m_dfu->numberOfDevices != 1) || m_dfu->numberOfDevices > 5) {
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
connectionManager->resumePolling(); connectionManager->resumePolling();
emit progressUpdate(FAILURE, QVariant(tr("Failed to enter bootloader mode."))); emit progressUpdate(FAILURE, QVariant(tr("Failed to enter bootloader mode.")));
emit autoUpdateFailed(); emit autoUpdateFailed();
@ -739,7 +747,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
QString filename; QString filename;
emit progressUpdate(LOADING_FW, QVariant()); emit progressUpdate(LOADING_FW, QVariant());
switch (dfu->devices[0].ID) { switch (m_dfu->devices[0].ID) {
case 0x301: case 0x301:
filename = "fw_oplinkmini"; filename = "fw_oplinkmini";
break; break;
@ -760,7 +768,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
filename = "fw_discoveryf4bare"; filename = "fw_discoveryf4bare";
break; break;
default: default:
emit progressUpdate(FAILURE, QVariant(tr("Unknown board id '0x%1'").arg(QString::number(dfu->devices[0].ID, 16)))); emit progressUpdate(FAILURE, QVariant(tr("Unknown board id '0x%1'").arg(QString::number(m_dfu->devices[0].ID, 16))));
emit autoUpdateFailed(); emit autoUpdateFailed();
return false; return false;
} }
@ -779,16 +787,16 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
} }
firmware = file.readAll(); firmware = file.readAll();
QEventLoop eventLoop2; QEventLoop eventLoop2;
connect(dfu, SIGNAL(progressUpdated(int)), this, SLOT(autoUpdateFlashProgress(int))); connect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(autoUpdateFlashProgress(int)));
connect(dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &eventLoop2, SLOT(quit())); connect(m_dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &eventLoop2, SLOT(quit()));
emit progressUpdate(UPLOADING_FW, QVariant()); emit progressUpdate(UPLOADING_FW, QVariant());
if (!dfu->enterDFU(0)) { if (!m_dfu->enterDFU(0)) {
emit progressUpdate(FAILURE, QVariant(tr("Could not enter direct firmware upload mode."))); emit progressUpdate(FAILURE, QVariant(tr("Could not enter direct firmware upload mode.")));
emit autoUpdateFailed(); emit autoUpdateFailed();
return false; return false;
} }
dfu->AbortOperation(); m_dfu->AbortOperation();
if (!dfu->UploadFirmware(filename, false, 0)) { if (!m_dfu->UploadFirmware(filename, false, 0)) {
emit progressUpdate(FAILURE, QVariant(tr("Firmware upload failed."))); emit progressUpdate(FAILURE, QVariant(tr("Firmware upload failed.")));
emit autoUpdateFailed(); emit autoUpdateFailed();
return false; return false;
@ -796,7 +804,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
eventLoop2.exec(); eventLoop2.exec();
QByteArray desc = firmware.right(100); QByteArray desc = firmware.right(100);
emit progressUpdate(UPLOADING_DESC, QVariant()); emit progressUpdate(UPLOADING_DESC, QVariant());
if (dfu->UploadDescription(desc) != OP_DFU::Last_operation_Success) { if (m_dfu->UploadDescription(desc) != OP_DFU::Last_operation_Success) {
emit progressUpdate(FAILURE, QVariant(tr("Failed to upload firmware description."))); emit progressUpdate(FAILURE, QVariant(tr("Failed to upload firmware description.")));
emit autoUpdateFailed(); emit autoUpdateFailed();
return false; return false;
@ -806,10 +814,12 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
// Wait for board to connect to GCS again after boot and erase // Wait for board to connect to GCS again after boot and erase
// For older board like CC3D this can take some time // For older board like CC3D this can take some time
if (!telemetryManager->isConnected()) { // Theres a special case with OPLink
if (!telemetryManager->isConnected() && !m_oplinkwatchdog.isConnected()) {
progressUpdate(erase ? BOOTING_AND_ERASING : BOOTING, QVariant()); progressUpdate(erase ? BOOTING_AND_ERASING : BOOTING, QVariant());
ResultEventLoop eventLoop; ResultEventLoop eventLoop;
connect(telemetryManager, SIGNAL(connected()), &eventLoop, SLOT(success())); connect(telemetryManager, SIGNAL(connected()), &eventLoop, SLOT(success()));
connect(&m_oplinkwatchdog, SIGNAL(standaloneConnected()), &eventLoop, SLOT(success()));
if (eventLoop.run(REBOOT_TIMEOUT + (erase ? ERASE_TIMEOUT : 0)) != 0) { if (eventLoop.run(REBOOT_TIMEOUT + (erase ? ERASE_TIMEOUT : 0)) != 0) {
emit progressUpdate(FAILURE, QVariant(tr("Timed out while booting."))); emit progressUpdate(FAILURE, QVariant(tr("Timed out while booting.")));
@ -817,6 +827,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
return false; return false;
} }
disconnect(&m_oplinkwatchdog, SIGNAL(standaloneConnected()), &eventLoop, SLOT(success()));
disconnect(telemetryManager, SIGNAL(connected()), &eventLoop, SLOT(success())); disconnect(telemetryManager, SIGNAL(connected()), &eventLoop, SLOT(success()));
} }
@ -861,9 +872,9 @@ void UploaderGadgetWidget::systemRescue()
// Existing DFU objects will have a handle over USB and will // Existing DFU objects will have a handle over USB and will
// disturb everything for the rescue process: // disturb everything for the rescue process:
if (dfu) { if (m_dfu) {
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
} }
// Avoid users pressing Rescue twice. // Avoid users pressing Rescue twice.
@ -907,39 +918,39 @@ void UploaderGadgetWidget::systemRescue()
} }
log("Detecting first board..."); log("Detecting first board...");
dfu = new DFUObject(DFU_DEBUG, false, QString()); m_dfu = new DFUObject(DFU_DEBUG, false, QString());
dfu->AbortOperation(); m_dfu->AbortOperation();
if (!dfu->enterDFU(0)) { if (!m_dfu->enterDFU(0)) {
log("Could not enter DFU mode."); log("Could not enter DFU mode.");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
m_config->rescueButton->setEnabled(true); m_config->rescueButton->setEnabled(true);
return; return;
} }
if (!dfu->findDevices() || (dfu->numberOfDevices != 1)) { if (!m_dfu->findDevices() || (m_dfu->numberOfDevices != 1)) {
log("Could not detect a board, aborting!"); log("Could not detect a board, aborting!");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
m_config->rescueButton->setEnabled(true); m_config->rescueButton->setEnabled(true);
return; return;
} }
log(QString("Found %1 device(s).").arg(dfu->numberOfDevices)); log(QString("Found %1 device(s).").arg(m_dfu->numberOfDevices));
if (dfu->numberOfDevices > 5) { if (m_dfu->numberOfDevices > 5) {
log("Inconsistent number of devices, aborting!"); log("Inconsistent number of devices, aborting!");
delete dfu; delete m_dfu;
dfu = NULL; m_dfu = NULL;
cm->resumePolling(); cm->resumePolling();
m_config->rescueButton->setEnabled(true); m_config->rescueButton->setEnabled(true);
return; return;
} }
for (int i = 0; i < dfu->numberOfDevices; i++) { for (int i = 0; i < m_dfu->numberOfDevices; i++) {
DeviceWidget *dw = new DeviceWidget(this); DeviceWidget *dw = new DeviceWidget(this);
connectSignalSlot(dw); connectSignalSlot(dw);
dw->setDeviceID(i); dw->setDeviceID(i);
dw->setDfu(dfu); dw->setDfu(m_dfu);
dw->populate(); dw->populate();
m_config->systemElements->addTab(dw, tr("Device") + QString::number(i)); m_config->systemElements->addTab(dw, tr("Device") + QString::number(i));
} }
@ -949,7 +960,7 @@ void UploaderGadgetWidget::systemRescue()
m_config->rescueButton->setEnabled(false); m_config->rescueButton->setEnabled(false);
// So that we can boot from the GUI afterwards. // So that we can boot from the GUI afterwards.
currentStep = IAP_STATE_BOOTLOADER; m_currentIAPStep = IAP_STATE_BOOTLOADER;
} }
void UploaderGadgetWidget::uploadStarted() void UploaderGadgetWidget::uploadStarted()
@ -1017,6 +1028,7 @@ void UploaderGadgetWidget::finishAutoUpdate()
{ {
disconnect(this, SIGNAL(progressUpdate(uploader::ProgressStep, QVariant)), this, SLOT(autoUpdateStatus(uploader::ProgressStep, QVariant))); disconnect(this, SIGNAL(progressUpdate(uploader::ProgressStep, QVariant)), this, SLOT(autoUpdateStatus(uploader::ProgressStep, QVariant)));
m_config->autoUpdateOkButton->setEnabled(true); m_config->autoUpdateOkButton->setEnabled(true);
m_autoupdateClosing = true;
// wait a bit and "close" auto update // wait a bit and "close" auto update
QTimer::singleShot(AUTOUPDATE_CLOSE_TIMEOUT, this, SLOT(closeAutoUpdate())); QTimer::singleShot(AUTOUPDATE_CLOSE_TIMEOUT, this, SLOT(closeAutoUpdate()));
@ -1024,9 +1036,12 @@ void UploaderGadgetWidget::finishAutoUpdate()
void UploaderGadgetWidget::closeAutoUpdate() void UploaderGadgetWidget::closeAutoUpdate()
{ {
m_config->autoUpdateGroupBox->setVisible(false); if (m_autoupdateClosing) {
m_config->buttonFrame->setEnabled(true); m_config->autoUpdateGroupBox->setVisible(false);
m_config->splitter->setEnabled(true); m_config->buttonFrame->setEnabled(true);
m_config->splitter->setEnabled(true);
}
m_autoupdateClosing = false;
} }
void UploaderGadgetWidget::autoUpdateStatus(uploader::ProgressStep status, QVariant value) void UploaderGadgetWidget::autoUpdateStatus(uploader::ProgressStep status, QVariant value)

View File

@ -35,12 +35,15 @@
#include "op_dfu.h" #include "op_dfu.h"
#include <QProgressDialog> #include <QProgressDialog>
#include "oplinkwatchdog.h"
using namespace OP_DFU; using namespace OP_DFU;
using namespace uploader; using namespace uploader;
class FlightStatus; class FlightStatus;
class UAVObject; class UAVObject;
class OPLinkStatus;
class OPLinkWatchdog;
class TimedDialog : public QProgressDialog { class TimedDialog : public QProgressDialog {
Q_OBJECT Q_OBJECT
@ -140,9 +143,11 @@ signals:
private: private:
Ui_UploaderWidget *m_config; Ui_UploaderWidget *m_config;
DFUObject *dfu; DFUObject *m_dfu;
IAPStep currentStep; IAPStep m_currentIAPStep;
bool resetOnly; bool m_resetOnly;
OPLinkWatchdog m_oplinkwatchdog;
bool m_autoupdateClosing;
void clearLog(); void clearLog();
QString getPortDevice(const QString &friendName); QString getPortDevice(const QString &friendName);
@ -177,6 +182,7 @@ private slots:
void finishAutoUpdate(); void finishAutoUpdate();
void closeAutoUpdate(); void closeAutoUpdate();
void autoUpdateStatus(uploader::ProgressStep status, QVariant value); void autoUpdateStatus(uploader::ProgressStep status, QVariant value);
void oplinkUpdated();
}; };
#endif // UPLOADERGADGETWIDGET_H #endif // UPLOADERGADGETWIDGET_H