Commit f8ca385d authored by Don Gagne's avatar Don Gagne

Show APM firmware versions when flashing

parent 45e47189
......@@ -262,6 +262,7 @@ HEADERS += \
src/QGCComboBox.h \
src/QGCConfig.h \
src/QGCDockWidget.h \
src/QGCFileDownload.h \
src/QGCGeo.h \
src/QGCLoggingCategory.h \
src/QGCMapPalette.h \
......@@ -382,6 +383,7 @@ SOURCES += \
src/QGCApplication.cc \
src/QGCComboBox.cc \
src/QGCDockWidget.cc \
src/QGCFileDownload.cc \
src/QGCLoggingCategory.cc \
src/QGCMapPalette.cc \
src/QGCPalette.cc \
......
......@@ -164,7 +164,7 @@ QGCView {
var firmwareType = firmwareVersionCombo.model.get(firmwareVersionCombo.currentIndex).firmwareType
var vehicleType = FirmwareUpgradeController.DefaultVehicleFirmware
if (apmFlightStack.checked) {
vehicleType = vehicleTypeSelectionCombo.model.get(vehicleTypeSelectionCombo.currentIndex).vehicleType
vehicleType = controller.vehicleTypeFromVersionIndex(vehicleTypeSelectionCombo.currentIndex)
}
controller.flash(stack, firmwareType, vehicleType)
}
......@@ -199,47 +199,6 @@ QGCView {
}
}
ListModel {
id: vehicleTypeList
ListElement {
text: "Quad"
vehicleType: FirmwareUpgradeController.QuadFirmware
}
ListElement {
text: "X8"
vehicleType: FirmwareUpgradeController.X8Firmware
}
ListElement {
text: "Hexa"
vehicleType: FirmwareUpgradeController.HexaFirmware
}
ListElement {
text: "Octo"
vehicleType: FirmwareUpgradeController.OctoFirmware
}
ListElement {
text: "Y"
vehicleType: FirmwareUpgradeController.YFirmware
}
ListElement {
text: "Y6"
vehicleType: FirmwareUpgradeController.Y6Firmware
}
ListElement {
text: "Heli"
vehicleType: FirmwareUpgradeController.HeliFirmware
}
ListElement {
text: "Plane"
vehicleType: FirmwareUpgradeController.PlaneFirmware
}
ListElement {
text: "Rover"
vehicleType: FirmwareUpgradeController.RoverFirmware
}
}
ListModel {
id: px4FlowTypeList
......@@ -274,17 +233,6 @@ QGCView {
firmwareVersionCombo.currentIndex = 0
}
function vehicleTypeChanged(model) {
vehicleTypeSelectionCombo.model = null
// All of this bizarre, setting model to null and index to 1 and then to 0 is to work around
// strangeness in the combo box implementation. This sequence of steps correctly changes the combo model
// without generating any warnings and correctly updates the combo text with the new selection.
vehicleTypeSelectionCombo.model = null
vehicleTypeSelectionCombo.model = model
vehicleTypeSelectionCombo.currentIndex = 1
vehicleTypeSelectionCombo.currentIndex = 0
}
QGCRadioButton {
id: px4FlightStack
checked: true
......@@ -301,10 +249,7 @@ QGCView {
text: "APM Flight Stack"
visible: !px4Flow
onClicked: {
parent.firmwareVersionChanged(firmwareTypeList)
parent.vehicleTypeChanged(vehicleTypeList)
}
onClicked: parent.firmwareVersionChanged(firmwareTypeList)
}
QGCLabel {
......@@ -317,19 +262,21 @@ QGCView {
Row {
spacing: 10
QGCComboBox {
id: firmwareVersionCombo
width: 200
visible: showFirmwareTypeSelection
model: px4Flow ? px4FlowTypeList : firmwareTypeList
id: firmwareVersionCombo
width: 200
visible: showFirmwareTypeSelection
model: px4Flow ? px4FlowTypeList : firmwareTypeList
currentIndex: controller.selectedFirmwareType
onActivated: {
if (model.get(index).firmwareType == FirmwareUpgradeController.PX4BetaFirmware || FirmwareUpgradeController.APMBetaFirmware ) {
controller.selectedFirmwareType = index
if (model.get(index).firmwareType == FirmwareUpgradeController.BetaFirmware) {
firmwareVersionWarningLabel.visible = true
firmwareVersionWarningLabel.text = "WARNING: BETA FIRMWARE. " +
"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."
} else if (model.get(index).firmwareType == FirmwareUpgradeController.PX4DeveloperFirmware || FirmwareUpgradeController.APMDeveloperFirmware) {
} else if (model.get(index).firmwareType == FirmwareUpgradeController.DeveloperFirmware) {
firmwareVersionWarningLabel.visible = true
firmwareVersionWarningLabel.text = "WARNING: CONTINUOUS BUILD FIRMWARE. " +
"This firmware has NOT BEEN FLIGHT TESTED. " +
......@@ -347,7 +294,7 @@ QGCView {
id: vehicleTypeSelectionCombo
width: 200
visible: apmFlightStack.checked
model: vehicleTypeList
model: controller.apmAvailableVersions
}
}
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
......@@ -29,6 +29,7 @@
#include "Bootloader.h"
#include "QGCFileDialog.h"
#include "QGCApplication.h"
#include "QGCFileDownload.h"
struct FirmwareToUrlElement_t {
FirmwareUpgradeController::AutoPilotStackType_t stackType;
......@@ -45,11 +46,12 @@ uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareId)
}
/// @Brief Constructs a new FirmwareUpgradeController Widget. This widget is used within the PX4VehicleConfig set of screens.
FirmwareUpgradeController::FirmwareUpgradeController(void) :
_downloadManager(NULL),
_downloadNetworkReply(NULL),
_statusLog(NULL),
_image(NULL)
FirmwareUpgradeController::FirmwareUpgradeController(void)
: _downloadManager(NULL)
, _downloadNetworkReply(NULL)
, _statusLog(NULL)
, _selectedFirmwareType(StableFirmware)
, _image(NULL)
{
_threadController = new PX4FirmwareUpgradeThreadController(this);
Q_CHECK_PTR(_threadController);
......@@ -68,6 +70,8 @@ FirmwareUpgradeController::FirmwareUpgradeController(void) :
connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress, this, &FirmwareUpgradeController::_updateProgress);
connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick);
_initFirmwareHash();
}
FirmwareUpgradeController::~FirmwareUpgradeController()
......@@ -115,42 +119,45 @@ void FirmwareUpgradeController::cancel(void)
_threadController->cancel();
}
void FirmwareUpgradeController::_foundBoard(bool firstAttempt, const QSerialPortInfo& info, int type)
void FirmwareUpgradeController::_foundBoard(bool firstAttempt, const QSerialPortInfo& info, int boardType)
{
_foundBoardInfo = info;
switch (type) {
case QGCSerialPortInfo::BoardTypePX4FMUV1:
_foundBoardType = "PX4 FMU V1";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypePX4FMUV2:
case QGCSerialPortInfo::BoardTypePX4FMUV4:
_foundBoardType = "Pixhawk";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypeAeroCore:
_foundBoardType = "AeroCore";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypePX4Flow:
_foundBoardType = "PX4 Flow";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardType3drRadio:
_foundBoardType = "3DR Radio";
if (!firstAttempt) {
// Radio always flashes latest firmware, so we can start right away without
// any further user input.
_startFlashWhenBootloaderFound = true;
_startFlashWhenBootloaderFoundFirmwareIdentity = FirmwareIdentifier(ThreeDRRadio,
StableFirmware,
DefaultVehicleFirmware);
}
break;
_foundBoardType = (QGCSerialPortInfo::BoardType_t)boardType;
switch (boardType) {
case QGCSerialPortInfo::BoardTypePX4FMUV1:
_foundBoardTypeName = "PX4 FMU V1";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypePX4FMUV2:
case QGCSerialPortInfo::BoardTypePX4FMUV4:
_foundBoardTypeName = "Pixhawk";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypeAeroCore:
_foundBoardTypeName = "AeroCore";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardTypePX4Flow:
_foundBoardTypeName = "PX4 Flow";
_startFlashWhenBootloaderFound = false;
break;
case QGCSerialPortInfo::BoardType3drRadio:
_foundBoardTypeName = "3DR Radio";
if (!firstAttempt) {
// Radio always flashes latest firmware, so we can start right away without
// any further user input.
_startFlashWhenBootloaderFound = true;
_startFlashWhenBootloaderFoundFirmwareIdentity = FirmwareIdentifier(ThreeDRRadio,
StableFirmware,
DefaultVehicleFirmware);
}
break;
}
qCDebug(FirmwareUpgradeLog) << _foundBoardType;
emit boardFound();
_loadAPMVersions(_foundBoardType);
}
......@@ -334,46 +341,65 @@ void FirmwareUpgradeController::_bootloaderSyncFailed(void)
_errorCancel("Unable to sync with bootloader.");
}
/// @brief Prompts the user to select a firmware file if needed and moves the state machine to the next state.
void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareId)
QHash<FirmwareUpgradeController::FirmwareIdentifier, QString>* FirmwareUpgradeController::_firmwareHashForBoardId(int boardId)
{
// make sure the firmware hashes are populated
_initFirmwareHash();
// Select the firmware set based on board type
QHash<FirmwareIdentifier, QString> prgFirmware;
switch (_bootloaderBoardID) {
case Bootloader::boardIDPX4FMUV1:
prgFirmware = _rgPX4FMUV1Firmware;
break;
case Bootloader::boardIDPX4Flow:
prgFirmware = _rgPX4FLowFirmware;
break;
case Bootloader::boardIDPX4FMUV2:
prgFirmware = _rgPX4FMUV2Firmware;
break;
switch (boardId) {
case Bootloader::boardIDPX4FMUV1:
return &_rgPX4FMUV1Firmware;
case Bootloader::boardIDPX4Flow:
return &_rgPX4FLowFirmware;
case Bootloader::boardIDPX4FMUV2:
return &_rgPX4FMUV2Firmware;
case Bootloader::boardIDPX4FMUV4:
return &_rgPX4FMUV4Firmware;
case Bootloader::boardIDAeroCore:
return &_rgAeroCoreFirmware;
case Bootloader::boardID3DRRadio:
return &_rg3DRRadioFirmware;
default:
return NULL;
}
}
case Bootloader::boardIDPX4FMUV4:
prgFirmware = _rgPX4FMUV4Firmware;
break;
case Bootloader::boardIDAeroCore:
prgFirmware = _rgAeroCoreFirmware;
break;
case Bootloader::boardID3DRRadio:
prgFirmware = _rg3DRRadioFirmware;
break;
default:
break;
QHash<FirmwareUpgradeController::FirmwareIdentifier, QString>* FirmwareUpgradeController::_firmwareHashForBoardType(QGCSerialPortInfo::BoardType_t boardType)
{
int boardId;
switch (boardType) {
case QGCSerialPortInfo::BoardTypePX4FMUV1:
boardId = Bootloader::boardIDPX4FMUV1;
break;
case QGCSerialPortInfo::BoardTypePX4FMUV2:
boardId = Bootloader::boardIDPX4FMUV2;
break;
case QGCSerialPortInfo::BoardTypePX4FMUV4:
boardId = Bootloader::boardIDPX4FMUV4;
break;
case QGCSerialPortInfo::BoardTypeAeroCore:
boardId = Bootloader::boardIDAeroCore;
break;
case QGCSerialPortInfo::BoardTypePX4Flow:
boardId = Bootloader::boardIDPX4Flow;
break;
case QGCSerialPortInfo::BoardType3drRadio:
boardId = Bootloader::boardID3DRRadio;
break;
case QGCSerialPortInfo::BoardTypeUnknown:
qWarning() << "Internal error";
boardId = Bootloader::boardIDPX4FMUV2;
break;
}
return _firmwareHashForBoardId(boardId);
}
/// @brief Prompts the user to select a firmware file if needed and moves the state machine to the next state.
void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareId)
{
QHash<FirmwareIdentifier, QString>* prgFirmware = _firmwareHashForBoardId(_bootloaderBoardID);
if (prgFirmware.isEmpty() && firmwareId.firmwareType != CustomFirmware) {
if (!prgFirmware && firmwareId.firmwareType != CustomFirmware) {
_errorCancel("Attempting to flash an unknown board type, you must select 'Custom firmware file'");
return;
}
......@@ -385,8 +411,8 @@ void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareId)
"Firmware Files (*.px4 *.bin *.ihx)"); // File filter
} else {
if (prgFirmware.contains(firmwareId)) {
_firmwareFilename = prgFirmware.value(firmwareId);
if (prgFirmware->contains(firmwareId)) {
_firmwareFilename = prgFirmware->value(firmwareId);
} else {
_errorCancel("Unable to find specified firmware download location");
return;
......@@ -609,3 +635,123 @@ void FirmwareUpgradeController::_eraseComplete(void)
{
_eraseTimer.stop();
}
void FirmwareUpgradeController::_loadAPMVersions(QGCSerialPortInfo::BoardType_t boardType)
{
_apmVersionMap.clear();
QHash<FirmwareIdentifier, QString>* prgFirmware = _firmwareHashForBoardType(boardType);
foreach (FirmwareIdentifier firmwareId, prgFirmware->keys()) {
if (firmwareId.autopilotStackType == AutoPilotStackAPM) {
QString versionFile = QFileInfo(prgFirmware->value(firmwareId)).path() + "/git-version.txt";
qCDebug(FirmwareUpgradeLog) << "Downloading" << versionFile;
QGCFileDownload* downloader = new QGCFileDownload(this);
connect(downloader, &QGCFileDownload::downloadFinished, this, &FirmwareUpgradeController::_apmVersionDownloadFinished);
downloader->download(versionFile);
}
}
}
void FirmwareUpgradeController::_apmVersionDownloadFinished(QString remoteFile, QString localFile)
{
qCDebug(FirmwareUpgradeLog) << "Download complete" << remoteFile << localFile;
// Now read the version file and pull out the version string
QFile versionFile(localFile);
versionFile.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream stream(&versionFile);
QString versionContents = stream.readAll();
QString version;
QRegularExpression re("APMVERSION: (.*)$");
QRegularExpressionMatch match = re.match(versionContents);
if (match.hasMatch()) {
version = match.captured(1);
}
if (version.isEmpty()) {
qWarning() << "Unable to parse version info from file" << remoteFile;
return;
}
// In order to determine the firmware and vehicle type for this file we find the matching entry in the firmware list
QHash<FirmwareIdentifier, QString>* prgFirmware = _firmwareHashForBoardType(_foundBoardType);
QString remotePath = QFileInfo(remoteFile).path();
foreach (FirmwareIdentifier firmwareId, prgFirmware->keys()) {
if (remotePath == QFileInfo((*prgFirmware)[firmwareId]).path()) {
qCDebug(FirmwareUpgradeLog) << "Adding version to map, version:firwmareType:vehicleType" << version << firmwareId.firmwareType << firmwareId.firmwareVehicleType;
_apmVersionMap[firmwareId.firmwareType][firmwareId.firmwareVehicleType] = version;
}
}
emit apmAvailableVersionsChanged();
}
void FirmwareUpgradeController::setSelectedFirmwareType(FirmwareType_t firmwareType)
{
_selectedFirmwareType = firmwareType;
emit selectedFirmwareTypeChanged(_selectedFirmwareType);
emit apmAvailableVersionsChanged();
}
QStringList FirmwareUpgradeController::apmAvailableVersions(void)
{
QStringList list;
_apmVehicleTypeFromCurrentVersionList.clear();
foreach (FirmwareVehicleType_t vehicleType, _apmVersionMap[_selectedFirmwareType].keys()) {
QString version;
switch (vehicleType) {
case QuadFirmware:
version = "Quad - ";
break;
case X8Firmware:
version = "X8 - ";
break;
case HexaFirmware:
version = "Hexa - ";
break;
case OctoFirmware:
version = "Octo - ";
break;
case YFirmware:
version = "Y - ";
break;
case Y6Firmware:
version = "Y6 - ";
break;
case HeliFirmware:
version = "Heli - ";
break;
case PlaneFirmware:
case RoverFirmware:
case DefaultVehicleFirmware:
break;
}
version += _apmVersionMap[_selectedFirmwareType][vehicleType];
_apmVehicleTypeFromCurrentVersionList.append(vehicleType);
list << version;
}
return list;
}
FirmwareUpgradeController::FirmwareVehicleType_t FirmwareUpgradeController::vehicleTypeFromVersionIndex(int index)
{
if (index < 0 || index >= _apmVehicleTypeFromCurrentVersionList.count()) {
qWarning() << "Invalid index, index:count" << index << _apmVehicleTypeFromCurrentVersionList.count();
return QuadFirmware;
}
return _apmVehicleTypeFromCurrentVersionList[index];
}
......@@ -106,10 +106,12 @@ public:
FirmwareUpgradeController(void);
~FirmwareUpgradeController();
Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound)
Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound)
Q_PROPERTY(QString boardType MEMBER _foundBoardType NOTIFY boardFound)
Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound)
Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound)
Q_PROPERTY(QString boardType MEMBER _foundBoardTypeName NOTIFY boardFound)
Q_PROPERTY(FirmwareType_t selectedFirmwareType READ selectedFirmwareType WRITE setSelectedFirmwareType NOTIFY selectedFirmwareTypeChanged)
Q_PROPERTY(QStringList apmAvailableVersions READ apmAvailableVersions NOTIFY apmAvailableVersionsChanged)
/// TextArea for log output
Q_PROPERTY(QQuickItem* statusLog READ statusLog WRITE setStatusLog)
......@@ -126,6 +128,8 @@ public:
Q_INVOKABLE void flash(AutoPilotStackType_t stackType,
FirmwareType_t firmwareType = StableFirmware,
FirmwareVehicleType_t vehicleType = DefaultVehicleFirmware );
Q_INVOKABLE FirmwareVehicleType_t vehicleTypeFromVersionIndex(int index);
// overload, not exposed to qml side
void flash(const FirmwareIdentifier& firmwareId);
......@@ -140,6 +144,11 @@ public:
QString boardPort(void) { return _foundBoardInfo.portName(); }
QString boardDescription(void) { return _foundBoardInfo.description(); }
FirmwareType_t selectedFirmwareType(void) { return _selectedFirmwareType; }
void setSelectedFirmwareType(FirmwareType_t firmwareType);
QStringList apmAvailableVersions(void);
signals:
void boardFound(void);
......@@ -148,12 +157,14 @@ signals:
void flashComplete(void);
void flashCancelled(void);
void error(void);
void selectedFirmwareTypeChanged(FirmwareType_t firmwareType);
void apmAvailableVersionsChanged(void);
private slots:
void _downloadProgress(qint64 curr, qint64 total);
void _downloadFinished(void);
void _downloadError(QNetworkReply::NetworkError code);
void _foundBoard(bool firstAttempt, const QSerialPortInfo& portInfo, int type);
void _foundBoard(bool firstAttempt, const QSerialPortInfo& portInfo, int boardType);
void _noBoardFound(void);
void _boardGone();
void _foundBootloader(int bootloaderVersion, int boardID, int flashSize);
......@@ -165,6 +176,7 @@ private slots:
void _eraseStarted(void);
void _eraseComplete(void);
void _eraseProgressTick(void);
void _apmVersionDownloadFinished(QString remoteFile, QString localFile);
private:
void _getFirmwareFile(FirmwareIdentifier firmwareId);
......@@ -172,7 +184,10 @@ private:
void _downloadFirmware(void);
void _appendStatusLog(const QString& text, bool critical = false);
void _errorCancel(const QString& msg);
void _loadAPMVersions(QGCSerialPortInfo::BoardType_t boardType);
QHash<FirmwareIdentifier, QString>* _firmwareHashForBoardId(int boardId);
QHash<FirmwareIdentifier, QString>* _firmwareHashForBoardType(QGCSerialPortInfo::BoardType_t boardType);
QString _portName;
QString _portDescription;
......@@ -184,6 +199,9 @@ private:
QHash<FirmwareIdentifier, QString> _rgPX4FLowFirmware;
QHash<FirmwareIdentifier, QString> _rg3DRRadioFirmware;
QMap<FirmwareType_t, QMap<FirmwareVehicleType_t, QString> > _apmVersionMap;
QList<FirmwareVehicleType_t> _apmVehicleTypeFromCurrentVersionList;
/// Information which comes back from the bootloader
bool _bootloaderFound; ///< true: we have received the foundBootloader signals
uint32_t _bootloaderVersion; ///< Bootloader version
......@@ -216,9 +234,12 @@ private:
bool _searchingForBoard; ///< true: searching for board, false: search for bootloader
QSerialPortInfo _foundBoardInfo;
QString _foundBoardType;
QSerialPortInfo _foundBoardInfo;
QGCSerialPortInfo::BoardType_t _foundBoardType;
QString _foundBoardTypeName;
FirmwareType_t _selectedFirmwareType;
FirmwareImage* _image;
};
......
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