1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-17 02:52:12 +01:00

Merge branch 'next' into corvuscorax/OP-1161_magnetometer-alarm

This commit is contained in:
Corvus Corax 2014-05-08 21:16:21 +02:00
commit ce8e9db362
12 changed files with 497 additions and 484 deletions

View File

@ -743,26 +743,15 @@ void MainWindow::registerDefaultActions()
tmpaction->setEnabled(true);
connect(tmpaction, SIGNAL(triggered()), this, SLOT(showHelp()));
// About sep
#ifndef Q_WS_MAC // doesn't have the "About" actions in the Help menu
// About GCS Action
// Mac doesn't have the "About" actions in the Help menu
#ifndef Q_WS_MAC
tmpaction = new QAction(this);
tmpaction->setSeparator(true);
cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Help.Sep.About"), m_globalContext);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
#endif
// About GCS Action
#ifdef Q_WS_MAC
#else
#endif
#ifdef Q_WS_MAC
#endif
connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutOpenPilotGCS()));
// About Plugins Action
tmpaction = new QAction(QIcon(Constants::ICON_PLUGIN), tr("About &Plugins..."), this);
cmd = am->registerAction(tmpaction, Constants::ABOUT_PLUGINS, m_globalContext);

View File

@ -37,47 +37,64 @@ void AutoUpdatePage::enableButtons(bool enable = false)
void AutoUpdatePage::updateStatus(uploader::AutoUpdateStep status, QVariant value)
{
QString msg;
switch (status) {
case uploader::WAITING_DISCONNECT:
getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint);
disableButtons();
ui->statusLabel->setText("Waiting for all OP boards to be disconnected");
ui->statusLabel->setText(tr("Waiting for all OP boards to be disconnected."));
// TODO get rid of magic number 20s (should use UploaderGadgetWidget::BOARD_EVENT_TIMEOUT)
ui->levellinProgressBar->setMaximum(20);
ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::WAITING_CONNECT:
getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
getWizard()->setWindowIcon(qApp->windowIcon());
// Note:
// the following commented out lines were probably added to fix an issue when uploader opened a popup requesting
// user to disconnect all boards
// Side effect is that the wizard dialog flickers
// the uploader was changed to avoid popups alltogether and that fix is not need anymore
// same commented fix can be found in FAILURE case and they are kept for future ref.
// getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
// getWizard()->setWindowIcon(qApp->windowIcon());
// getWizard()->show();
// End of Note
disableButtons();
getWizard()->show();
ui->statusLabel->setText("Please connect the board to the USB port (don't use external supply)");
ui->statusLabel->setText(tr("Please connect the board to the USB port (don't use external supply)."));
// TODO get rid of magic number 20s (should use UploaderGadgetWidget::BOARD_EVENT_TIMEOUT)
ui->levellinProgressBar->setMaximum(20);
ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::JUMP_TO_BL:
ui->levellinProgressBar->setValue(0);
ui->statusLabel->setText("Board going into bootloader mode");
ui->statusLabel->setText(tr("Board going into bootloader mode."));
break;
case uploader::LOADING_FW:
ui->statusLabel->setText("Loading firmware");
ui->statusLabel->setText(tr("Loading firmware."));
break;
case uploader::UPLOADING_FW:
ui->statusLabel->setText("Uploading firmware");
ui->statusLabel->setText(tr("Uploading firmware."));
ui->levellinProgressBar->setMaximum(100);
ui->levellinProgressBar->setValue(value.toInt());
break;
case uploader::UPLOADING_DESC:
ui->statusLabel->setText("Uploading description");
ui->statusLabel->setText(tr("Uploading description."));
break;
case uploader::BOOTING:
ui->statusLabel->setText("Booting the board");
ui->statusLabel->setText(tr("Booting the board."));
break;
case uploader::SUCCESS:
enableButtons(true);
ui->statusLabel->setText("Board updated, please press 'Next' to continue");
ui->statusLabel->setText(tr("Board updated, please press 'Next' to continue."));
break;
case uploader::FAILURE:
getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
getWizard()->setWindowIcon(qApp->windowIcon());
// getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint);
// 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 = tr("Something went wrong, you will have to manually upgrade the board using the uploader plugin.");
}
ui->statusLabel->setText(QString("<font color='red'>%1</font>").arg(msg));
break;
}
}

View File

@ -5,6 +5,7 @@ QT += svg
include(../../openpilotgcsplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../libs/version_info/version_info.pri)
include(telemetry_dependencies.pri)
HEADERS += telemetry_global.h \

View File

@ -1,3 +1,4 @@
include(../../plugins/uavtalk/uavtalk.pri)
include(../../plugins/uavobjects/uavobjects.pri)
include(../../plugins/uavobjectutil/uavobjectutil.pri)
include(../../plugins/uavtalk/uavtalk.pri)

View File

@ -28,21 +28,26 @@
#include "telemetryplugin.h"
#include "monitorgadgetfactory.h"
#include "extensionsystem/pluginmanager.h"
#include "version_info/version_info.h"
#include "uavobjectmanager.h"
#include "uavobject.h"
#include "coreplugin/icore.h"
#include "coreplugin/connectionmanager.h"
#include <QDebug>
#include <QtPlugin>
#include <QStringList>
#include "uavobjectutilmanager.h"
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/iuavgadget.h>
#include <coreplugin/connectionmanager.h>
#include <uavtalk/telemetrymanager.h>
TelemetryPlugin::TelemetryPlugin()
#include <QDebug>
#include <QStringList>
#include <QWidget>
#include <QMainWindow>
#include <QMessageBox>
#include <QCheckBox>
TelemetryPlugin::TelemetryPlugin() : firmwareWarningMessageBox(0)
{}
TelemetryPlugin::~TelemetryPlugin()
@ -81,166 +86,83 @@ bool TelemetryPlugin::initialize(const QStringList & args, QString *errMsg)
// add monitor widget to connection manager
Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager();
// connect(cm, SIGNAL(deviceConnected(QIODevice *)), w, SLOT(telemetryConnected()));
// connect(cm, SIGNAL(deviceDisconnected()), w, SLOT(telemetryDisconnected()));
cm->addWidget(w);
// Listen to autopilot connection events
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
connect(telMngr, SIGNAL(connected()), this, SLOT(versionMatchCheck()));
return true;
}
void TelemetryPlugin::extensionsInitialized()
{
// Core::ICore::instance()->readSettings(this);
// ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
// connect(pm, SIGNAL(objectAdded(QObject *)), this, SLOT(onTelemetryManagerAdded(QObject *)));
// _toRemoveNotifications.clear();
// connectNotifications();
}
// void TelemetryPlugin::saveConfig(QSettings *settings, UAVConfigInfo *configInfo)
// {
// configInfo->setVersion(VERSION);
//
// settings->beginWriteArray("Current");
// settings->setArrayIndex(0);
// currentNotification.saveState(settings);
// settings->endArray();
//
// settings->beginGroup("listNotifies");
// settings->remove("");
// settings->endGroup();
//
// settings->beginWriteArray("listNotifies");
// for (int i = 0; i < _notificationList.size(); i++) {
// settings->setArrayIndex(i);
// _notificationList.at(i)->saveState(settings);
// }
// settings->endArray();
// settings->setValue(QLatin1String("Enable"), enable);
// }
// void TelemetryPlugin::readConfig(QSettings *settings, UAVConfigInfo * /* configInfo */)
// {
//// Just for migration to the new format.
//// Q_ASSERT(configInfo->version() == UAVConfigVersion());
//
// settings->beginReadArray("Current");
// settings->setArrayIndex(0);
// currentNotification.restoreState(settings);
// settings->endArray();
//
//// read list of notifications from settings
// int size = settings->beginReadArray("listNotifies");
// for (int i = 0; i < size; ++i) {
// settings->setArrayIndex(i);
// NotificationItem *notification = new NotificationItem;
// notification->restoreState(settings);
// _notificationList.append(notification);
// }
// settings->endArray();
// setEnable(settings->value(QLatin1String("Enable"), 0).toBool());
// }
// void TelemetryPlugin::onTelemetryManagerAdded(QObject *obj)
// {
// telMngr = qobject_cast<TelemetryManager *>(obj);
// if (telMngr) {
// connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect()));
// }
// }
void TelemetryPlugin::shutdown()
{
// Do nothing
}
// void TelemetryPlugin::onAutopilotDisconnect()
// {
// connectNotifications();
// }
void TelemetryPlugin::shutdown()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
///*!
// clear any telemetry timers from previous flight;
// reset will be perform on start of option page
// */
// void TelemetryPlugin::resetNotification(void)
// {
//// first, reject empty args and unknown fields.
// foreach(NotificationItem * ntf, _notificationList) {
// ntf->disposeTimer();
// disconnect(ntf->getTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification()));
// ntf->disposeExpireTimer();
// disconnect(ntf->getExpireTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification()));
// }
// }
disconnect(telMngr, SIGNAL(connected()), this, SLOT(versionMatchCheck()));
// void TelemetryPlugin::connectNotifications()
// {
// foreach(UAVDataObject * obj, lstNotifiedUAVObjects) {
// if (obj != NULL) {
// disconnect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(on_arrived_Notification(UAVObject *)));
// }
// }
// if (phonon.mo != NULL) {
// delete phonon.mo;
// phonon.mo = NULL;
// }
//
// if (!enable) {
// return;
// }
//
// ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
// UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
//
// lstNotifiedUAVObjects.clear();
// _pendingNotifications.clear();
// _notificationList.append(_toRemoveNotifications);
// _toRemoveNotifications.clear();
//
//// first, reject empty args and unknown fields.
// foreach(NotificationItem * telemetry, _notificationList) {
// telemetry->_isPlayed = false;
// telemetry->isNowPlaying = false;
//
// if (telemetry->mute()) {
// continue;
// }
//// check is all sounds presented for notification,
//// if not - we must not subscribe to it at all
// if (telemetry->toList().isEmpty()) {
// continue;
// }
//
// UAVDataObject *obj = dynamic_cast<UAVDataObject *>(objManager->getObject(telemetry->getDataObject()));
// if (obj != NULL) {
// if (!lstNotifiedUAVObjects.contains(obj)) {
// lstNotifiedUAVObjects.append(obj);
//
// connect(obj, SIGNAL(objectUpdated(UAVObject *)),
// this, SLOT(on_arrived_Notification(UAVObject *)),
// Qt::QueuedConnection);
// }
// } else {
// qTelemetryDebug() << "Error: Object is unknown (" << telemetry->getDataObject() << ").";
// }
// }
//
// if (_notificationList.isEmpty()) {
// return;
// }
//// set notification message to current event
// phonon.mo = Phonon::createPlayer(Phonon::NotificationCategory);
// phonon.mo->clearQueue();
// phonon.firstPlay = true;
// QList<Phonon::AudioOutputDevice> audioOutputDevices =
// Phonon::BackendCapabilities::availableAudioOutputDevices();
// foreach(Phonon::AudioOutputDevice dev, audioOutputDevices) {
// qTelemetryDebug() << "Telemetry: Audio Output device: " << dev.name() << " - " << dev.description();
// }
// connect(phonon.mo, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
// this, SLOT(stateChanged(Phonon::State, Phonon::State)));
// }
if (firmwareWarningMessageBox) {
delete firmwareWarningMessageBox;
}
}
void TelemetryPlugin::versionMatchCheck()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
deviceDescriptorStruct boardDescription = utilMngr->getBoardDescriptionStruct();
QString uavoHash = VersionInfo::uavoHashArray();
uavoHash.chop(2);
uavoHash.remove(0, 2);
uavoHash = uavoHash.trimmed();
QByteArray uavoHashArray;
bool ok;
foreach(QString str, uavoHash.split(",")) {
uavoHashArray.append(str.toInt(&ok, 16));
}
QByteArray fwVersion = boardDescription.uavoHash;
if (fwVersion != uavoHashArray) {
QString gcsDescription = VersionInfo::revision();
QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":") + 1, 8);
gcsGitHash.remove(QRegExp("^[0]*"));
QString gcsGitDate = gcsDescription.mid(gcsDescription.indexOf(" ") + 1, 14);
QString gcsUavoHashStr;
QString fwUavoHashStr;
foreach(char i, fwVersion) {
fwUavoHashStr.append(QString::number(i, 16).right(2));
}
foreach(char i, uavoHashArray) {
gcsUavoHashStr.append(QString::number(i, 16).right(2));
}
QString versionFormat = "%1 (%2-%3)";
QString gcsVersion = versionFormat.arg(gcsGitDate, gcsGitHash, gcsUavoHashStr.left(8));
QString fwVersion = versionFormat.arg(boardDescription.gitDate, boardDescription.gitHash, fwUavoHashStr.left(8));
if (!firmwareWarningMessageBox) {
firmwareWarningMessageBox = new QMessageBox(Core::ICore::instance()->mainWindow());
firmwareWarningMessageBox->setWindowModality(Qt::NonModal);
firmwareWarningMessageBox->setWindowTitle(tr("Firmware Version Mismatch!"));
firmwareWarningMessageBox->setIcon(QMessageBox::Warning);
firmwareWarningMessageBox->setStandardButtons(QMessageBox::Ok);
firmwareWarningMessageBox->setText(tr("GCS and firmware versions of the UAV objects set do not match which can cause configuration problems."));
// should we want to re-introduce the checkbox
// firmwareWarningMessageBox->setCheckBox(new QCheckBox(tr("&Don't show this message again.")));
}
QString detailTxt = tr("GCS version: %1").arg(gcsVersion) + "\n" + tr("Firmware version: %1").arg(fwVersion);
firmwareWarningMessageBox->setDetailedText(detailTxt);
firmwareWarningMessageBox->show();
}
}

View File

@ -29,6 +29,7 @@
#include <extensionsystem/iplugin.h>
class QMessageBox;
class MonitorGadgetFactory;
class TelemetryPlugin : public ExtensionSystem::IPlugin {
@ -44,8 +45,12 @@ public:
bool initialize(const QStringList &arguments, QString *errorString);
void shutdown();
private slots:
void versionMatchCheck();
private:
MonitorGadgetFactory *mf;
QMessageBox *firmwareWarningMessageBox;
};
#endif // TELEMETRYPLUGIN_H

View File

@ -47,7 +47,16 @@
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@ -88,10 +97,10 @@ menu on the right.</string>
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reboot the board and clear its settings memory.&lt;/p&gt;&lt;p&gt; Useful if the board cannot boot properly.&lt;/p&gt;&lt;p&gt; Blue led starts blinking quick for 20-30 seconds than the board will start normally&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If telemetry is not running, select the link using the dropdown&lt;/p&gt;&lt;p&gt;menu on the right.&lt;/p&gt;&lt;p&gt;PLEASE NOTE: Supported with bootloader versions 4.0 and earlier&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reboot the board and clear its settings memory.&lt;/p&gt;&lt;p&gt; Useful if the board cannot boot properly.&lt;/p&gt;&lt;p&gt; Blue led starts blinking quick for 20-30 seconds than the board will start normally&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If telemetry is not running, select the link using the dropdown&lt;/p&gt;&lt;p&gt;menu on the right.&lt;/p&gt;&lt;p&gt;PLEASE NOTE: Supported with bootloader versions 4.0 and later&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Erase settings</string>
<string>Erase Settings</string>
</property>
</widget>
</item>
@ -192,6 +201,12 @@ through serial or USB)</string>
</item>
<item row="0" column="11">
<widget class="QLabel" name="boardStatus">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
@ -277,7 +292,7 @@ Rescue is possible in USB mode only.</string>
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
<bool>true</bool>
</property>
</widget>
</item>

View File

@ -1,6 +1,6 @@
include(../../openpilotgcsplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/uavobjects/uavobjects.pri)
include(../../plugins/uavobjectutil/uavobjectutil.pri)
include(../../plugins/uavtalk/uavtalk.pri)
include(../../plugins/ophid/ophid.pri)
include(../../plugins/uavobjectutil/uavobjectutil.pri)

View File

@ -25,18 +25,111 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "uploadergadgetwidget.h"
#include "version_info/version_info.h"
#include "flightstatus.h"
#include "flightstatus.h"
#include "delay.h"
#include "devicewidget.h"
#include "runningdevicewidget.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/connectionmanager.h>
#include <uavtalk/telemetrymanager.h>
#include <QDesktopServices>
#include <QMessageBox>
#include <QProgressBar>
#include <QDebug>
#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) :
QProgressDialog(labelText, tr("Cancel"), 0, timeout, parent, flags), bar(new QProgressBar(this))
{
setWindowTitle(title);
setAutoReset(false);
// open immediately...
setMinimumDuration(0);
// setup progress bar
bar->setRange(0, timeout);
bar->setFormat(tr("Timing out in %1 seconds").arg(timeout));
setBar(bar);
}
void TimedDialog::perform()
{
setValue(value() + 1);
int remaining = bar->maximum() - bar->value();
if (remaining > 0) {
bar->setFormat(tr("Timing out in %1 seconds").arg(remaining));
} else {
bar->setFormat(tr("Timed out after %1 seconds").arg(bar->maximum()));
}
}
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::cancel()
{
quit();
result = ConnectionWaiter::Canceled;
}
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();
}
}
int ConnectionWaiter::openDialog(const QString &title, const QString &labelText, int targetDeviceCount, int timeout, QWidget *parent, Qt::WindowFlags flags)
{
TimedDialog dlg(title, labelText, timeout / 1000, parent, flags);
ConnectionWaiter waiter(targetDeviceCount, timeout, parent);
connect(&dlg, SIGNAL(canceled()), &waiter, SLOT(cancel()));
connect(&waiter, SIGNAL(timeChanged(int)), &dlg, SLOT(perform()));
return waiter.exec();
}
UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
{
m_config = new Ui_UploaderWidget();
@ -44,35 +137,31 @@ 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<TelemetryManager>();
connect(telMngr, SIGNAL(connected()), this, SLOT(onAutopilotConnect()));
connect(telMngr, SIGNAL(connected()), this, SLOT(versionMatchCheck()));
connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect()));
Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager();
connect(cm, SIGNAL(deviceConnected(QIODevice *)), this, SLOT(onPhysicalHWConnect()));
connect(m_config->haltButton, SIGNAL(clicked()), this, SLOT(systemHalt()));
connect(m_config->resetButton, SIGNAL(clicked()), this, SLOT(systemReset()));
connect(m_config->bootButton, SIGNAL(clicked()), this, SLOT(systemBoot()));
connect(m_config->safeBootButton, SIGNAL(clicked()), this, SLOT(systemSafeBoot()));
connect(m_config->eraseBootButton, SIGNAL(clicked()), this, SLOT(systemEraseBoot()));
connect(m_config->rescueButton, SIGNAL(clicked()), this, SLOT(systemRescue()));
Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager();
connect(cm, SIGNAL(deviceConnected(QIODevice *)), this, SLOT(onPhisicalHWConnect()));
getSerialPorts();
m_config->autoUpdateButton->setEnabled(autoUpdateCapable());
connect(m_config->autoUpdateButton, SIGNAL(clicked()), this, SLOT(startAutoUpdate()));
connect(m_config->autoUpdateOkButton, SIGNAL(clicked()), this, SLOT(closeAutoUpdate()));
m_config->autoUpdateButton->setEnabled(autoUpdateCapable());
m_config->autoUpdateGroupBox->setVisible(false);
QIcon rbi;
rbi.addFile(QString(":uploader/images/view-refresh.svg"));
m_config->refreshPorts->setIcon(rbi);
m_config->refreshPorts->setIcon(QIcon(":uploader/images/view-refresh.svg"));
bootButtonsSetEnable(false);
@ -82,11 +171,9 @@ UploaderGadgetWidget::UploaderGadgetWidget(QWidget *parent) : QWidget(parent)
// And check whether by any chance we are not already connected
if (telMngr->isConnected()) {
onAutopilotConnect();
versionMatchCheck();
}
}
bool sortPorts(const QSerialPortInfo &s1, const QSerialPortInfo &s2)
{
return s1.portName() < s2.portName();
@ -141,7 +228,7 @@ FlightStatus *UploaderGadgetWidget::getFlightStatus()
Q_ASSERT(pm);
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
Q_ASSERT(objManager);
FlightStatus *status = dynamic_cast<FlightStatus *>(objManager->getObject(QString("FlightStatus")));
FlightStatus *status = dynamic_cast<FlightStatus *>(objManager->getObject("FlightStatus"));
Q_ASSERT(status);
return status;
}
@ -151,14 +238,12 @@ void UploaderGadgetWidget::bootButtonsSetEnable(bool enabled)
m_config->bootButton->setEnabled(enabled);
m_config->safeBootButton->setEnabled(enabled);
m_config->eraseBootButton->setEnabled(
enabled &&
// this feature is supported only on BL revision >= 4
((dfu != NULL) && (dfu->devices[0].BL_Version >= 4)));
// this feature is supported only on BL revision >= 4
bool isBL4 = ((dfu != NULL) && (dfu->devices[0].BL_Version >= 4));
m_config->eraseBootButton->setEnabled(isBL4 && enabled);
}
void UploaderGadgetWidget::onPhisicalHWConnect()
void UploaderGadgetWidget::onPhysicalHWConnect()
{
bootButtonsSetEnable(false);
m_config->rescueButton->setEnabled(false);
@ -190,7 +275,7 @@ void UploaderGadgetWidget::populate()
}
RunningDeviceWidget *dw = new RunningDeviceWidget(this);
dw->populate();
m_config->systemElements->addTab(dw, QString("Connected Device"));
m_config->systemElements->addTab(dw, tr("Connected Device"));
}
/**
@ -210,6 +295,14 @@ void UploaderGadgetWidget::onAutopilotDisconnect()
}
}
static void sleep(int ms)
{
QEventLoop eventLoop;
QTimer::singleShot(ms, &eventLoop, SLOT(quit()));
eventLoop.exec();
}
/**
Tell the mainboard to go to bootloader:
- Send the relevant IAP commands
@ -221,7 +314,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVObject *fwIAP = dynamic_cast<UAVDataObject *>(objManager->getObject(QString("FirmwareIAPObj")));
UAVObject *fwIAP = dynamic_cast<UAVDataObject *>(objManager->getObject("FirmwareIAPObj"));
switch (currentStep) {
case IAP_STATE_READY:
@ -235,39 +328,37 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
connect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
currentStep = IAP_STATE_STEP_1;
clearLog();
log(QString("IAP Step 1"));
log("IAP Step 1");
fwIAP->updated();
break;
case IAP_STATE_STEP_1:
if (!success) {
log(QString("Oops, failure step 1"));
log("Oops, failure step 1");
log("Reset did NOT happen");
currentStep = IAP_STATE_READY;
disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
m_config->haltButton->setEnabled(true);
break;
}
QTimer::singleShot(600, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
sleep(600);
fwIAP->getField("Command")->setValue("2233");
currentStep = IAP_STATE_STEP_2;
log(QString("IAP Step 2"));
log("IAP Step 2");
fwIAP->updated();
break;
case IAP_STATE_STEP_2:
if (!success) {
log(QString("Oops, failure step 2"));
log("Oops, failure step 2");
log("Reset did NOT happen");
currentStep = IAP_STATE_READY;
disconnect(fwIAP, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(goToBootloader(UAVObject *, bool)));
m_config->haltButton->setEnabled(true);
break;
}
QTimer::singleShot(600, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
sleep(600);
fwIAP->getField("Command")->setValue("3344");
currentStep = IAP_STEP_RESET;
log(QString("IAP Step 3"));
log("IAP Step 3");
fwIAP->updated();
break;
case IAP_STEP_RESET:
@ -286,14 +377,12 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
QString dli = cm->getCurrentDevice().getConName();
QString dlj = cm->getCurrentDevice().getConName();
cm->disconnectDevice();
QTimer::singleShot(200, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
sleep(200);
// Tell connections to stop their polling threads: otherwise it will mess up DFU
cm->suspendPolling();
QTimer::singleShot(200, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
sleep(200);
log("Board Halt");
m_config->boardStatus->setText("Bootloader");
m_config->boardStatus->setText(tr("Bootloader"));
if (dlj.startsWith("USB")) {
m_config->telemetryLink->setCurrentIndex(m_config->telemetryLink->findText("USB"));
} else {
@ -319,7 +408,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
dfu = NULL;
cm->resumePolling();
currentStep = IAP_STATE_READY;
m_config->boardStatus->setText("Bootloader?");
m_config->boardStatus->setText(tr("Bootloader?"));
m_config->haltButton->setEnabled(true);
return;
}
@ -330,15 +419,14 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
dfu = NULL;
cm->resumePolling();
currentStep = IAP_STATE_READY;
m_config->boardStatus->setText("Bootloader?");
m_config->boardStatus->setText(tr("Bootloader?"));
return;
}
// dfu.StatusRequest();
QTimer::singleShot(500, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
sleep(500);
dfu->findDevices();
log(QString("Found ") + QString::number(dfu->numberOfDevices) + QString(" device(s)."));
log(QString("Found %1 device(s).").arg(QString::number(dfu->numberOfDevices)));
if (dfu->numberOfDevices < 0 || dfu->numberOfDevices > 3) {
log("Inconsistent number of devices! Aborting");
delete dfu;
@ -358,7 +446,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
dw->setDeviceID(i);
dw->setDfu(dfu);
dw->populate();
m_config->systemElements->addTab(dw, QString("Device") + QString::number(i));
m_config->systemElements->addTab(dw, tr("Device") + QString::number(i));
}
// Need to re-enable in case we were not connected
@ -380,20 +468,14 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
void UploaderGadgetWidget::systemHalt()
{
FlightStatus *status = getFlightStatus();
// The board can not be halted when in armed state.
// If board is armed, or arming. Show message with notice.
FlightStatus *status = getFlightStatus();
if (status->getArmed() == FlightStatus::ARMED_DISARMED) {
goToBootloader();
} else {
QMessageBox mbox(this);
mbox.setText(QString(tr("The controller board is armed and can not be halted.\n\n"
"Please make sure the board is not armed and then press halt again to proceed\n"
"or use the rescue option to force a firmware upgrade.")));
mbox.setStandardButtons(QMessageBox::Ok);
mbox.setIcon(QMessageBox::Warning);
mbox.exec();
cannotHaltMessageBox();
}
}
@ -418,13 +500,7 @@ void UploaderGadgetWidget::systemReset()
log("Board Reset initiated.");
goToBootloader();
} else {
QMessageBox mbox(this);
mbox.setText(QString(tr("The controller board is armed and can not be reset.\n\n"
"Please make sure the board is not armed and then press reset again to proceed\n"
"or power cycle to force a board reset.")));
mbox.setStandardButtons(QMessageBox::Ok);
mbox.setIcon(QMessageBox::Warning);
mbox.exec();
cannotResetMessageBox();
}
}
@ -440,20 +516,17 @@ void UploaderGadgetWidget::systemSafeBoot()
void UploaderGadgetWidget::systemEraseBoot()
{
QMessageBox msgBox;
int result;
msgBox.setWindowTitle(tr("Erase Settings"));
msgBox.setInformativeText(tr("Do you want to erase all settings from the board?\nSettings cannot be recovered after this operation.\nThe board will be restarted and all the setting erased"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel | QMessageBox::Help);
result = msgBox.exec();
if (result == QMessageBox::Ok) {
switch (confirmEraseSettingsMessageBox()) {
case QMessageBox::Ok:
commonSystemBoot(true, true);
} else if (result == QMessageBox::Help) {
break;
case QMessageBox::Help:
QDesktopServices::openUrl(QUrl(tr("http://wiki.openpilot.org/display/Doc/Erase+board+settings"), QUrl::StrictMode));
break;
}
}
/**
* Tells the system to boot (from Bootloader state)
* @param[in] safeboot Indicates whether the firmware should use the stock HWSettings
@ -494,7 +567,7 @@ void UploaderGadgetWidget::commonSystemBoot(bool safeboot, bool erase)
cm->resumePolling();
m_config->rescueButton->setEnabled(true);
m_config->telemetryLink->setEnabled(true);
m_config->boardStatus->setText("Running");
m_config->boardStatus->setText(tr("Running"));
if (currentStep == IAP_STATE_BOOTLOADER) {
// Freeze the tabs, they are not useful anymore and their buttons
// will cause segfaults or weird stuff if we use them.
@ -531,32 +604,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;
}
timer.start(500);
loop.exec();
}
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());
@ -581,6 +647,7 @@ bool UploaderGadgetWidget::autoUpdate()
emit autoUpdateSignal(FAILURE, QVariant());
return false;
}
QString filename;
emit autoUpdateSignal(LOADING_FW, QVariant());
switch (dfu->devices[0].ID) {
@ -617,9 +684,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(progressUpdated(int)), this, SLOT(autoUpdateFlashProgress(int)));
connect(dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &eventLoop, SLOT(quit()));
emit autoUpdateSignal(UPLOADING_FW, QVariant());
if (!dfu->enterDFU(0)) {
emit autoUpdateSignal(FAILURE, QVariant());
@ -630,7 +698,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) {
@ -642,7 +710,17 @@ 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);
}
@ -658,62 +736,62 @@ void UploaderGadgetWidget::systemRescue()
cm->disconnectDevice();
// stop the polling thread: otherwise it will mess up DFU
cm->suspendPolling();
// Delete all previous tabs:
while (m_config->systemElements->count()) {
QWidget *qw = m_config->systemElements->widget(0);
m_config->systemElements->removeTab(0);
delete qw;
}
// Existing DFU objects will have a handle over USB and will
// disturb everything for the rescue process:
if (dfu) {
delete dfu;
dfu = NULL;
}
// Avoid users pressing Rescue twice.
m_config->rescueButton->setEnabled(false);
// Now we're good to go:
// Now we're good to go
clearLog();
log("**********************************************************");
log("** Follow those instructions to attempt a system rescue **");
log("**********************************************************");
log("You will be prompted to first connect USB, then system power");
// Check if boards are connected and, if yes, prompt user to disconnect them all
if (USBMonitor::instance()->availableDevices(0x20a0, -1, -1, -1).length() > 0) {
if (QMessageBox::warning(this, tr("OpenPilot Uploader"), tr("Please disconnect your OpenPilot board"), QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Cancel) {
QString labelText = QString("<p align=\"left\">%1</p>").arg(tr("Please disconnect your OpenPilot board."));
int result = ConnectionWaiter::openDialog(tr("System Rescue"), labelText, 0, BOARD_EVENT_TIMEOUT, this);
switch (result) {
case ConnectionWaiter::Canceled:
m_config->rescueButton->setEnabled(true);
return;
case ConnectionWaiter::TimedOut:
QMessageBox::warning(this, tr("System Rescue"), tr("Timed out while waiting for all boards to be disconnected!"));
m_config->rescueButton->setEnabled(true);
return;
}
}
// Now we're good to go:
clearLog();
log("**********************************************************");
log("** Follow those instructions to attempt a system rescue **");
log("**********************************************************");
log("You will be prompted to first connect USB, then system power");
m_progress = new QProgressDialog(tr("Please connect your OpenPilot board (USB only!)"), tr("Cancel"), 0, 20);
QProgressBar *bar = new QProgressBar(m_progress);
bar->setFormat("Timeout");
m_progress->setBar(bar);
m_progress->setMinimumDuration(0);
m_progress->setRange(0, 20);
connect(m_progress, SIGNAL(canceled()), this, SLOT(cancel()));
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(perform()));
m_timer->start(1000);
connect(USBMonitor::instance(), SIGNAL(deviceDiscovered(USBPortInfo)), &m_eventloop, SLOT(quit()));
m_eventloop.exec();
if (!m_timer->isActive()) {
m_progress->close();
m_timer->stop();
QMessageBox::warning(this, tr("OpenPilot Uploader"), tr("No board connection was detected!"));
// Now prompt user to connect board
QString labelText = QString("<p align=\"left\">%1<br>%2</p>").arg(tr("Please connect your OpenPilot board.")).arg(tr("Board must be connected to the USB port!"));
int result = ConnectionWaiter::openDialog(tr("System Rescue"), labelText, 1, BOARD_EVENT_TIMEOUT, this);
switch (result) {
case ConnectionWaiter::Canceled:
m_config->rescueButton->setEnabled(true);
return;
case ConnectionWaiter::TimedOut:
QMessageBox::warning(this, tr("System Rescue"), tr("Timed out while waiting for a board to be connected!"));
m_config->rescueButton->setEnabled(true);
return;
}
m_progress->close();
m_timer->stop();
log("... Detecting First Board...");
repaint();
log("Detecting first board...");
dfu = new DFUObject(DFU_DEBUG, false, QString());
dfu->AbortOperation();
if (!dfu->enterDFU(0)) {
@ -732,7 +810,8 @@ void UploaderGadgetWidget::systemRescue()
m_config->rescueButton->setEnabled(true);
return;
}
log(QString("Found ") + QString::number(dfu->numberOfDevices) + QString(" device(s)."));
log(QString("Found %1 device(s).").arg(dfu->numberOfDevices));
if (dfu->numberOfDevices > 5) {
log("Inconsistent number of devices, aborting!");
delete dfu;
@ -747,36 +826,15 @@ void UploaderGadgetWidget::systemRescue()
dw->setDeviceID(i);
dw->setDfu(dfu);
dw->populate();
m_config->systemElements->addTab(dw, QString("Device") + QString::number(i));
m_config->systemElements->addTab(dw, tr("Device") + QString::number(i));
}
m_config->haltButton->setEnabled(false);
m_config->resetButton->setEnabled(false);
bootButtonsSetEnable(true);
m_config->rescueButton->setEnabled(false);
currentStep = IAP_STATE_BOOTLOADER; // So that we can boot from the GUI afterwards.
}
void UploaderGadgetWidget::perform()
{
if (m_progress->value() == 19) {
m_timer->stop();
m_eventloop.exit();
}
m_progress->setValue(m_progress->value() + 1);
}
void UploaderGadgetWidget::performAuto()
{
++autoUpdateConnectTimeout;
emit autoUpdateSignal(WAITING_CONNECT, autoUpdateConnectTimeout * 5);
if (autoUpdateConnectTimeout == 20) {
m_timer->stop();
m_eventloop.exit();
}
}
void UploaderGadgetWidget::cancel()
{
m_timer->stop();
m_eventloop.exit();
// So that we can boot from the GUI afterwards.
currentStep = IAP_STATE_BOOTLOADER;
}
void UploaderGadgetWidget::uploadStarted()
@ -823,6 +881,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();
}
@ -831,14 +890,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);
@ -846,37 +904,57 @@ 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->autoUpdateLabel->setText(tr("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->autoUpdateLabel->setText(tr("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);
m_config->autoUpdateLabel->setText("Bringing the board into boot loader mode.");
m_config->autoUpdateLabel->setText(tr("Bringing the board into boot loader mode."));
break;
case uploader::LOADING_FW:
m_config->autoUpdateLabel->setText("Preparing to upload firmware to the board.");
m_config->autoUpdateLabel->setText(tr("Preparing to upload firmware to the board."));
break;
case uploader::UPLOADING_FW:
m_config->autoUpdateLabel->setText("Uploading firmware to the board.");
m_config->autoUpdateLabel->setText(tr("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:
m_config->autoUpdateLabel->setText("Uploading description of the new firmware to the board.");
m_config->autoUpdateLabel->setText(tr("Uploading description of the new firmware to the board."));
break;
case uploader::BOOTING:
m_config->autoUpdateLabel->setText("Rebooting the board.");
m_config->autoUpdateLabel->setText(tr("Rebooting the board."));
break;
case uploader::SUCCESS:
m_config->autoUpdateLabel->setText("<font color='green'>Board was updated successfully, press OK to finish.</font>");
m_config->autoUpdateProgressBar->setValue(m_config->autoUpdateProgressBar->maximum());
msg = tr("Board was updated successfully.");
msg += " " + tr("Press OK to finish.");
m_config->autoUpdateLabel->setText(QString("<font color='green'>%1</font>").arg(msg));
finishAutoUpdate();
break;
case uploader::FAILURE:
m_config->autoUpdateLabel->setText("<font color='red'>Something went wrong, you will have to manually upgrade the board. Press OK to continue.</font>");
msg = value.toString();
if (msg.isEmpty()) {
msg = tr("Something went wrong, you will have to manually upgrade the board.");
}
msg += " " + tr("Press OK to finish.");
m_config->autoUpdateLabel->setText(QString("<font color='red'>%1</font>").arg(msg));
finishAutoUpdate();
break;
}
@ -887,9 +965,8 @@ void UploaderGadgetWidget::autoUpdateStatus(uploader::AutoUpdateStep status, QVa
*/
void UploaderGadgetWidget::log(QString str)
{
qDebug() << str;
qDebug() << "UploaderGadgetWidget -" << str;
m_config->textBrowser->append(str);
m_config->textBrowser->repaint();
}
void UploaderGadgetWidget::clearLog()
@ -908,92 +985,45 @@ 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.
@param errorString The error string to display.
@param errorNumber Not used
*/
void UploaderGadgetWidget::error(QString errorString, int errorNumber)
{
Q_UNUSED(errorNumber);
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(errorString);
msgBox.exec();
m_config->boardStatus->setText(errorString);
}
/**
Shows a message box with an information string.
@param infoString The information string to display.
@param infoNumber Not used
*/
void UploaderGadgetWidget::info(QString infoString, int infoNumber)
{
Q_UNUSED(infoNumber);
m_config->boardStatus->setText(infoString);
}
void UploaderGadgetWidget::versionMatchCheck()
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
deviceDescriptorStruct boardDescription = utilMngr->getBoardDescriptionStruct();
QByteArray uavoHashArray;
QString uavoHash = VersionInfo::uavoHashArray();
uavoHash.chop(2);
uavoHash.remove(0, 2);
uavoHash = uavoHash.trimmed();
bool ok;
foreach(QString str, uavoHash.split(",")) {
uavoHashArray.append(str.toInt(&ok, 16));
}
QByteArray fwVersion = boardDescription.uavoHash;
if (fwVersion != uavoHashArray) {
QString gcsDescription = VersionInfo::revision();
QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":") + 1, 8);
gcsGitHash.remove(QRegExp("^[0]*"));
QString gcsGitDate = gcsDescription.mid(gcsDescription.indexOf(" ") + 1, 14);
QString gcsUavoHashStr;
QString fwUavoHashStr;
foreach(char i, fwVersion) {
fwUavoHashStr.append(QString::number(i, 16).right(2));
}
foreach(char i, uavoHashArray) {
gcsUavoHashStr.append(QString::number(i, 16).right(2));
}
QString gcsVersion = gcsGitDate + " (" + gcsGitHash + "-" + gcsUavoHashStr.left(8) + ")";
QString fwVersion = boardDescription.gitDate + " (" + boardDescription.gitHash + "-" + fwUavoHashStr.left(8) + ")";
QString warning = QString(tr(
"GCS and firmware versions of the UAV objects set do not match which can cause configuration problems. "
"GCS version: %1 Firmware version: %2.")).arg(gcsVersion).arg(fwVersion);
msg->showMessage(warning);
}
}
void UploaderGadgetWidget::openHelp()
{
QDesktopServices::openUrl(QUrl("http://wiki.openpilot.org/x/AoBZ", QUrl::StrictMode));
}
int UploaderGadgetWidget::confirmEraseSettingsMessageBox()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Confirm Settings Erase?"));
msgBox.setIcon(QMessageBox::Question);
msgBox.setText(tr("Do you want to erase all settings from the board?"));
msgBox.setInformativeText(tr("Settings cannot be recovered after this operation.\nThe board will be restarted and all settings erased."));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel | QMessageBox::Help);
return msgBox.exec();
}
int UploaderGadgetWidget::cannotHaltMessageBox()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Cannot Halt Board!"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(tr("The controller board is armed and can not be halted."));
msgBox.setInformativeText(tr("Please make sure the board is not armed and then press Halt again to proceed or use Rescue to force a firmware upgrade."));
msgBox.setStandardButtons(QMessageBox::Ok);
return msgBox.exec();
}
int UploaderGadgetWidget::cannotResetMessageBox()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Cannot Reset Board!"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(tr("The controller board is armed and can not be reset."));
msgBox.setInformativeText(tr("Please make sure the board is not armed and then press reset again to proceed or power cycle to force a board reset."));
msgBox.setStandardButtons(QMessageBox::Ok);
return msgBox.exec();
}

View File

@ -29,79 +29,111 @@
#define UPLOADERGADGETWIDGET_H
#include "ui_uploader.h"
#include "delay.h"
#include "devicewidget.h"
#include "runningdevicewidget.h"
#include "op_dfu.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include "extensionsystem/pluginmanager.h"
#include "uavobjectmanager.h"
#include "uavobject.h"
#include "coreplugin/icore.h"
#include "coreplugin/connectionmanager.h"
#include "ophid/inc/ophid_plugin.h"
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QThread>
#include <QMessageBox>
#include <QTimer>
#include "devicedescriptorstruct.h"
#include <QProgressDialog>
#include <QErrorMessage>
#include <QDesktopServices>
#include "uploader_global.h"
#include "enums.h"
#include "op_dfu.h"
#include <QProgressDialog>
using namespace OP_DFU;
using namespace uploader;
class FlightStatus;
class UAVObject;
class TimedDialog : public QProgressDialog {
Q_OBJECT
public:
TimedDialog(const QString &title, const QString &labelText, int timeout, QWidget *parent = 0, Qt::WindowFlags flags = 0);
private slots:
void perform();
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 ResultCode { Ok, Canceled, TimedOut };
public slots:
int exec();
void cancel();
void quit();
static int openDialog(const QString &title, const QString &labelText, int targetDeviceCount, int timeout, QWidget *parent = 0, Qt::WindowFlags flags = 0);
signals:
void timeChanged(int elapsed);
private slots:
void perform();
void deviceEvent();
private:
QEventLoop eventLoop;
QTimer timer;
// timeout in ms
int timeout;
// elapsed time in seconds
int elapsed;
int targetDeviceCount;
int result;
};
class UPLOADER_EXPORT UploaderGadgetWidget : public QWidget {
Q_OBJECT
public:
UploaderGadgetWidget(QWidget *parent = 0);
~UploaderGadgetWidget();
static const int BOARD_EVENT_TIMEOUT;
static const int AUTOUPDATE_CLOSE_TIMEOUT;
void log(QString str);
bool autoUpdateCapable();
public slots:
void onAutopilotConnect();
void onAutopilotDisconnect();
void populate();
void openHelp();
bool autoUpdate();
void autoUpdateProgress(int);
void autoUpdateDisconnectProgress(int);
void autoUpdateConnectProgress(int);
void autoUpdateFlashProgress(int);
signals:
void autoUpdateSignal(uploader::AutoUpdateStep, QVariant);
private:
Ui_UploaderWidget *m_config;
DFUObject *dfu;
IAPStep currentStep;
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;
int confirmEraseSettingsMessageBox();
int cannotHaltMessageBox();
int cannotResetMessageBox();
private slots:
void onPhisicalHWConnect();
void versionMatchCheck();
void error(QString errorString, int errorNumber);
void info(QString infoString, int infoNumber);
void onPhysicalHWConnect();
void goToBootloader(UAVObject * = NULL, bool = false);
void systemHalt();
void systemReset();
@ -111,9 +143,6 @@ private slots:
void commonSystemBoot(bool safeboot = false, bool erase = false);
void systemRescue();
void getSerialPorts();
void perform();
void performAuto();
void cancel();
void uploadStarted();
void uploadEnded(bool succeed);
void downloadStarted();

View File

@ -26,10 +26,11 @@
*/
#include "uploaderplugin.h"
#include "uploadergadgetfactory.h"
#include <QtPlugin>
#include <QStringList>
#include <extensionsystem/pluginmanager.h>
#include <QStringList>
UploaderPlugin::UploaderPlugin()
{
// Do nothing
@ -44,8 +45,10 @@ bool UploaderPlugin::initialize(const QStringList & args, QString *errMsg)
{
Q_UNUSED(args);
Q_UNUSED(errMsg);
mf = new UploaderGadgetFactory(this);
addAutoReleasedObject(mf);
return true;
}

View File

@ -44,6 +44,7 @@ public:
void extensionsInitialized();
bool initialize(const QStringList & arguments, QString *errorString);
void shutdown();
private:
UploaderGadgetFactory *mf;
};