From fb3610d4bf1be148b472d3a3a1a978d80f293f96 Mon Sep 17 00:00:00 2001
From: Pritam Ghanghas <pritam.ghanghas@gmail.com>
Date: Wed, 16 Sep 2015 04:08:29 +0530
Subject: [PATCH] Added support for flashing beta and developer versions of APM
 stack

---
 src/VehicleSetup/FirmwareUpgrade.qml          | 150 +++---
 src/VehicleSetup/FirmwareUpgradeController.cc | 448 +++++++++++++++---
 src/VehicleSetup/FirmwareUpgradeController.h  |  94 ++--
 3 files changed, 527 insertions(+), 165 deletions(-)

diff --git a/src/VehicleSetup/FirmwareUpgrade.qml b/src/VehicleSetup/FirmwareUpgrade.qml
index 2d2fd779bc..4cf2f597f7 100644
--- a/src/VehicleSetup/FirmwareUpgrade.qml
+++ b/src/VehicleSetup/FirmwareUpgrade.qml
@@ -139,12 +139,18 @@ QGCView {
         QGCViewDialog {
             anchors.fill: parent
  
-            property bool showVersionSelection: apmFlightStack.checked || advancedMode.checked
+            property bool showFirmwareTypeSelection: apmFlightStack.checked || advancedMode.checked
             property bool px4Flow:              controller.boardType == "PX4 Flow"
 
             function accept() {
                 hideDialog()
-                controller.flash(firmwareVersionCombo.model.get(firmwareVersionCombo.currentIndex).firmwareType)
+                var stack = apmFlightStack.checked ? FirmwareUpgradeController.AutoPilotStackAPM : FirmwareUpgradeController.AutoPilotStackPX4
+                var firmwareType = firmwareVersionCombo.model.get(firmwareVersionCombo.currentIndex).firmwareType
+                var vehicleType = FirmwareUpgradeController.DefaultVehicleFirmware
+                if (apmFlightStack.checked) {
+                    vehicleType = vehicleTypeSelectionCombo.model.get(vehicleTypeSelectionCombo.currentIndex).vehicleType
+                }
+                controller.flash(stack, firmwareType, vehicleType)
             }
  
             function reject() {
@@ -157,64 +163,68 @@ QGCView {
             }
  
             ListModel {
-                id: px4FirmwareTypeList
+                id: firmwareTypeList
 
                 ListElement {
                     text:           "Standard Version (stable)";
-                    firmwareType:   FirmwareUpgradeController.PX4StableFirmware
+                    firmwareType:   FirmwareUpgradeController.StableFirmware
                 }
                 ListElement {
                     text:           "Beta Testing (beta)";
-                    firmwareType:   FirmwareUpgradeController.PX4BetaFirmware
+                    firmwareType:   FirmwareUpgradeController.BetaFirmware
                 }
                 ListElement {
                     text:           "Developer Build (master)";
-                    firmwareType:   FirmwareUpgradeController.PX4DeveloperFirmware
+                    firmwareType:   FirmwareUpgradeController.DeveloperFirmware
                 }
                 ListElement {
                     text:           "Custom firmware file...";
-                    firmwareType:   FirmwareUpgradeController.PX4CustomFirmware
+                    firmwareType:   FirmwareUpgradeController.CustomFirmware
                  }
             }
  
             ListModel {
-                id: apmFirmwareTypeList
+                id: vehicleTypeList
 
                 ListElement {
-                    text: "ArduCopter Quad"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterQuadFirmware
+                    text: "Default (Quad)"
+                    vehicleType: FirmwareUpgradeController.DefaultVehicleFirmware
+                }
+                ListElement {
+                    text: "Quad"
+                    vehicleType: FirmwareUpgradeController.QuadFirmware
                 }
                 ListElement {
-                    text: "ArduCopter X8"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterX8Firmware
+                    text: "X8"
+                    vehicleType: FirmwareUpgradeController.X8Firmware
                 }
                 ListElement {
-                    text: "ArduCopter Hexa"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterHexaFirmware
+                    text: "Hexa"
+                    vehicleType: FirmwareUpgradeController.HexaFirmware
                 }
                 ListElement {
-                    text: "ArduCopter Octo"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterOctoFirmware
+                    text: "Octo"
+                    vehicleType: FirmwareUpgradeController.OctoFirmware
                 }
                 ListElement {
-                    text: "ArduCopter Y"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterYFirmware
+                    text: "Y"
+                    vehicleType: FirmwareUpgradeController.YFirmware
                 }
                 ListElement {
-                    text: "ArduCopter Y6"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterY6Firmware
+                    text: "Y6"
+                    vehicleType: FirmwareUpgradeController.Y6Firmware
                 }
                 ListElement {
-                    text: "ArduCopter Heli"
-                    firmwareType: FirmwareUpgradeController.ApmArduCopterHeliFirmware
+                    text: "Heli"
+                    vehicleType: FirmwareUpgradeController.HeliFirmware
                 }
                 ListElement {
-                    text: "ArduPlane"
-                    firmwareType: FirmwareUpgradeController.ApmArduPlaneFirmware
+                    text: "Plane"
+                    vehicleType: FirmwareUpgradeController.PlaneFirmware
                 }
                 ListElement {
                     text: "Rover"
-                    firmwareType: FirmwareUpgradeController.ApmRoverFirmware
+                    vehicleType: FirmwareUpgradeController.RoverFirmware
                 }
             }
 
@@ -223,11 +233,11 @@ QGCView {
 
                 ListElement {
                     text:           "Standard Version (stable)";
-                    firmwareType:   FirmwareUpgradeController.PX4StableFirmware
+                    firmwareType:   FirmwareUpgradeController.StableFirmware
                 }
                 ListElement {
                     text:           "Custom firmware file...";
-                    firmwareType:   FirmwareUpgradeController.PX4CustomFirmware
+                    firmwareType:   FirmwareUpgradeController.CustomFirmware
                  }
             }
  
@@ -252,6 +262,17 @@ 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
@@ -259,7 +280,7 @@ QGCView {
                     text:           "PX4 Flight Stack (full QGC support)"
                     visible:        !px4Flow
 
-                    onClicked: parent.firmwareVersionChanged(px4FirmwareTypeList)
+                    onClicked: parent.firmwareVersionChanged(firmwareTypeList)
                 }
 
                 QGCRadioButton {
@@ -268,42 +289,55 @@ QGCView {
                     text:           "APM Flight Stack (partial QGC support)"
                     visible:        !px4Flow
 
-                    onClicked: parent.firmwareVersionChanged(apmFirmwareTypeList)
+                    onClicked: {
+                        parent.firmwareVersionChanged(firmwareTypeList)
+                        parent.vehicleTypeChanged(vehicleTypeList)
+                    }
                 }
- 
+
                 QGCLabel {
                     width:      parent.width
                     wrapMode:   Text.WordWrap
-                    visible:    showVersionSelection
+                    visible:    showFirmwareTypeSelection
                     text:       px4Flow ? "Select which version of the firmware you would like to install:" : "Select which version of the above flight stack you would like to install:"
                 }
 
-                QGCComboBox {
-                    id:         firmwareVersionCombo
-                    width:      200
-                    visible:    showVersionSelection
-                    model:      px4Flow ? px4FlowTypeList : px4FirmwareTypeList
-
-                    onActivated: {
-                        if (model.get(index).firmwareType == FirmwareUpgradeController.PX4BetaFirmware) {
-                            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) {
-                            firmwareVersionWarningLabel.visible = true
-                            firmwareVersionWarningLabel.text = "WARNING: CONTINUOUS BUILD FIRMWARE. " +
-                                                                    "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."
-                         } else {
-                            firmwareVersionWarningLabel.visible = false
+                Row {
+                    spacing: 10
+                    QGCComboBox {
+                        id:         firmwareVersionCombo
+                        width:      200
+                        visible:    showFirmwareTypeSelection
+                        model:      px4Flow ? px4FlowTypeList : firmwareTypeList
+
+                        onActivated: {
+                            if (model.get(index).firmwareType == FirmwareUpgradeController.PX4BetaFirmware || FirmwareUpgradeController.APMBetaFirmware ) {
+                                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) {
+                                firmwareVersionWarningLabel.visible = true
+                                firmwareVersionWarningLabel.text = "WARNING: CONTINUOUS BUILD FIRMWARE. " +
+                                        "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."
+                            } else {
+                                firmwareVersionWarningLabel.visible = false
+                            }
                         }
-                     }
-                 }
+                    }
+
+                    QGCComboBox {
+                        id:         vehicleTypeSelectionCombo
+                        width:      200
+                        visible:    apmFlightStack.checked
+                        model:      vehicleTypeList
+                    }
+                }
 
                 QGCLabel {
                     id:         firmwareVersionWarningLabel
@@ -311,8 +345,8 @@ QGCView {
                     wrapMode:   Text.WordWrap
                     visible:    false
                 }
-             }
- 
+            }
+
             QGCCheckBox {
                 id:             advancedMode
                 anchors.bottom: parent.bottom
diff --git a/src/VehicleSetup/FirmwareUpgradeController.cc b/src/VehicleSetup/FirmwareUpgradeController.cc
index 515d8b49a1..f25dc55852 100644
--- a/src/VehicleSetup/FirmwareUpgradeController.cc
+++ b/src/VehicleSetup/FirmwareUpgradeController.cc
@@ -30,6 +30,13 @@
 #include "QGCFileDialog.h"
 #include "QGCMessageBox.h"
 
+uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareIDTrinity)
+{
+    return ( firmwareIDTrinity.autopilotStackType |
+             (firmwareIDTrinity.firmwareType << 8) |
+             (firmwareIDTrinity.firmwareVehicleType << 16) );
+}
+
 /// @Brief Constructs a new FirmwareUpgradeController Widget. This widget is used within the PX4VehicleConfig set of screens.
 FirmwareUpgradeController::FirmwareUpgradeController(void) :
     _downloadManager(NULL),
@@ -65,17 +72,25 @@ void FirmwareUpgradeController::startBoardSearch(void)
     _threadController->startFindBoardLoop();
 }
 
-void FirmwareUpgradeController::flash(FirmwareType_t firmwareType)
+void FirmwareUpgradeController::flash(AutoPilotStackType_t stackType,
+                                      FirmwareType_t firmwareType,
+                                      FirmwareVehicleType_t vehicleType)
 {
+    FirmwareIdentifier firmwareId = FirmwareIdentifier(stackType, firmwareType, vehicleType);
     if (_bootloaderFound) {
-        _getFirmwareFile(firmwareType);
+        _getFirmwareFile(firmwareId);
     } else {
         // We haven't found the bootloader yet. Need to wait until then to flash
         _startFlashWhenBootloaderFound = true;
-        _startFlashWhenBootloaderFoundFirmwareType = firmwareType;
+        _startFlashWhenBootloaderFoundFirmwareIdentity = firmwareId;
     }
 }
 
+void FirmwareUpgradeController::flash(const FirmwareIdentifier& firmwareId)
+{
+    flash(firmwareId.autopilotStackType, firmwareId.firmwareType, firmwareId.firmwareVehicleType);
+}
+
 void FirmwareUpgradeController::cancel(void)
 {
     _eraseTimer.stop();
@@ -105,10 +120,12 @@ void FirmwareUpgradeController::_foundBoard(bool firstAttempt, const QSerialPort
         case FoundBoard3drRadio:
             _foundBoardType = "3DR Radio";
             if (!firstAttempt) {
-                // Radio always flashes stable firmware, so we can start right away without
+                // Radio always flashes latest firmware, so we can start right away without
                 // any further user input.
                 _startFlashWhenBootloaderFound = true;
-                _startFlashWhenBootloaderFoundFirmwareType = PX4StableFirmware;
+                _startFlashWhenBootloaderFoundFirmwareIdentity = FirmwareIdentifier(PX4Radio,
+                                                                                    StableFirmware,
+                                                                                    DefaultVehicleFirmware);
             }
             break;
     }
@@ -143,7 +160,7 @@ void FirmwareUpgradeController::_foundBootloader(int bootloaderVersion, int boar
     _appendStatusLog(QString("  Flash size: %1").arg(_bootloaderBoardFlashSize));
     
     if (_startFlashWhenBootloaderFound) {
-        flash(_startFlashWhenBootloaderFoundFirmwareType);
+        flash(_startFlashWhenBootloaderFoundFirmwareIdentity);
     }
 }
 
@@ -155,116 +172,389 @@ void FirmwareUpgradeController::_bootloaderSyncFailed(void)
 }
 
 /// @brief Prompts the user to select a firmware file if needed and moves the state machine to the next state.
-void FirmwareUpgradeController::_getFirmwareFile(FirmwareType_t firmwareType)
+void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareIDTrinity)
 {
-    static DownloadLocationByFirmwareType_t rgPX4FMUV2Firmware[] = {
-        { PX4StableFirmware,            "http://px4-travis.s3.amazonaws.com/Firmware/stable/px4fmu-v2_default.px4" },
-        { PX4BetaFirmware,              "http://px4-travis.s3.amazonaws.com/Firmware/beta/px4fmu-v2_default.px4" },
-        { PX4DeveloperFirmware,         "http://px4-travis.s3.amazonaws.com/Firmware/master/px4fmu-v2_default.px4"},
-        { ApmArduCopterQuadFirmware,    "http://firmware.diydrones.com/Copter/stable/PX4-quad/ArduCopter-v2.px4" },
-        { ApmArduCopterX8Firmware,      "http://firmware.diydrones.com/Copter/stable/PX4-octa-quad/ArduCopter-v2.px4" },
-        { ApmArduCopterHexaFirmware,    "http://firmware.diydrones.com/Copter/stable/PX4-hexa/ArduCopter-v2.px4" },
-        { ApmArduCopterOctoFirmware,    "http://firmware.diydrones.com/Copter/stable/PX4-octa/ArduCopter-v2.px4" },
-        { ApmArduCopterYFirmware,       "http://firmware.diydrones.com/Copter/stable/PX4-tri/ArduCopter-v2.px4" },
-        { ApmArduCopterY6Firmware,      "http://firmware.diydrones.com/Copter/stable/PX4-y6/ArduCopter-v2.px4" },
-        { ApmArduCopterHeliFirmware,    "http://firmware.diydrones.com/Copter/stable/PX4-heli/ArduCopter-v2.px4" },
-        { ApmArduPlaneFirmware,         "http://firmware.diydrones.com/Plane/stable/PX4/ArduPlane-v2.px4" },
-        { ApmRoverFirmware,             "http://firmware.diydrones.com/Plane/stable/PX4/APMrover2-v2.px4" },
-    };
-    static const size_t crgPX4FMUV2Firmware = sizeof(rgPX4FMUV2Firmware) / sizeof(rgPX4FMUV2Firmware[0]);
-    
-    static const DownloadLocationByFirmwareType_t rgAeroCoreFirmware[] = {
-        { PX4StableFirmware,    	"http://gumstix-aerocore.s3.amazonaws.com/PX4/stable/aerocore_default.px4" },
-        { PX4BetaFirmware,      	"http://gumstix-aerocore.s3.amazonaws.com/PX4/beta/aerocore_default.px4" },
-        { PX4DeveloperFirmware, 	"http://gumstix-aerocore.s3.amazonaws.com/PX4/master/aerocore_default.px4" },
-        { ApmArduCopterQuadFirmware,    "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-quad/ArduCopter-aerocore.px4" },
-        { ApmArduCopterX8Firmware,      "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-octa-quad/ArduCopter-aerocore.px4" },
-        { ApmArduCopterHexaFirmware,    "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-hexa/ArduCopter-aerocore.px4" },
-        { ApmArduCopterOctoFirmware,    "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-octa/ArduCopter-aerocore.px4" },
-        { ApmArduCopterYFirmware,       "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-tri/ArduCopter-aerocore.px4" },
-        { ApmArduCopterY6Firmware,      "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-y6/ArduCopter-aerocore.px4" },
-        { ApmArduCopterHeliFirmware,    "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-heli/ArduCopter-aerocore.px4" },
-        { ApmArduPlaneFirmware,         "http://gumstix-aerocore.s3.amazonaws.com/APM/Plane/stable/PX4/ArduPlane-aerocore.px4" },
-        { ApmRoverFirmware,             "http://gumstix-aerocore.s3.amazonaws.com/APM/Plane/stable/PX4/APMrover2-aerocore.px4" },
-    };
-    static const size_t crgAeroCoreFirmware = sizeof(rgAeroCoreFirmware) / sizeof(rgAeroCoreFirmware[0]);
-    
-    static const DownloadLocationByFirmwareType_t rgPX4FMUV1Firmware[] = {
-        { PX4StableFirmware,    "http://px4-travis.s3.amazonaws.com/Firmware/stable/px4fmu-v1_default.px4" },
-        { PX4BetaFirmware,      "http://px4-travis.s3.amazonaws.com/Firmware/beta/px4fmu-v1_default.px4" },
-        { PX4DeveloperFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/px4fmu-v1_default.px4" },
-    };
-    static const size_t crgPX4FMUV1Firmware = sizeof(rgPX4FMUV1Firmware) / sizeof(rgPX4FMUV1Firmware[0]);
-    
-    static const DownloadLocationByFirmwareType_t rgPX4FlowFirmware[] = {
-        { PX4StableFirmware, "http://px4-travis.s3.amazonaws.com/Flow/master/px4flow.px4" },
-    };
-    static const size_t crgPX4FlowFirmware = sizeof(rgPX4FlowFirmware) / sizeof(rgPX4FlowFirmware[0]);
-    
-    static const DownloadLocationByFirmwareType_t rg3DRRadioFirmware[] = {
-        { PX4StableFirmware, "http://firmware.diydrones.com/SiK/stable/radio~hm_trp.ihx" },
-    };
-    static const size_t crg3DRRadioFirmware = sizeof(rg3DRRadioFirmware) / sizeof(rg3DRRadioFirmware[0]);
-    
+
+    static QHash<FirmwareIdentifier, QString> rgPX4FMUV2Firmware;
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 StableFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/stable/px4fmu-v2_default.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 BetaFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/beta/px4fmu-v2_default.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 DeveloperFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/master/px4fmu-v2_default.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 QuadFirmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 X8Firmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 HexaFirmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-hexa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 OctoFirmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-octa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 YFirmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-tri/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 Y6Firmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-y6/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 HeliFirmware),
+                              "http://firmware.diydrones.com/Copter/stable/PX4-heli/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 PlaneFirmware),
+                              "http://firmware.diydrones.com/Plane/stable/PX4/ArduPlane-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 RoverFirmware),
+                              "http://firmware.diydrones.com/Rover/stable/PX4/APMrover2-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 QuadFirmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 X8Firmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 HexaFirmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-hexa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 OctoFirmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-octa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 YFirmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-tri/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 Y6Firmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-y6/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 HeliFirmware),
+                              "http://firmware.diydrones.com/Copter/beta/PX4-heli/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 PlaneFirmware),
+                              "http://firmware.diydrones.com/Plane/beta/PX4/ArduPlane-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 RoverFirmware),
+                              "http://firmware.diydrones.com/Rover/beta/PX4/APMrover2-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 QuadFirmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 X8Firmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 HexaFirmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-hexa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 OctoFirmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-octa/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 YFirmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-tri/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 Y6Firmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-y6/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 HeliFirmware),
+                              "http://firmware.diydrones.com/Copter/latest/PX4-heli/ArduCopter-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 PlaneFirmware),
+                              "http://firmware.diydrones.com/Plane/latest/PX4/ArduPlane-v2.px4");
+
+    rgPX4FMUV2Firmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 RoverFirmware),
+                              "http://firmware.diydrones.com/Rover/latest/PX4/APMrover2-v2.px4");
+
+    //////////////////////////////////// PX4MU aerocore firmwares //////////////////////////////////////////////////
+    static QHash<FirmwareIdentifier, QString> rgAeroCoreFirmware;
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 StableFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/PX4/stable/aerocore_default.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 BetaFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/PX4/beta/aerocore_default.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 DeveloperFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/PX4/master/aerocore_default.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 QuadFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/APM/Copter/stable/PX4-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 X8Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 HexaFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-hexa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 OctoFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-octa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 YFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-tri/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 Y6Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-y6/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 HeliFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-heli/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 PlaneFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Plane/stable/PX4/ArduPlane-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 StableFirmware,
+                                                 RoverFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Rover/stable/PX4/APMrover2-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 QuadFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 X8Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 HexaFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-hexa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 OctoFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-octa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 YFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-tri/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 Y6Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-y6/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 HeliFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/beta/PX4-heli/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 PlaneFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Plane/beta/PX4/ArduPlane-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 BetaFirmware,
+                                                 RoverFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Rover/beta/PX4/APMrover2-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 QuadFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 X8Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-octa-quad/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 HexaFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-hexa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 OctoFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-octa/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 YFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-tri/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 Y6Firmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-y6/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 HeliFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-heli/ArduCopter-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 PlaneFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Plane/latest/PX4/ArduPlane-v2.px4");
+
+    rgAeroCoreFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM,
+                                                 DeveloperFirmware,
+                                                 RoverFirmware),
+                              "http://gumstix-aerocore.s3.amazonaws.com/Rover/latest/PX4/APMrover2-v2.px4");
+
+    /////////////////////////////// FMUV1 firmwares ///////////////////////////////////////////
+
+    static QHash<FirmwareIdentifier, QString> rgPX4FMUV1Firmware;
+    rgPX4FMUV1Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 StableFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/latest/px4fmu-v1_default.px4");
+
+    rgPX4FMUV1Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 BetaFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/beta/px4fmu-v1_default.px4");
+
+    rgPX4FMUV1Firmware.insert(FirmwareIdentifier(AutoPilotStackPX4,
+                                                 DeveloperFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://px4-travis.s3.amazonaws.com/Firmware/master/px4fmu-v1_default.px4");
+
+    /////////////////////////////// px4flow firmwares ///////////////////////////////////////
+
+    static QHash<FirmwareIdentifier, QString> rgPX4FLowFirmware;
+    rgPX4FLowFirmware.insert(FirmwareIdentifier(PX4Flow,
+                                                StableFirmware,
+                                                DefaultVehicleFirmware),
+                             "http://px4-travis.s3.amazonaws.com/Flow/master/px4flow.px4");
+
+    /////////////////////////////// 3dr radio firmwares ///////////////////////////////////////
+
+    static QHash<FirmwareIdentifier, QString> rg3DRRadioFirmware;
+    rg3DRRadioFirmware.insert(FirmwareIdentifier(PX4Flow,
+                                                 StableFirmware,
+                                                 DefaultVehicleFirmware),
+                              "http://firmware.diydrones.com/SiK/latest/radio~hm_trp.ihx");
+
     // Select the firmware set based on board type
     
-    const DownloadLocationByFirmwareType_t* prgFirmware;
-    size_t crgFirmware = 0;
+    QHash<FirmwareIdentifier, QString> prgFirmware;
     
     switch (_bootloaderBoardID) {
         case Bootloader::boardIDPX4FMUV1:
             prgFirmware = rgPX4FMUV1Firmware;
-            crgFirmware = crgPX4FMUV1Firmware;
             break;
             
         case Bootloader::boardIDPX4Flow:
-            prgFirmware = rgPX4FlowFirmware;
-            crgFirmware = crgPX4FlowFirmware;
+            prgFirmware = rgPX4FLowFirmware;
             break;
             
         case Bootloader::boardIDPX4FMUV2:
             prgFirmware = rgPX4FMUV2Firmware;
-            crgFirmware = crgPX4FMUV2Firmware;
             break;
             
         case Bootloader::boardIDAeroCore:
             prgFirmware = rgAeroCoreFirmware;
-            crgFirmware = crgAeroCoreFirmware;
             break;
             
         case Bootloader::boardID3DRRadio:
             prgFirmware = rg3DRRadioFirmware;
-            crgFirmware = crg3DRRadioFirmware;
             break;
             
         default:
-            prgFirmware = NULL;
             break;
     }
     
-    if (prgFirmware == NULL && firmwareType != PX4CustomFirmware) {
+    if (prgFirmware.isEmpty() && firmwareIDTrinity.firmwareType != CustomFirmware) {
         _errorCancel("Attempting to flash an unknown board type, you must select 'Custom firmware file'");
         return;
     }
     
-    if (firmwareType == PX4CustomFirmware) {
+    if (firmwareIDTrinity.firmwareType == CustomFirmware) {
         _firmwareFilename = QGCFileDialog::getOpenFileName(NULL,                                                                // Parent to main window
                                                            "Select Firmware File",                                              // Dialog Caption
                                                            QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory
                                                            "Firmware Files (*.px4 *.bin *.ihx)");                               // File filter
     } else {
-        bool found = false;
-        
-        for (size_t i=0; i<crgFirmware; i++) {
-            if (prgFirmware->firmwareType == firmwareType) {
-                found = true;
-                break;
-            }
-            prgFirmware++;
-        }
-        
-        if (found) {
-            _firmwareFilename = prgFirmware->downloadLocation;
+
+        if (prgFirmware.contains(firmwareIDTrinity)) {
+            _firmwareFilename = prgFirmware.value(firmwareIDTrinity);
         } else {
             _errorCancel("Unable to find specified firmware download location");
             return;
diff --git a/src/VehicleSetup/FirmwareUpgradeController.h b/src/VehicleSetup/FirmwareUpgradeController.h
index b9c4dcde20..ea26f0a045 100644
--- a/src/VehicleSetup/FirmwareUpgradeController.h
+++ b/src/VehicleSetup/FirmwareUpgradeController.h
@@ -43,33 +43,68 @@
 
 #include <stdint.h>
 
+/// Supported firmware types. If you modify these you will need to update the qml file as well.
+
 // Firmware Upgrade MVC Controller for FirmwareUpgrade.qml.
 class FirmwareUpgradeController : public QObject
 {
     Q_OBJECT
     
 public:
+        typedef enum {
+            AutoPilotStackPX4,
+            AutoPilotStackAPM,
+            PX4Flow,
+            PX4Radio
+        } AutoPilotStackType_t;
+
+        typedef enum {
+            StableFirmware,
+            BetaFirmware,
+            DeveloperFirmware,
+            CustomFirmware
+        } FirmwareType_t;
+
+        typedef enum {
+            QuadFirmware,
+            X8Firmware,
+            HexaFirmware,
+            OctoFirmware,
+            YFirmware,
+            Y6Firmware,
+            HeliFirmware,
+            PlaneFirmware,
+            RoverFirmware,
+            DefaultVehicleFirmware = QuadFirmware,
+        } FirmwareVehicleType_t;
+
+        Q_ENUMS(AutoPilotStackType_t)
+        Q_ENUMS(FirmwareType_t)
+        Q_ENUMS(FirmwareVehicleType_t)
+
+    class FirmwareIdentifier
+    {
+    public:
+        FirmwareIdentifier(AutoPilotStackType_t stack = AutoPilotStackPX4,
+                           FirmwareType_t firmware = StableFirmware,
+                           FirmwareVehicleType_t vehicle = DefaultVehicleFirmware)
+            : autopilotStackType(stack), firmwareType(firmware), firmwareVehicleType(vehicle) {}
+
+        bool operator==(const FirmwareIdentifier& firmwareIDTrinity) const
+        {
+            return (firmwareIDTrinity.autopilotStackType == autopilotStackType &&
+                    firmwareIDTrinity.firmwareType == firmwareType &&
+                    firmwareIDTrinity.firmwareVehicleType == firmwareVehicleType);
+        }
+
+        // members
+        AutoPilotStackType_t    autopilotStackType;
+        FirmwareType_t          firmwareType;
+        FirmwareVehicleType_t   firmwareVehicleType;
+    };
+
     FirmwareUpgradeController(void);
     
-    /// Supported firmware types. If you modify these you will need to update the qml file as well.
-    typedef enum {
-        PX4StableFirmware,
-        PX4BetaFirmware,
-        PX4DeveloperFirmware,
-        PX4CustomFirmware,
-        ApmArduCopterQuadFirmware,
-        ApmArduCopterX8Firmware,
-        ApmArduCopterHexaFirmware,
-        ApmArduCopterOctoFirmware,
-        ApmArduCopterYFirmware,
-        ApmArduCopterY6Firmware,
-        ApmArduCopterHeliFirmware,
-        ApmArduPlaneFirmware,
-        ApmRoverFirmware,
-    } FirmwareType_t;
-
-    Q_ENUMS(FirmwareType_t)
-    
     Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound)
     Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound)
     Q_PROPERTY(QString boardType MEMBER _foundBoardType NOTIFY boardFound)
@@ -90,8 +125,13 @@ public:
     Q_INVOKABLE void cancel(void);
     
     /// Called when the firmware type has been selected by the user to continue the flash process.
-    Q_INVOKABLE void flash(FirmwareType_t firmwareType);
+    Q_INVOKABLE void flash(AutoPilotStackType_t stackType,
+                           FirmwareType_t firmwareType = StableFirmware,
+                           FirmwareVehicleType_t vehicleType = DefaultVehicleFirmware );
     
+    // overload, not exposed to qml side
+    void flash(const FirmwareIdentifier& firmwareId);
+
     // Property accessors
     
     QQuickItem* progressBar(void) { return _progressBar; }
@@ -133,16 +173,11 @@ private slots:
     void _linkDisconnected(LinkInterface* link);
 
 private:
-    void _getFirmwareFile(FirmwareType_t firmwareType);
+    void _getFirmwareFile(FirmwareIdentifier firmwareIDTrinity);
     void _downloadFirmware(void);
     void _appendStatusLog(const QString& text, bool critical = false);
     void _errorCancel(const QString& msg);
     
-    typedef struct {
-        FirmwareType_t  firmwareType;
-        const char*     downloadLocation;
-    } DownloadLocationByFirmwareType_t;
-    
     QString _portName;
     QString _portDescription;
 
@@ -152,8 +187,8 @@ private:
     uint32_t    _bootloaderBoardID;         ///< Board ID
     uint32_t    _bootloaderBoardFlashSize;  ///< Flash size in bytes of board
     
-    bool            _startFlashWhenBootloaderFound;
-    FirmwareType_t  _startFlashWhenBootloaderFoundFirmwareType;
+    bool                 _startFlashWhenBootloaderFound;
+    FirmwareIdentifier   _startFlashWhenBootloaderFoundFirmwareIdentity;
 
     QPixmap _boardIcon;             ///< Icon used to display image of board
     
@@ -184,4 +219,7 @@ private:
     FirmwareImage*  _image;
 };
 
+// global hashing function
+uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareIDTrinity);
+
 #endif
-- 
GitLab