Commit 3fef8e4d authored by Don Gagne's avatar Don Gagne

Merge pull request #1232 from DonLakeFlyer/FirmwareUpgrade

Convert Firmware Upgrade to QML
parents c51c5688 381acec9
......@@ -338,7 +338,6 @@ FORMS += \
src/ui/px4_configuration/QGCPX4MulticopterConfig.ui \
src/ui/px4_configuration/QGCPX4SensorCalibration.ui \
src/ui/px4_configuration/PX4RCCalibration.ui \
src/ui/px4_configuration/PX4FirmwareUpgrade.ui \
src/ui/QGCUASFileView.ui \
src/QGCQmlWidgetHolder.ui \
src/ui/QGCMapRCToParamDialog.ui \
......@@ -475,9 +474,6 @@ HEADERS += \
src/ui/px4_configuration/QGCPX4SensorCalibration.h \
src/ui/px4_configuration/PX4RCCalibration.h \
src/ui/px4_configuration/RCValueWidget.h \
src/ui/px4_configuration/PX4Bootloader.h \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.h \
src/ui/px4_configuration/PX4FirmwareUpgrade.h \
src/uas/UASManagerInterface.h \
src/uas/QGCUASParamManagerInterface.h \
src/uas/QGCUASFileManager.h \
......@@ -622,9 +618,6 @@ SOURCES += \
src/ui/px4_configuration/QGCPX4SensorCalibration.cc \
src/ui/px4_configuration/PX4RCCalibration.cc \
src/ui/px4_configuration/RCValueWidget.cc \
src/ui/px4_configuration/PX4Bootloader.cc \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc \
src/ui/px4_configuration/PX4FirmwareUpgrade.cc \
src/uas/QGCUASFileManager.cc \
src/ui/QGCUASFileView.cc \
src/CmdLineOptParser.cc \
......@@ -718,6 +711,10 @@ SOURCES += \
#
# AutoPilot Plugin Support
#
INCLUDEPATH += \
src/VehicleSetup
FORMS += \
src/VehicleSetup/ParameterEditor.ui \
src/ui/QGCPX4VehicleConfig.ui \
......@@ -728,6 +725,9 @@ HEADERS+= \
src/VehicleSetup/SetupView.h \
src/VehicleSetup/ParameterEditor.h \
src/VehicleSetup/VehicleComponent.h \
src/VehicleSetup/FirmwareUpgradeController.h \
src/VehicleSetup/PX4Bootloader.h \
src/VehicleSetup/PX4FirmwareUpgradeThread.h \
src/AutoPilotPlugins/AutoPilotPluginManager.h \
src/AutoPilotPlugins/AutoPilotPlugin.h \
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h \
......@@ -746,6 +746,9 @@ SOURCES += \
src/VehicleSetup/SetupView.cc \
src/VehicleSetup/ParameterEditor.cc \
src/VehicleSetup/VehicleComponent.cc \
src/VehicleSetup/FirmwareUpgradeController.cc \
src/VehicleSetup/PX4Bootloader.cc \
src/VehicleSetup/PX4FirmwareUpgradeThread.cc \
src/AutoPilotPlugins/AutoPilotPluginManager.cc \
src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc \
src/AutoPilotPlugins/Generic/GenericParameterFacts.cc \
......
......@@ -5,33 +5,100 @@ import QtQuick.Controls.Styles 1.2
import QGroundControl.Controls 1.0
import QGroundControl.FactControls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FirmwareUpgradeController 1.0
Rectangle {
width: 600
height: 400
height: 600
property var qgcPal: QGCPalette { colorGroup: QGCPalette.Active }
property FirmwareUpgradeController controller: FirmwareUpgradeController {
upgradeButton: upgradeButton
statusLog: statusTextArea
firmwareType: FirmwareUpgradeController.StableFirmware
}
color: qgcPal.window
Text {
text: "FIRMWARE UPDATE"
color: qgcPal.windowText
font.pointSize: 20
}
Column {
anchors.fill:parent
Text {
text: "FIRMWARE UPDATE"
color: qgcPal.windowText
font.pointSize: 20
}
Item {
// Just used as a spacer
height: 20
width: 10
}
ExclusiveGroup { id: firmwareGroup }
QGCRadioButton {
id: stableFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Standard Version (stable)")
checked: true
enabled: upgradeButton.enabled
onClicked: {
if (checked)
controller.firmwareType = FirmwareUpgradeController.StableFirmware
}
}
QGCRadioButton {
id: betaFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Beta Testing (beta)")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.BetaFirmware }
}
QGCRadioButton {
id: devloperFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Developer Build (master)")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.DeveloperFirmware }
}
QGCRadioButton {
id: customFirwareRadio
exclusiveGroup: firmwareGroup
text: qsTr("Custom firmware file...")
enabled: upgradeButton.enabled
onClicked: { if (checked) controller.firmwareType = FirmwareUpgradeController.CustomFirmware }
}
Item {
// Just used as a spacer
height: 20
width: 10
}
QGCButton {
id: upgradeButton
text: "UPGRADE"
onClicked: {
controller.doFirmwareUpgrade();
}
}
Item {
// Just used as a spacer
height: 20
width: 10
}
TextArea {
id: statusTextArea
width: parent.width
height: 300
readOnly: true
style: TextAreaStyle {
textColor: qgcPal.windowText
backgroundColor: qgcPal.window
}
}
}
}
......@@ -2,7 +2,7 @@
QGroundControl Open Source Ground Control Station
(c) 2009, 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
......@@ -25,7 +25,7 @@
/// @brief PX4 Firmware Upgrade UI
/// @author Don Gagne <don@thegagnes.com>
#include "PX4FirmwareUpgrade.h"
#include "FirmwareUpgradeController.h"
#include <QFile>
#include <QFileInfo>
......@@ -33,325 +33,129 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QDir>
#include <QQmlProperty>
#include <QDebug>
#include "QGCFileDialog.h"
#include "QGCMessageBox.h"
/// @Brief Constructs a new PX4FirmwareUpgrade Widget. This widget is used within the PX4VehicleConfig set of screens.
PX4FirmwareUpgrade::PX4FirmwareUpgrade(QWidget *parent) :
QWidget(parent),
_upgradeState(upgradeStateBegin),
/// @Brief Constructs a new FirmwareUpgradeController Widget. This widget is used within the PX4VehicleConfig set of screens.
FirmwareUpgradeController::FirmwareUpgradeController(void) :
_downloadManager(NULL),
_downloadNetworkReply(NULL)
_downloadNetworkReply(NULL),
_firmwareType(StableFirmware),
_upgradeButton(NULL),
_statusLog(NULL)
{
_ui = new Ui::PX4FirmwareUpgrade;
_ui->setupUi(this);
_threadController = new PX4FirmwareUpgradeThreadController(this);
Q_CHECK_PTR(_threadController);
/*
// FIXME: NYI
// Connect standard ui elements
connect(_ui->tryAgain, &QPushButton::clicked, this, &PX4FirmwareUpgrade::_tryAgainButton);
connect(_ui->cancel, &QPushButton::clicked, this, &PX4FirmwareUpgrade::_cancelButton);
connect(_ui->next, &QPushButton::clicked, this, &PX4FirmwareUpgrade::_nextButton);
connect(_ui->tryAgain, &QPushButton::clicked, this, &FirmwareUpgradeController::_tryAgainButton);
connect(_ui->cancel, &QPushButton::clicked, this, &FirmwareUpgradeController::_cancelButton);
connect(_ui->next, &QPushButton::clicked, this, &FirmwareUpgradeController::_nextButton);
connect(_ui->firmwareCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_firmwareSelected(int)));
*/
connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBoard, this, &PX4FirmwareUpgrade::_foundBoard);
connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBootloader, this, &PX4FirmwareUpgrade::_foundBootloader);
connect(_threadController, &PX4FirmwareUpgradeThreadController::bootloaderSyncFailed, this, &PX4FirmwareUpgrade::_bootloaderSyncFailed);
connect(_threadController, &PX4FirmwareUpgradeThreadController::error, this, &PX4FirmwareUpgrade::_error);
connect(_threadController, &PX4FirmwareUpgradeThreadController::complete, this, &PX4FirmwareUpgrade::_complete);
connect(_threadController, &PX4FirmwareUpgradeThreadController::findTimeout, this, &PX4FirmwareUpgrade::_findTimeout);
connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &PX4FirmwareUpgrade::_updateProgress);
connect(&_eraseTimer, &QTimer::timeout, this, &PX4FirmwareUpgrade::_eraseProgressTick);
_setupState(upgradeStateBegin);
}
PX4FirmwareUpgrade::~PX4FirmwareUpgrade()
{
}
/// @brief Returns the state machine entry for the specified state.
const PX4FirmwareUpgrade::stateMachineEntry* PX4FirmwareUpgrade::_getStateMachineEntry(enum PX4FirmwareUpgrade::upgradeStates state)
{
static const char* msgBegin = "If you are currently connected to your Pixhawk board via QGroundControl, you must 'Disconnect' from the board. "
"If your board is connected via USB, you must unplug the USB cable.\n\n"
"Click 'Next' when these two steps are complete to begin upgrading.";
static const char* msgBoardSearch = "Plug in your board via USB now...";
static const char* msgBoardNotFound = "Unable to detect your board. If the board is currently connected via USB. Disconnect it, and click 'Try Again'.";
static const char* msgBootloaderSearch = "Searching for Bootloader...";
static const char* msgBootloaderNotFound = "Unable to connect to Bootloader. If the board is currently connected via USB. Disconnect it, and click 'Try Again'.";
static const char* msgBootloaderError = "An error occured while communicating with the Bootloader.";
static const char* msgFirmwareSelect = "Please select the firmware you would like to upload to the board from the dropdown to the right.";
static const char* msgFirmwareDownloading = "Firmware downloading...";
static const char* msgFirmwareDownloadFailed = "Firmware download failed";
static const char* msgFirmwareBoardErasing = "Erasing old firmware from board...";
static const char* msgFirmwareBoardEraseFailed = "Board erase failed.";
static const char* msgFirmwareBoardFlashing = "Flashing new firmware onto board...";
static const char* msgFirmwareBoardFlashError = "A failure has occured while flashing the new firmware to your board. "
"This has left the board in an inconsistent state.\n\n"
"There currently is an known issue which does not yet have a fix which may cause this.\n\n"
"You should click 'Try Again' to attempt the upgrade process again.";
static const char* msgFirmwareBoardVerifying = "Verifying firmware on board...";
static const char* msgFirmwareBoardVerifyError = "Verification of flash memory on board failed. "
"This has left the board in an inconsistent state. "
"You should click 'Try Again' to attempt the upgrade process again.";
static const char* msgFirmwareBoardUpgraded = "Your board has been upgraded successfully.\n\nYou can now connect to your board via QGroundControl\n\nClick 'Try Again' to do another upgrade.";
static const stateMachineEntry rgStateMachine[] = {
//State Next command Cancel command Try Again command State Text
{ upgradeStateBegin, &PX4FirmwareUpgrade::_findBoard, NULL, NULL, msgBegin },
{ upgradeStateBoardSearch, NULL, &PX4FirmwareUpgrade::_cancelFind, NULL, msgBoardSearch },
{ upgradeStateBoardNotFound, NULL, &PX4FirmwareUpgrade::_cancel, &PX4FirmwareUpgrade::_findBoard, msgBoardNotFound },
{ upgradeStateBootloaderSearch, NULL, &PX4FirmwareUpgrade::_cancelFind, NULL, msgBootloaderSearch },
{ upgradeStateBootloaderNotFound, NULL, &PX4FirmwareUpgrade::_cancel, &PX4FirmwareUpgrade::_restart, msgBootloaderNotFound },
{ upgradeStateBootloaderError, NULL, &PX4FirmwareUpgrade::_cancel, NULL, msgBootloaderError },
{ upgradeStateFirmwareSelect, &PX4FirmwareUpgrade::_getFirmwareFile, &PX4FirmwareUpgrade::_cancel, NULL, msgFirmwareSelect },
{ upgradeStateFirmwareDownloading, NULL, &PX4FirmwareUpgrade::_cancelDownload, NULL, msgFirmwareDownloading },
{ upgradeStateDownloadFailed, NULL, NULL, &PX4FirmwareUpgrade::_restart, msgFirmwareDownloadFailed },
{ upgradeStateErasing, NULL, NULL, NULL, msgFirmwareBoardErasing },
{ upgradeStateEraseError, NULL, &PX4FirmwareUpgrade::_cancel, NULL, msgFirmwareBoardEraseFailed },
{ upgradeStateFlashing, NULL, NULL, NULL, msgFirmwareBoardFlashing },
{ upgradeStateFlashError, NULL, NULL, &PX4FirmwareUpgrade::_restart, msgFirmwareBoardFlashError },
{ upgradeStateVerifying, NULL, NULL, NULL, msgFirmwareBoardVerifying },
{ upgradeStateVerifyError, NULL, NULL, &PX4FirmwareUpgrade::_restart, msgFirmwareBoardVerifyError },
{ upgradeStateBoardUpgraded, NULL, NULL, &PX4FirmwareUpgrade::_restart, msgFirmwareBoardUpgraded },
};
const stateMachineEntry* entry = &rgStateMachine[state];
// Validate that our state array has not gotten out of sync
for (size_t i=0; i<upgradeStateMax; i++) {
Q_ASSERT(rgStateMachine[i].state == i);
}
return entry;
}
/// @brief Sets up the Wizard according to the specified state
void PX4FirmwareUpgrade::_setupState(enum PX4FirmwareUpgrade::upgradeStates state)
{
_upgradeState = state;
const stateMachineEntry* stateMachine = _getStateMachineEntry(state);
_ui->tryAgain->setEnabled(stateMachine->tryAgain != NULL);
_ui->skip->setEnabled(false);
_ui->cancel->setEnabled(stateMachine->cancel != NULL);
_ui->next->setEnabled(stateMachine->next != NULL);
_ui->statusLog->setText(stateMachine->msg);
if (_upgradeState == upgradeStateDownloadFailed) {
// Bootloader is still open, reboot to close and heopfully get back to FMU
_threadController->sendBootloaderReboot();
}
connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBoard, this, &FirmwareUpgradeController::_foundBoard);
connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBootloader, this, &FirmwareUpgradeController::_foundBootloader);
connect(_threadController, &PX4FirmwareUpgradeThreadController::bootloaderSyncFailed, this, &FirmwareUpgradeController::_bootloaderSyncFailed);
connect(_threadController, &PX4FirmwareUpgradeThreadController::error, this, &FirmwareUpgradeController::_error);
connect(_threadController, &PX4FirmwareUpgradeThreadController::complete, this, &FirmwareUpgradeController::_complete);
connect(_threadController, &PX4FirmwareUpgradeThreadController::findTimeout, this, &FirmwareUpgradeController::_findTimeout);
connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &FirmwareUpgradeController::_updateProgress);
_updateIndicatorUI();
}
/// @brief Updates the Indicator UI which is to the right of the Wizard area to match the current
/// upgrade state.
void PX4FirmwareUpgrade::_updateIndicatorUI(void)
{
if (_upgradeState == upgradeStateBegin) {
// Reset to intial state. All check boxes unchecked, all additional information hidden.
_ui->statusLabel->clear();
_ui->progressBar->setValue(0);
_ui->progressBar->setTextVisible(false);
_ui->boardFoundCheck->setCheckState(Qt::Unchecked);
_ui->port->setVisible(false);
_ui->description->setVisible(false);
_ui->bootloaderFoundCheck->setCheckState(Qt::Unchecked);
_ui->bootloaderVersion->setVisible(false);
_ui->boardID->setVisible(false);
_ui->icon->setVisible(false);
_ui->firmwareCombo->setVisible(false);
_ui->firmwareCombo->setEnabled(true);
_ui->selectFirmwareCheck->setCheckState(Qt::Unchecked);
_ui->firmwareDownloadedCheck->setCheckState(Qt::Unchecked);
_ui->boardUpgradedCheck->setCheckState(Qt::Unchecked);
} else if (_upgradeState == upgradeStateBootloaderSearch){
// We have found the board
_ui->statusLabel->clear();
_ui->progressBar->setValue(0);
_ui->boardFoundCheck->setCheckState(Qt::Checked);
_ui->port->setText("Port: " + _portName);
_ui->description->setText("Name: " +_portDescription);
_ui->port->setVisible(true);
_ui->description->setVisible(true);
} else if (_upgradeState == upgradeStateFirmwareSelect) {
// We've found the bootloader and need to set up firmware selection
_ui->statusLabel->clear();
_ui->progressBar->setValue(0);
_ui->bootloaderFoundCheck->setCheckState(Qt::Checked);
_ui->bootloaderVersion->setText(QString("Version: %1").arg(_bootloaderVersion));
_ui->boardID->setText(QString("Board ID: %1").arg(_boardID));
_setBoardIcon(_boardID);
_setFirmwareCombo(_boardID);
_ui->bootloaderVersion->setVisible(true);
_ui->boardID->setVisible(true);
_ui->icon->setVisible(true);
_ui->firmwareCombo->setVisible(true);
_ui->firmwareCombo->setEnabled(true);
_ui->firmwareCombo->setCurrentIndex(0);
} else if (_upgradeState == upgradeStateFirmwareDownloading) {
_ui->statusLabel->clear();
_ui->selectFirmwareCheck->setCheckState(Qt::Checked);
_ui->firmwareCombo->setEnabled(false);
} else if (_upgradeState == upgradeStateFlashing) {
_ui->statusLabel->clear();
_ui->progressBar->setValue(0);
_ui->firmwareDownloadedCheck->setCheckState(Qt::Checked);
} else if (_upgradeState == upgradeStateBoardUpgraded) {
_ui->statusLabel->clear();
_ui->progressBar->setValue(0);
_ui->boardUpgradedCheck->setCheckState((_upgradeState >= upgradeStateBoardUpgraded) ? Qt::Checked : Qt::Unchecked);
}
}
/// @brief Responds to a click on the Next Button calling the appropriate method as specified by the state machine.
void PX4FirmwareUpgrade::_nextButton(void)
{
const stateMachineEntry* stateMachine = _getStateMachineEntry(_upgradeState);
Q_ASSERT(stateMachine->next != NULL);
(this->*stateMachine->next)();
}
/// @brief Responds to a click on the Cancel Button calling the appropriate method as specified by the state machine.
void PX4FirmwareUpgrade::_cancelButton(void)
{
const stateMachineEntry* stateMachine = _getStateMachineEntry(_upgradeState);
Q_ASSERT(stateMachine->cancel != NULL);
(this->*stateMachine->cancel)();
}
/// @brief Responds to a click on the Try Again Button calling the appropriate method as specified by the state machine.
void PX4FirmwareUpgrade::_tryAgainButton(void)
{
const stateMachineEntry* stateMachine = _getStateMachineEntry(_upgradeState);
Q_ASSERT(stateMachine->tryAgain != NULL);
(this->*stateMachine->tryAgain)();
}
/// @brief Cancels a findBoard or findBootloader operation.
void PX4FirmwareUpgrade::_cancelFind(void)
{
_threadController->cancelFind();
connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick);
}
/// @brief Cancels the current state and returns to the begin start
void PX4FirmwareUpgrade::_cancel(void)
void FirmwareUpgradeController::_cancel(void)
{
_setupState(upgradeStateBegin);
// Bootloader may still still open, reboot to close and heopfully get back to FMU
_threadController->sendBootloaderReboot();
Q_ASSERT(_upgradeButton);
_upgradeButton->setEnabled(true);
}
/// @brief Begins the process or searching for the board
void PX4FirmwareUpgrade::_findBoard(void)
void FirmwareUpgradeController::_findBoard(void)
{
_setupState(upgradeStateBoardSearch);
_appendStatusLog(tr("Plug your board into USB now..."));
_searchingForBoard = true;
_threadController->findBoard(_findBoardTimeoutMsec);
}
/// @brief Called when board has been found by the findBoard process
void PX4FirmwareUpgrade::_foundBoard(bool firstTry, const QString portName, QString portDescription)
void FirmwareUpgradeController::_foundBoard(bool firstTry, const QString portName, QString portDescription)
{
if (firstTry) {
// Board is still plugged
QGCMessageBox::critical(tr("Firmware Upgrade"), tr("You must unplug you board before beginning the Firmware Upgrade process."));
_appendStatusLog(tr("You must unplug your board before beginning the Firmware Upgrade process."));
_cancel();
} else {
_portName = portName;
_portDescription = portDescription;
_setupState(upgradeStateBootloaderSearch);
_appendStatusLog(tr("Board found:"));
_appendStatusLog(tr(" Port: %1").arg(_portName));
_appendStatusLog(tr(" Description: %1").arg(_portName));
_findBootloader();
}
}
/// @brief Begins the findBootloader process to connect to the bootloader
void PX4FirmwareUpgrade::_findBootloader(void)
void FirmwareUpgradeController::_findBootloader(void)
{
_setupState(upgradeStateBootloaderSearch);
_appendStatusLog(tr("Attemping to communicate with bootloader..."));
_searchingForBoard = false;
_threadController->findBootloader(_portName, _findBootloaderTimeoutMsec);
}
/// @brief Called when the bootloader is connected to by the findBootloader process. Moves the state machine
/// to the next step.
void PX4FirmwareUpgrade::_foundBootloader(int bootloaderVersion, int boardID, int flashSize)
void FirmwareUpgradeController::_foundBootloader(int bootloaderVersion, int boardID, int flashSize)
{
_bootloaderVersion = bootloaderVersion;
_boardID = boardID;
_boardFlashSize = flashSize;
_setupState(upgradeStateFirmwareSelect);
_appendStatusLog(tr("Connected to bootloader:"));
_appendStatusLog(tr(" Version: %1").arg(_bootloaderVersion));
_appendStatusLog(tr(" Board ID: %1").arg(_boardID));
_appendStatusLog(tr(" Flash size: %1").arg(_boardFlashSize));
_getFirmwareFile();
}
/// @brief Called when the findBootloader process is unable to sync to the bootloader. Moves the state
/// machine to the appropriate error state.
void PX4FirmwareUpgrade::_bootloaderSyncFailed(void)
void FirmwareUpgradeController::_bootloaderSyncFailed(void)
{
if (_upgradeState == upgradeStateBootloaderSearch) {
// We can connect to the board, but we still can't talk to the bootloader.
qDebug() << "Bootloader sync failed";
_setupState(upgradeStateBootloaderNotFound);
} else {
Q_ASSERT(false);
}
_appendStatusLog(tr("Unable to sync with bootloader."));
_cancel();
}
/// @brief Called when the findBoard or findBootloader process times out. Moves the state machine to the
/// appropriate error state.
void PX4FirmwareUpgrade::_findTimeout(void)
void FirmwareUpgradeController::_findTimeout(void)
{
if (_upgradeState == upgradeStateBoardSearch) {
qDebug() << "Timeout on board search";
_setupState(upgradeStateBoardNotFound);
} else if (_upgradeState == upgradeStateBootloaderSearch) {
qDebug() << "Timeout on bootloader search";
_setupState(upgradeStateBoardNotFound);
QString msg;
if (_searchingForBoard) {
msg = tr("Unable to detect your board. If the board is currently connected via USB. Disconnect it and try Upgrade again.");
} else {
Q_ASSERT(false);
msg = tr("Unable to communicate with Bootloader. If the board is currently connected via USB. Disconnect it and try Upgrade again.");
}
_appendStatusLog(msg);
_cancel();
}
/// @brief Sets the board image into the icon label according to the board id.
void PX4FirmwareUpgrade::_setBoardIcon(int boardID)
void FirmwareUpgradeController::_setBoardIcon(int boardID)
{
QString imageFile;
......@@ -373,20 +177,20 @@ void PX4FirmwareUpgrade::_setBoardIcon(int boardID)
bool success = _boardIcon.load(imageFile);
Q_ASSERT(success);
Q_UNUSED(success);
/*
// FIXME: NYI
int w = _ui->icon->width();
int h = _ui->icon->height();
_ui->icon->setPixmap(_boardIcon.scaled(w, h, Qt::KeepAspectRatio));
*/
}
}
/// @brief Sets up the selections in the firmware combox box associated with the specified
/// board id.
void PX4FirmwareUpgrade::_setFirmwareCombo(int boardID)
/// @brief Prompts the user to select a firmware file if needed and moves the state machine to the next state.
void FirmwareUpgradeController::_getFirmwareFile(void)
{
_ui->firmwareCombo->clear();
static const char* rgPX4FMUV1Firmware[3] =
{
"http://px4.oznet.ch/stable/px4fmu-v1_default.px4",
......@@ -408,16 +212,18 @@ void PX4FirmwareUpgrade::_setFirmwareCombo(int boardID)
"http://px4.oznet.ch/continuous/px4flow.px4"
};
Q_ASSERT(sizeof(rgPX4FMUV1Firmware) == sizeof(rgPX4FMUV2Firmware) && sizeof(rgPX4FMUV1Firmware) == sizeof(rgPX4FlowFirmware));
const char** prgFirmware;
switch (boardID) {
switch (_boardID) {
case _boardIDPX4FMUV1:
prgFirmware = rgPX4FMUV1Firmware;
break;
case _boardIDPX4Flow:
prgFirmware = rgPX4FlowFirmware;
break;
case _boardIDPX4FMUV2:
prgFirmware = rgPX4FMUV2Firmware;
break;
......@@ -427,71 +233,37 @@ void PX4FirmwareUpgrade::_setFirmwareCombo(int boardID)
break;
}
if (prgFirmware) {
_ui->firmwareCombo->addItem(tr("Standard Version (stable)"), prgFirmware[0]);
_ui->firmwareCombo->addItem(tr("Beta Testing (beta)"), prgFirmware[1]);
_ui->firmwareCombo->addItem(tr("Developer Build (master)"), prgFirmware[2]);
}
_ui->firmwareCombo->addItem(tr("Custom firmware file..."), "selectfile");
}
/// @brief Called when the selection in the firmware combo box changes. Updates the wizard
/// text appropriately with licensing and possibly warning information.
void PX4FirmwareUpgrade::_firmwareSelected(int index)
{
#define SELECT_FIRMWARE_LICENSE "By clicking Next you agree to the terms and disclaimer of the BSD open source license, as redistributed with the source code."
if (_upgradeState == upgradeStateFirmwareSelect) {
switch (index) {
case 0:
case 3:
_ui->statusLog->setText(tr(SELECT_FIRMWARE_LICENSE));
break;
case 1:
_ui->statusLog->setText(tr("WARNING: BETA FIRMWARE\n"
"This firmware version is ONLY intended for beta testers. "
"Although it has received FLIGHT TESTING, it represents actively changed code. Do NOT use for normal operation.\n\n"
SELECT_FIRMWARE_LICENSE));
break;
case 2:
_ui->statusLog->setText(tr("WARNING: CONTINUOUS BUILD FIRMWARE\n"
"This firmware has NOT BEEN FLIGHT TESTED. "
"It is only intended for DEVELOPERS. Run bench tests without props first. "
"Do NOT fly this without addional safety precautions. Follow the mailing "
"list actively when using it.\n\n"
SELECT_FIRMWARE_LICENSE));
break;
}
_ui->next->setEnabled(!_ui->firmwareCombo->itemData(index).toString().isEmpty());
if (prgFirmware == NULL && _firmwareType != CustomFirmware) {
QGCMessageBox::critical(tr("Firmware Upgrade"), tr("Attemping to flash an unknown board type, you must select 'Custom firmware file'"));
_cancel();
return;
}
}
/// @brief Prompts the user to select a firmware file if needed and moves the state machine to the
/// download firmware state.
void PX4FirmwareUpgrade::_getFirmwareFile(void)
{
int index = _ui->firmwareCombo->currentIndex();
_firmwareFilename = _ui->firmwareCombo->itemData(index).toString();
Q_ASSERT(!_firmwareFilename.isEmpty());
if (_firmwareFilename == "selectfile") {
_firmwareFilename = QGCFileDialog::getOpenFileName(
this,
tr("Load Firmware File"), // Dialog Caption
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory
tr("Firmware Files (*.px4 *.bin)")); // File filter
if (_firmwareType == CustomFirmware) {
_firmwareFilename = QGCFileDialog::getOpenFileName(NULL, // Parent to main window
tr("Select Firmware File"), // Dialog Caption
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory
tr("Firmware Files (*.px4 *.bin)")); // File filter
} else {
_firmwareFilename = prgFirmware[_firmwareType];
}
if (!_firmwareFilename.isEmpty()) {
if (_firmwareFilename.isEmpty()) {
_cancel();
} else {
_downloadFirmware();
}
}
/// @brief Begins the process of downloading the selected firmware file.
void PX4FirmwareUpgrade::_downloadFirmware(void)
void FirmwareUpgradeController::_downloadFirmware(void)
{
// Split out filename from path
Q_ASSERT(!_firmwareFilename.isEmpty());
_appendStatusLog(tr("Downloading firmware..."));
_appendStatusLog(tr(" From: %1").arg(_firmwareFilename));
// Split out filename from path
QString firmwareFilename = QFileInfo(_firmwareFilename).fileName();
Q_ASSERT(!firmwareFilename.isEmpty());
......@@ -500,8 +272,8 @@ void PX4FirmwareUpgrade::_downloadFirmware(void)
if (downloadFile.isEmpty()) {
downloadFile = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
if (downloadFile.isEmpty()) {
_setupState(upgradeStateDownloadFailed);
_ui->statusLabel->setText(tr("Unabled to find writable download location. Tried downloads and temp directory."));
_appendStatusLog(tr("Unabled to find writable download location. Tried downloads and temp directory."));
_cancel();
return;
}
}
......@@ -525,33 +297,29 @@ void PX4FirmwareUpgrade::_downloadFirmware(void)
Q_CHECK_PTR(_downloadManager);
_downloadNetworkReply = _downloadManager->get(networkRequest);
Q_ASSERT(_downloadNetworkReply);
connect(_downloadNetworkReply, &QNetworkReply::downloadProgress, this, &PX4FirmwareUpgrade::_downloadProgress);
connect(_downloadNetworkReply, &QNetworkReply::finished, this, &PX4FirmwareUpgrade::_downloadFinished);
connect(_downloadNetworkReply, &QNetworkReply::downloadProgress, this, &FirmwareUpgradeController::_downloadProgress);
connect(_downloadNetworkReply, &QNetworkReply::finished, this, &FirmwareUpgradeController::_downloadFinished);
// FIXME
//connect(_downloadNetworkReply, &QNetworkReply::error, this, &PX4FirmwareUpgrade::_downloadError);
//connect(_downloadNetworkReply, &QNetworkReply::error, this, &FirmwareUpgradeController::_downloadError);
connect(_downloadNetworkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(_downloadError(QNetworkReply::NetworkError)));
_setupState(upgradeStateFirmwareDownloading);
}
/// @brief Cancels a download which is in progress.
void PX4FirmwareUpgrade::_cancelDownload(void)
{
_downloadNetworkReply->abort();
}
/// @brief Updates the progress indicator while downloading
void PX4FirmwareUpgrade::_downloadProgress(qint64 curr, qint64 total)
void FirmwareUpgradeController::_downloadProgress(qint64 curr, qint64 total)
{
// Take care of cases where 0 / 0 is emitted as error return value
if (total > 0) {
_ui->progressBar->setValue((curr*100) / total);
// FIXME: NYI
Q_UNUSED(curr);
//_ui->progressBar->setValue((curr*100) / total);
}
}
/// @brief Called when the firmware download completes.
void PX4FirmwareUpgrade::_downloadFinished(void)
void FirmwareUpgradeController::_downloadFinished(void)
{
_appendStatusLog(tr("Download complete"));
QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
Q_ASSERT(reply);
......@@ -573,8 +341,8 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
// Store downloaded file in download location
QFile file(downloadFilename);
if (!file.open(QIODevice::WriteOnly)) {
_ui->statusLabel->setText(tr("Could not save downloaded file to %1. Error: %2").arg(downloadFilename).arg(file.errorString()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Could not save downloaded file to %1. Error: %2").arg(downloadFilename).arg(file.errorString()));
_cancel();
return;
}
......@@ -587,8 +355,7 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
QFile px4File(downloadFilename);
if (!px4File.open(QIODevice::ReadOnly | QIODevice::Text)) {
_ui->statusLabel->setText(tr("Unable to open firmware file %1, error: %2").arg(downloadFilename).arg(px4File.errorString()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Unable to open firmware file %1, error: %2").arg(downloadFilename).arg(px4File.errorString()));
return;
}
......@@ -597,8 +364,8 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
QJsonDocument doc = QJsonDocument::fromJson(bytes);
if (doc.isNull()) {
_ui->statusLabel->setText(tr("supplied file is not a valid JSON document"));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Supplied file is not a valid JSON document"));
_cancel();
return;
}
......@@ -608,23 +375,23 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
static const char* rgJsonKeys[] = { "board_id", "image_size", "description", "git_identity" };
for (size_t i=0; i<sizeof(rgJsonKeys)/sizeof(rgJsonKeys[0]); i++) {
if (!px4Json.contains(rgJsonKeys[i])) {
_ui->statusLabel->setText(tr("Incorrectly formatted firmware file. No %1 key.").arg(rgJsonKeys[i]));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Incorrectly formatted firmware file. No %1 key.").arg(rgJsonKeys[i]));
_cancel();
return;
}
}
uint32_t firmwareBoardID = (uint32_t)px4Json.value(QString("board_id")).toInt();
if (firmwareBoardID != _boardID) {
_ui->statusLabel->setText(tr("Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardID).arg(_boardID));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardID).arg(_boardID));
_cancel();
return;
}
_imageSize = px4Json.value(QString("image_size")).toInt();
if (_imageSize == 0) {
_ui->statusLabel->setText(tr("Image size of 0 in .px4 file %1").arg(downloadFilename));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Image size of 0 in .px4 file %1").arg(downloadFilename));
_cancel();
return;
}
qDebug() << "Image size from px4:" << _imageSize;
......@@ -657,13 +424,13 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
QByteArray b = uncompressed;
if (b.count() == 0) {
_ui->statusLabel->setText(tr("Firmware file has 0 length image"));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Firmware file has 0 length image"));
_cancel();
return;
}
if (b.count() != (int)_imageSize) {
_ui->statusLabel->setText(tr("Image size for decompressed image does not match stored image size: Expected(%1) Actual(%2)").arg(_imageSize).arg(b.count()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Image size for decompressed image does not match stored image size: Expected(%1) Actual(%2)").arg(_imageSize).arg(b.count()));
_cancel();
return;
}
......@@ -678,15 +445,15 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
QFile decompressFile(decompressFilename);
if (!decompressFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
_ui->statusLabel->setText(tr("Unable to open decompressed file %1 for writing, error: %2").arg(decompressFilename).arg(decompressFile.errorString()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Unable to open decompressed file %1 for writing, error: %2").arg(decompressFilename).arg(decompressFile.errorString()));
_cancel();
return;
}
qint64 bytesWritten = decompressFile.write(b);
if (bytesWritten != b.count()) {
_ui->statusLabel->setText(tr("Write failed for decompressed image file, error: %1").arg(decompressFile.errorString()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Write failed for decompressed image file, error: %1").arg(decompressFile.errorString()));
_cancel();
return;
}
decompressFile.close();
......@@ -706,8 +473,8 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
}
if (firmwareBoardID != 0 && firmwareBoardID != _boardID) {
_ui->statusLabel->setText(tr("Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardID).arg(_boardID));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardID).arg(_boardID));
_cancel();
return;
}
......@@ -715,8 +482,9 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
QFile binFile(_firmwareFilename);
if (!binFile.open(QIODevice::ReadOnly)) {
_ui->statusLabel->setText(tr("Unabled to open firmware file %1, %2").arg(_firmwareFilename).arg(binFile.errorString()));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Unabled to open firmware file %1, %2").arg(_firmwareFilename).arg(binFile.errorString()));
_cancel();
return;
}
_imageSize = (uint32_t)binFile.size();
binFile.close();
......@@ -727,8 +495,8 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
}
if (_imageSize > _boardFlashSize) {
_ui->statusLabel->setText(tr("Image size of %1 is too large for board flash size %2").arg(_imageSize).arg(_boardFlashSize));
_setupState(upgradeStateDownloadFailed);
_appendStatusLog(tr("Image size of %1 is too large for board flash size %2").arg(_imageSize).arg(_boardFlashSize));
_cancel();
return;
}
......@@ -736,24 +504,24 @@ void PX4FirmwareUpgrade::_downloadFinished(void)
}
/// @brief Called when an error occurs during download
void PX4FirmwareUpgrade::_downloadError(QNetworkReply::NetworkError code)
void FirmwareUpgradeController::_downloadError(QNetworkReply::NetworkError code)
{
if (code == QNetworkReply::OperationCanceledError) {
_ui->statusLabel->setText(tr("Download cancelled"));
_appendStatusLog(tr("Download cancelled"));
} else {
_ui->statusLabel->setText(tr("Error during download. Error: %1").arg(code));
_appendStatusLog(tr("Error during download. Error: %1").arg(code));
}
_setupState(upgradeStateDownloadFailed);
_cancel();
}
/// @brief Erase the board
void PX4FirmwareUpgrade::_erase(void)
void FirmwareUpgradeController::_erase(void)
{
_appendStatusLog(tr("Erasing previous firmware..."));
// We set up our own progress bar for erase since the erase command does not provide one
_eraseTickCount = 0;
_eraseTimer.start(_eraseTickMsec);
_setupState(upgradeStateErasing);
// Erase command
_threadController->erase();
......@@ -761,24 +529,27 @@ void PX4FirmwareUpgrade::_erase(void)
/// @brief Signals completion of one of the specified bootloader commands. Moves the state machine to the
/// appropriate next step.
void PX4FirmwareUpgrade::_complete(const int command)
void FirmwareUpgradeController::_complete(const int command)
{
if (command == PX4FirmwareUpgradeThreadWorker::commandProgram) {
_setupState(upgradeStateVerifying);
_appendStatusLog(tr("Verifying board programming..."));
_threadController->verify(_firmwareFilename);
} else if (command == PX4FirmwareUpgradeThreadWorker::commandVerify) {
_setupState(upgradeStateBoardUpgraded);
_appendStatusLog(tr("Upgrade complete"));
QGCMessageBox::information(tr("Firmware Upgrade"), tr("Upgrade completed succesfully"));
_cancel();
} else if (command == PX4FirmwareUpgradeThreadWorker::commandErase) {
_eraseTimer.stop();
_setupState(upgradeStateFlashing);
_appendStatusLog(tr("Flashing new firmware to board..."));
_threadController->program(_firmwareFilename);
} else if (command == PX4FirmwareUpgradeThreadWorker::commandCancel) {
if (_upgradeState == upgradeStateBoardSearch) {
_setupState(upgradeStateBoardNotFound);
} else if (_upgradeState == upgradeStateBootloaderSearch) {
_setupState(upgradeStateBootloaderNotFound);
// FIXME: This is no longer needed, no Cancel
if (_searchingForBoard) {
_appendStatusLog(tr("Board not found"));
_cancel();
} else {
Q_ASSERT(false);
_appendStatusLog(tr("Bootloader not found"));
_cancel();
}
} else {
Q_ASSERT(false);
......@@ -787,38 +558,55 @@ void PX4FirmwareUpgrade::_complete(const int command)
/// @brief Signals that an error has occured with the specified bootloader commands. Moves the state machine
/// to the appropriate error state.
void PX4FirmwareUpgrade::_error(const int command, const QString errorString)
void FirmwareUpgradeController::_error(const int command, const QString errorString)
{
_ui->statusLabel->setText(tr("Error: %1").arg(errorString));
Q_UNUSED(command);
if (command == PX4FirmwareUpgradeThreadWorker::commandProgram) {
_setupState(upgradeStateFlashError);
} else if (command == PX4FirmwareUpgradeThreadWorker::commandErase) {
_setupState(upgradeStateEraseError);
} else if (command == PX4FirmwareUpgradeThreadWorker::commandBootloader) {
_setupState(upgradeStateBootloaderError);
} else if (command == PX4FirmwareUpgradeThreadWorker::commandVerify) {
_setupState(upgradeStateVerifyError);
} else {
Q_ASSERT(false);
}
_appendStatusLog(tr("Error: %1").arg(errorString));
_cancel();
}
/// @brief Updates the progress bar from long running bootloader commands
void PX4FirmwareUpgrade::_updateProgress(int curr, int total)
void FirmwareUpgradeController::_updateProgress(int curr, int total)
{
_ui->progressBar->setValue((curr*100) / total);
// FIXME: NYI
Q_UNUSED(curr);
Q_UNUSED(total);
// _ui->progressBar->setValue((curr*100) / total);
}
/// @brief Resets the state machine back to the beginning
void PX4FirmwareUpgrade::_restart(void)
void FirmwareUpgradeController::_restart(void)
{
_setupState(upgradeStateBegin);
// FIXME: NYI
//_setupState(upgradeStateBegin);
}
/// @brief Moves the progress bar ahead on tick while erasing the board
void PX4FirmwareUpgrade::_eraseProgressTick(void)
void FirmwareUpgradeController::_eraseProgressTick(void)
{
_eraseTickCount++;
_ui->progressBar->setValue((_eraseTickCount*_eraseTickMsec*100) / _eraseTotalMsec);
// FIXME: NYI
// _ui->progressBar->setValue((_eraseTickCount*_eraseTickMsec*100) / _eraseTotalMsec);
}
void FirmwareUpgradeController::doFirmwareUpgrade(void)
{
Q_ASSERT(_upgradeButton);
_upgradeButton->setEnabled(false);
_findBoard();
}
/// Appends the specified text to the status log area in the ui
void FirmwareUpgradeController::_appendStatusLog(const QString& text)
{
Q_ASSERT(_statusLog);
QVariant returnedValue;
QVariant varText = text;
QMetaObject::invokeMethod(_statusLog,
"append",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, varText));
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
QGroundControl Open Source Ground Control Station
(c) 2009, 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
......@@ -22,43 +22,65 @@
======================================================================*/
/// @file
/// @brief PX4 Firmware Upgrade UI
/// @author Don Gagne <don@thegagnes.com>
#ifndef PX4FirmwareUpgrade_H
#define PX4FirmwareUpgrade_H
#ifndef FirmwareUpgradeController_H
#define FirmwareUpgradeController_H
#include <QWidget>
#include "PX4FirmwareUpgradeThread.h"
#include <QObject>
#include <QUrl>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPixmap>
#include <QQuickItem>
#include "qextserialport.h"
#include <stdint.h>
#include "PX4FirmwareUpgradeThread.h"
#include "ui_PX4FirmwareUpgrade.h"
namespace Ui {
class PX4RCCalibration;
}
class PX4FirmwareUpgrade : public QWidget
// Firmware Upgrade MVC Controller for FirmwareUpgrade.qml.
class FirmwareUpgradeController : public QObject
{
Q_OBJECT
public:
explicit PX4FirmwareUpgrade(QWidget *parent = 0);
~PX4FirmwareUpgrade();
FirmwareUpgradeController(void);
/// Supported firmware types
typedef enum {
StableFirmware,
BetaFirmware,
DeveloperFirmware,
CustomFirmware
} FirmwareType_t;
Q_ENUMS(FirmwareType_t)
/// Firmare type to load
Q_PROPERTY(FirmwareType_t firmwareType READ firmwareType WRITE setFirmwareType)
/// Upgrade push button in UI
Q_PROPERTY(QQuickItem* upgradeButton READ upgradeButton WRITE setUpgradeButton)
/// TextArea for log output
Q_PROPERTY(QQuickItem* statusLog READ statusLog WRITE setStatusLog)
/// Begins the firware upgrade process
Q_INVOKABLE void doFirmwareUpgrade(void);
FirmwareType_t firmwareType(void) { return _firmwareType; }
void setFirmwareType(FirmwareType_t firmwareType) { _firmwareType = firmwareType; }
QQuickItem* upgradeButton(void) { return _upgradeButton; }
void setUpgradeButton(QQuickItem* upgradeButton) { _upgradeButton = upgradeButton; }
QQuickItem* statusLog(void) { return _statusLog; }
void setStatusLog(QQuickItem* statusLog) { _statusLog = statusLog; }
private slots:
void _tryAgainButton(void);
void _cancelButton(void);
void _nextButton(void);
void _firmwareSelected(int index);
void _downloadProgress(qint64 curr, qint64 total);
void _downloadFinished(void);
void _downloadError(QNetworkReply::NetworkError code);
......@@ -73,56 +95,18 @@ private slots:
void _eraseProgressTick(void);
private:
/// @brief The various states that the upgrade process progresses through.
enum upgradeStates {
upgradeStateBegin,
upgradeStateBoardSearch,
upgradeStateBoardNotFound,
upgradeStateBootloaderSearch,
upgradeStateBootloaderNotFound,
upgradeStateBootloaderError,
upgradeStateFirmwareSelect,
upgradeStateFirmwareDownloading,
upgradeStateDownloadFailed,
upgradeStateErasing,
upgradeStateEraseError,
upgradeStateFlashing,
upgradeStateFlashError,
upgradeStateVerifying,
upgradeStateVerifyError,
upgradeStateBoardUpgraded,
upgradeStateMax
};
void _setupState(enum upgradeStates state);
void _updateIndicatorUI(void);
void _findBoard(void);
void _findBootloader(void);
void _cancel(void);
void _cancelFind(void);
void _getFirmwareFile(void);
void _setBoardIcon(int boardID);
void _setFirmwareCombo(int boardID);
void _downloadFirmware(void);
void _cancelDownload(void);
void _erase(void);
typedef void (PX4FirmwareUpgrade::*stateFunc)(void);
struct stateMachineEntry {
enum upgradeStates state; ///< State machine state, used to verify correctness of entry
stateFunc next; ///< Method to call when Next is clicked, NULL for Next not available
stateFunc cancel; ///< Method to call when Cancel is clicked, NULL for Cancel not available
stateFunc tryAgain; ///< Method to call when Try Again is clicked, NULL for Try Again not available
const char* msg; ///< Text message to display to user for this state
};
const struct stateMachineEntry* _getStateMachineEntry(enum upgradeStates state);
enum upgradeStates _upgradeState; ///< Current state of the upgrade state machines
void _appendStatusLog(const QString& text);
QString _portName;
QString _portDescription;
......@@ -154,7 +138,11 @@ private:
static const int _findBoardTimeoutMsec = 30000; ///< Amount of time for user to plug in USB
static const int _findBootloaderTimeoutMsec = 5000; ///< Amount time to look for bootloader
Ui::PX4FirmwareUpgrade* _ui;
FirmwareType_t _firmwareType; ///< Firmware type to load
QQuickItem* _upgradeButton; ///< Upgrade button in ui
QQuickItem* _statusLog; ///< Status log TextArea Qml control
bool _searchingForBoard; ///< true: searching for board, false: search for bootloader
};
#endif // PX4FirmwareUpgrade_H
#endif
......@@ -174,9 +174,13 @@ void PX4FirmwareUpgradeThreadWorker::timeout(void)
void PX4FirmwareUpgradeThreadWorker::sendBootloaderReboot(void)
{
_bootloader->sendBootloaderReboot(_bootloaderPort);
_bootloaderPort->deleteLater();
_bootloaderPort = NULL;
if (_bootloaderPort) {
if (_bootloaderPort->isOpen()) {
_bootloader->sendBootloaderReboot(_bootloaderPort);
}
_bootloaderPort->deleteLater();
_bootloaderPort = NULL;
}
}
void PX4FirmwareUpgradeThreadWorker::program(const QString firmwareFilename)
......
......@@ -30,11 +30,11 @@
#include "UASManager.h"
#include "AutoPilotPluginManager.h"
#include "VehicleComponent.h"
#include "PX4FirmwareUpgrade.h"
#include "ParameterEditor.h"
#include "QGCQmlWidgetHolder.h"
#include "MainWindow.h"
#include "QGCMessageBox.h"
#include "FirmwareUpgradeController.h"
#include <QQmlError>
#include <QQmlContext>
......@@ -54,13 +54,13 @@ SetupView::SetupView(QWidget* parent) :
Q_UNUSED(fSucceeded);
Q_ASSERT(fSucceeded);
//setResizeMode(SizeRootObjectToView);
_ui->buttonHolder->setAutoPilot(NULL);
_ui->buttonHolder->setSource(QUrl::fromUserInput("qrc:/qml/SetupViewButtons.qml"));
_ui->buttonHolder->rootContext()->setContextProperty("controller", this);
qmlRegisterType<FirmwareUpgradeController>("QGroundControl.FirmwareUpgradeController", 1, 0, "FirmwareUpgradeController");
_setActiveUAS(UASManager::instance()->getActiveUAS());
}
......@@ -120,16 +120,11 @@ void SetupView::firmwareButtonClicked(void)
return;
}
#if 1
PX4FirmwareUpgrade* setup = new PX4FirmwareUpgrade(this);
#else
// NYI
QGCQmlWidgetHolder* setup = new QGCQmlWidgetHolder;
Q_CHECK_PTR(setup);
//setup->setAutoPilot(_autoPilotPlugin);
setup->setSource(QUrl::fromUserInput("qrc:/qml/FirmwareUpgrade.qml"));
#endif
_changeSetupWidget(setup);
}
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PX4FirmwareUpgrade</class>
<widget class="QWidget" name="PX4FirmwareUpgrade">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>727</width>
<height>527</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>727</width>
<height>527</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="windowOpacity">
<double>1.000000000000000</double>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>726</width>
<height>525</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" rowstretch="0" columnstretch="0,0">
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="boardFoundCheck">
<property name="text">
<string>Board found</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="port">
<property name="text">
<string>Port</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="description">
<property name="text">
<string>Description</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="bootloaderFoundCheck">
<property name="text">
<string>Bootloader found</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="bootloaderVersion">
<property name="text">
<string>Bootloader Version</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="boardID">
<property name="text">
<string>Board ID</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="icon">
<property name="minimumSize">
<size>
<width>200</width>
<height>100</height>
</size>
</property>
<property name="text">
<string>Icon</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="selectFirmwareCheck">
<property name="text">
<string>Select Firmware</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="firmwareCombo"/>
</item>
<item>
<widget class="QCheckBox" name="firmwareDownloadedCheck">
<property name="text">
<string>Firmware downloaded</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="boardUpgradedCheck">
<property name="text">
<string>Board upgraded</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="statusLog">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>180</height>
</size>
</property>
<property name="text">
<string>Status log</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>16</height>
</size>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="tryAgain">
<property name="text">
<string>Try Again</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="skip">
<property name="text">
<string>Skip</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="next">
<property name="text">
<string>Next</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>60</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment