FirmwareUpgradeController.cc 48.7 KB
Newer Older
huangjian's avatar
huangjian committed
1
/****************************************************************************
2
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
9

10
#include "FirmwareUpgradeController.h"
11
#include "Bootloader.h"
12
#include "QGCApplication.h"
13
#include "QGCFileDownload.h"
14 15
#include "QGCOptions.h"
#include "QGCCorePlugin.h"
16 17
#include "FirmwareUpgradeSettings.h"
#include "SettingsManager.h"
18 19
#include "QGCZlib.h"
#include "JsonHelper.h"
20
#include "LinkManager.h"
Pritam Ghanghas's avatar
Pritam Ghanghas committed
21

Don Gagne's avatar
Don Gagne committed
22 23
#include <QStandardPaths>
#include <QRegularExpression>
Don Gagne's avatar
Don Gagne committed
24 25
#include <QJsonDocument>
#include <QJsonObject>
26
#include <QJsonArray>
27
#include <QNetworkProxy>
Don Gagne's avatar
Don Gagne committed
28

29 30
#include "zlib.h"

31 32 33 34 35 36 37 38 39 40 41 42 43
const char* FirmwareUpgradeController::_manifestFirmwareJsonKey =               "firmware";
const char* FirmwareUpgradeController::_manifestBoardIdJsonKey =                "board_id";
const char* FirmwareUpgradeController::_manifestMavTypeJsonKey =                "mav-type";
const char* FirmwareUpgradeController::_manifestFormatJsonKey =                 "format";
const char* FirmwareUpgradeController::_manifestUrlJsonKey =                    "url";
const char* FirmwareUpgradeController::_manifestMavFirmwareVersionTypeJsonKey = "mav-firmware-version-type";
const char* FirmwareUpgradeController::_manifestUSBIDJsonKey =                  "USBID";
const char* FirmwareUpgradeController::_manifestMavFirmwareVersionJsonKey =     "mav-firmware-version";
const char* FirmwareUpgradeController::_manifestBootloaderStrJsonKey =          "bootloader_str";
const char* FirmwareUpgradeController::_manifestLatestKey =                     "latest";
const char* FirmwareUpgradeController::_manifestPlatformKey =                   "platform";
const char* FirmwareUpgradeController::_manifestBrandNameKey =                  "brand_name";

Pritam Ghanghas's avatar
Pritam Ghanghas committed
44
struct FirmwareToUrlElement_t {
45 46 47 48
    FirmwareUpgradeController::AutoPilotStackType_t     stackType;
    FirmwareUpgradeController::FirmwareBuildType_t      firmwareType;
    FirmwareUpgradeController::FirmwareVehicleType_t    vehicleType;
    QString                                             url;
Pritam Ghanghas's avatar
Pritam Ghanghas committed
49 50
};

51
uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareId)
52
{
53
    return static_cast<uint>(( firmwareId.autopilotStackType |
54 55
                               (firmwareId.firmwareType << 8) |
                               (firmwareId.firmwareVehicleType << 16) ));
56 57
}

58
/// @Brief Constructs a new FirmwareUpgradeController Widget. This widget is used within the PX4VehicleConfig set of screens.
59
FirmwareUpgradeController::FirmwareUpgradeController(void)
60 61
    : _singleFirmwareURL                (qgcApp()->toolbox()->corePlugin()->options()->firmwareUpgradeSingleURL())
    , _singleFirmwareMode               (!_singleFirmwareURL.isEmpty())
62
    , _downloadingFirmwareList          (false)
63 64 65
    , _downloadManager                  (nullptr)
    , _downloadNetworkReply             (nullptr)
    , _statusLog                        (nullptr)
DonLakeFlyer's avatar
DonLakeFlyer committed
66
    , _selectedFirmwareBuildType        (StableFirmware)
67 68
    , _image                            (nullptr)
    , _apmBoardDescriptionReplaceText   ("<APMBoardDescription>")
69 70
    , _apmChibiOSSetting                (qgcApp()->toolbox()->settingsManager()->firmwareUpgradeSettings()->apmChibiOS())
    , _apmVehicleTypeSetting            (qgcApp()->toolbox()->settingsManager()->firmwareUpgradeSettings()->apmVehicleType())
71
{
72 73 74 75 76 77 78 79 80 81
    _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["OFFICIAL"] =  StableFirmware;
    _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["BETA"] =      BetaFirmware;
    _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["DEV"] =       DeveloperFirmware;

    _manifestMavTypeToFirmwareVehicleTypeMap["Copter"] =        CopterFirmware;
    _manifestMavTypeToFirmwareVehicleTypeMap["HELICOPTER"] =    HeliFirmware;
    _manifestMavTypeToFirmwareVehicleTypeMap["FIXED_WING"] =    PlaneFirmware;
    _manifestMavTypeToFirmwareVehicleTypeMap["GROUND_ROVER"] =  RoverFirmware;
    _manifestMavTypeToFirmwareVehicleTypeMap["SUBMARINE"] =     SubFirmware;

82 83 84
    _threadController = new PX4FirmwareUpgradeThreadController(this);
    Q_CHECK_PTR(_threadController);

85 86 87
    connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBoard,             this, &FirmwareUpgradeController::_foundBoard);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::noBoardFound,           this, &FirmwareUpgradeController::_noBoardFound);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::boardGone,              this, &FirmwareUpgradeController::_boardGone);
88
    connect(_threadController, &PX4FirmwareUpgradeThreadController::foundBoardInfo,         this, &FirmwareUpgradeController::_foundBoardInfo);
89 90 91 92 93 94 95 96
    connect(_threadController, &PX4FirmwareUpgradeThreadController::error,                  this, &FirmwareUpgradeController::_error);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress,         this, &FirmwareUpgradeController::_updateProgress);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::status,                 this, &FirmwareUpgradeController::_status);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::eraseStarted,           this, &FirmwareUpgradeController::_eraseStarted);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::eraseComplete,          this, &FirmwareUpgradeController::_eraseComplete);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::flashComplete,          this, &FirmwareUpgradeController::_flashComplete);
    connect(_threadController, &PX4FirmwareUpgradeThreadController::updateProgress,         this, &FirmwareUpgradeController::_updateProgress);
    
97
    connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick);
98

99
#if !defined(NO_ARDUPILOT_DIALECT)
100 101
    connect(_apmChibiOSSetting,     &Fact::rawValueChanged, this, &FirmwareUpgradeController::_buildAPMFirmwareNames);
    connect(_apmVehicleTypeSetting, &Fact::rawValueChanged, this, &FirmwareUpgradeController::_buildAPMFirmwareNames);
102
#endif
103

104
    _initFirmwareHash();
Don Gagne's avatar
Don Gagne committed
105
    _determinePX4StableVersion();
106 107

#if !defined(NO_ARDUPILOT_DIALECT)
108
    _downloadArduPilotManifest();
109
#endif
110 111
}

Don Gagne's avatar
Don Gagne committed
112 113 114 115 116
FirmwareUpgradeController::~FirmwareUpgradeController()
{
    qgcApp()->toolbox()->linkManager()->setConnectionsAllowed();
}

117
void FirmwareUpgradeController::startBoardSearch(void)
118
{
Don Gagne's avatar
Don Gagne committed
119 120 121 122
    LinkManager* linkMgr = qgcApp()->toolbox()->linkManager();

    linkMgr->setConnectionsSuspended(tr("Connect not allowed during Firmware Upgrade."));

123 124
    // FIXME: Why did we get here with active vehicle?
    if (!qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()) {
Don Gagne's avatar
Don Gagne committed
125 126 127
        // We have to disconnect any inactive links
        linkMgr->disconnectAll();
    }
128

129 130 131
    _bootloaderFound = false;
    _startFlashWhenBootloaderFound = false;
    _threadController->startFindBoardLoop();
132 133
}

134
void FirmwareUpgradeController::flash(AutoPilotStackType_t stackType,
135
                                      FirmwareBuildType_t firmwareType,
136
                                      FirmwareVehicleType_t vehicleType)
137
{
138
    qCDebug(FirmwareUpgradeLog) << "_flash stackType:firmwareType:vehicleType" << stackType << firmwareType << vehicleType;
139
    FirmwareIdentifier firmwareId = FirmwareIdentifier(stackType, firmwareType, vehicleType);
140
    if (_bootloaderFound) {
141
        _getFirmwareFile(firmwareId);
142 143 144
    } else {
        // We haven't found the bootloader yet. Need to wait until then to flash
        _startFlashWhenBootloaderFound = true;
145
        _startFlashWhenBootloaderFoundFirmwareIdentity = firmwareId;
146 147 148 149 150 151 152 153 154 155 156 157
        _firmwareFilename.clear();
    }
}

void FirmwareUpgradeController::flashFirmwareUrl(QString firmwareFlashUrl)
{
    _firmwareFilename = firmwareFlashUrl;
    if (_bootloaderFound) {
        _downloadFirmware();
    } else {
        // We haven't found the bootloader yet. Need to wait until then to flash
        _startFlashWhenBootloaderFound = true;
158
    }
159 160
}

161 162 163 164 165
void FirmwareUpgradeController::flash(const FirmwareIdentifier& firmwareId)
{
    flash(firmwareId.autopilotStackType, firmwareId.firmwareType, firmwareId.firmwareVehicleType);
}

166
void FirmwareUpgradeController::flashSingleFirmwareMode(FirmwareBuildType_t firmwareType)
167
{
Gus Grubba's avatar
Gus Grubba committed
168
    flash(SingleFirmwareMode, firmwareType, DefaultVehicleFirmware);
169 170
}

171
void FirmwareUpgradeController::cancel(void)
172
{
173 174 175
    _eraseTimer.stop();
    _threadController->cancel();
}
176

177 178 179 180 181 182 183
QStringList FirmwareUpgradeController::availableBoardsName(void)
{
    QGCSerialPortInfo::BoardType_t boardType;
    QString boardName;
    QStringList names;

    auto ports = QGCSerialPortInfo::availablePorts();
184
    for (const auto& info : ports) {
185 186 187 188 189 190 191 192 193
        if(info.canFlash()) {
            info.getBoardInfo(boardType, boardName);
            names.append(boardName);
        }
    }

    return names;
}

194
void FirmwareUpgradeController::_foundBoard(bool firstAttempt, const QSerialPortInfo& info, int boardType, QString boardName)
195
{
196 197 198
    _boardInfo      = info;
    _boardType      = static_cast<QGCSerialPortInfo::BoardType_t>(boardType);
    _boardTypeName  = boardName;
199 200 201

    qDebug() << info.manufacturer() << info.description();

202
    _startFlashWhenBootloaderFound = false;
203

204
    if (_boardType == QGCSerialPortInfo::BoardTypeSiKRadio) {
205 206 207 208 209 210 211 212
        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);
        }
213
    }
214
    
215
    qCDebug(FirmwareUpgradeLog) << _boardType << _boardTypeName;
216
    emit boardFound();
217 218
}

219 220

void FirmwareUpgradeController::_noBoardFound(void)
221
{
222 223 224 225 226 227
    emit noBoardFound();
}

void FirmwareUpgradeController::_boardGone(void)
{
    emit boardGone();
228 229 230 231
}

/// @brief Called when the bootloader is connected to by the findBootloader process. Moves the state machine
///         to the next step.
232
void FirmwareUpgradeController::_foundBoardInfo(int bootloaderVersion, int boardID, int flashSize)
233
{
234 235 236 237
    _bootloaderFound            = true;
    _bootloaderVersion          = static_cast<uint32_t>(bootloaderVersion);
    _bootloaderBoardID          = static_cast<uint32_t>(boardID);
    _bootloaderBoardFlashSize   = static_cast<uint32_t>(flashSize);
238
    
239 240 241 242
    _appendStatusLog(tr("Connected to bootloader:"));
    _appendStatusLog(tr("  Version: %1").arg(_bootloaderVersion));
    _appendStatusLog(tr("  Board ID: %1").arg(_bootloaderBoardID));
    _appendStatusLog(tr("  Flash size: %1").arg(_bootloaderBoardFlashSize));
243
    
244
    if (_startFlashWhenBootloaderFound) {
245
        flash(_startFlashWhenBootloaderFoundFirmwareIdentity);
246
    }
247

248 249 250
    if (_rgManifestFirmwareInfo.count()) {
        _buildAPMFirmwareNames();
    }
251 252

    emit bootloaderFound();
253 254 255
}


Pritam Ghanghas's avatar
Pritam Ghanghas committed
256 257 258
/// @brief intializes the firmware hashes with proper urls.
/// This happens only once for a class instance first time when it is needed.
void FirmwareUpgradeController::_initFirmwareHash()
259
{
Pritam Ghanghas's avatar
Pritam Ghanghas committed
260 261 262 263 264
    // indirect check whether this function has been called before or not
    // may have to be modified if _rgPX4FMUV2Firmware disappears
    if (!_rgPX4FMUV2Firmware.isEmpty()) {
        return;
    }
265

Pritam Ghanghas's avatar
Pritam Ghanghas committed
266 267 268 269 270 271
    //////////////////////////////////// PX4FMU aerocore firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t  rgAeroCoreFirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/stable/aerocore_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/beta/aerocore_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/master/aerocore_default.px4"},
    };
272

273 274 275 276 277 278
    //////////////////////////////////// AUAVX2_1 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgAUAVX2_1FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/auav-x21_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/auav-x21_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/auav-x21_default.px4"},
    };
Henry Zhang's avatar
Henry Zhang committed
279 280 281 282 283 284
    //////////////////////////////////// MindPXFMUV2 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgMindPXFMUV2FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/mindpx-v2_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/mindpx-v2_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/mindpx-v2_default.px4"},
    };
285 286 287 288 289
    //////////////////////////////////// TAPV1 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgTAPV1FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/tap-v1_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/tap-v1_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/tap-v1_default.px4"},
290
        { SingleFirmwareMode,StableFirmware,    DefaultVehicleFirmware, _singleFirmwareURL},
291 292 293 294 295 296 297
    };
    //////////////////////////////////// ASCV1 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgASCV1FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/asc-v1_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/asc-v1_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/asc-v1_default.px4"},
    };
298 299 300 301 302 303 304 305

    //////////////////////////////////// Crazyflie 2.0 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgCrazyflie2FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/crazyflie_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/crazyflie_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/crazyflie_default.px4"},
    };

306
    //////////////////////////////////// Omnibus F4 SD firmwares //////////////////////////////////////////////////
307 308 309 310 311
    FirmwareToUrlElement_t rgOmnibusF4SDFirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/omnibus_f4sd_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/omnibus_f4sd_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/omnibus_f4sd_default.px4"},
    };
312 313 314 315 316 317 318
    
    //////////////////////////////////// FMUK66V3 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgFMUK66V3FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/nxp_fmuk66-v3_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/nxp_fmuk66-v3_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/nxp_fmuk66-v3_default.px4"},
    };
319 320 321 322 323 324 325

    //////////////////////////////////// Kakute F7 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgKakuteF7FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/holybro_kakutef7_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/holybro_kakutef7_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/holybro_kakutef7_default.px4"},
    };
326
    
327 328 329 330 331 332
    //////////////////////////////////// Durandal firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgDurandalV1FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/holybro_durandal-v1_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/holybro_durandal-v1_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/holybro_durandal-v1_default.px4"},
    };
333 334 335 336 337 338 339

    //////////////////////////////////// ModalAI FC v1 firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgModalFCV1FirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/modalai_fc-v1_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/modalai_fc-v1_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/modalai_fc-v1_default.px4"},
    };
340 341 342 343 344 345 346 347

    //////////////////////////////////// mRo Control Zero firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgmRoCtrlZero[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/mro_ctrl-zero-f7_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/mro_ctrl-zero-f7_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/mro_ctrl-zero-f7_default.px4"},
    };

junwoo091400's avatar
junwoo091400 committed
348 349 350 351 352 353
    //////////////////////////////////// UVify FC firmwares //////////////////////////////////////////////////
    FirmwareToUrlElement_t rgUVifyCoreFirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/uvify_core_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/uvify_core_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/uvify_core_default.px4"},
    };
354

Pritam Ghanghas's avatar
Pritam Ghanghas committed
355 356
    /////////////////////////////// px4flow firmwares ///////////////////////////////////////
    FirmwareToUrlElement_t rgPX4FLowFirmwareArray[] = {
357
        { PX4FlowPX4, StableFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Flow/master/px4flow.px4" },
358
    #if !defined(NO_ARDUPILOT_DIALECT)
DonLakeFlyer's avatar
DonLakeFlyer committed
359
        { PX4FlowAPM, StableFirmware, DefaultVehicleFirmware, "http://firmware.ardupilot.org/Tools/PX4Flow/px4flow-klt-latest.px4" },
360
    #endif
Pritam Ghanghas's avatar
Pritam Ghanghas committed
361 362 363 364
    };

    /////////////////////////////// 3dr radio firmwares ///////////////////////////////////////
    FirmwareToUrlElement_t rg3DRRadioFirmwareArray[] = {
365
        { ThreeDRRadio, StableFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/SiK/stable/radio~hm_trp.ihx"}
Pritam Ghanghas's avatar
Pritam Ghanghas committed
366 367
    };

czhj's avatar
czhj committed
368 369 370 371 372 373 374
    /////////////////////////////// cuav nora firmwares ///////////////////////////////////////
    FirmwareToUrlElement_t rgCUAVNoraFirmwareArray[] = {
        { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/cuav_nora_default.px4"},
        { AutoPilotStackPX4, BetaFirmware,      DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/cuav_nora_default.px4"},
        { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/cuav_nora_default.px4"},
    };

375
    // We build the maps for PX4 firmwares dynamically using the data below
Don Gagne's avatar
Don Gagne committed
376 377 378 379 380 381 382 383 384 385

#if 0
    Example URLs for PX4 and ArduPilot
    { AutoPilotStackPX4, StableFirmware,    DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/px4fmu-v4_default.px4"},
    { AutoPilotStackAPM, StableFirmware,    CopterFirmware,         "http://firmware.ardupilot.org/Copter/stable/PX4/ArduCopter-v4.px4"},
    { AutoPilotStackAPM, DeveloperFirmware, CopterChibiosFirmware,  "http://firmware.ardupilot.org/Copter/latest/fmuv4/arducopter.apj"},
#endif

    QString px4Url          ("http://px4-travis.s3.amazonaws.com/Firmware/%1/px4fmu-%2_default.px4");

386
    QMap<FirmwareBuildType_t, QString> px4MapFirmwareTypeToDir;
Don Gagne's avatar
Don Gagne committed
387 388 389
    px4MapFirmwareTypeToDir[StableFirmware] =       QStringLiteral("stable");
    px4MapFirmwareTypeToDir[BetaFirmware] =         QStringLiteral("beta");
    px4MapFirmwareTypeToDir[DeveloperFirmware] =    QStringLiteral("master");
Don Gagne's avatar
Don Gagne committed
390 391

    // PX4 Firmwares
392
    for (const FirmwareBuildType_t& firmwareType: px4MapFirmwareTypeToDir.keys()) {
Don Gagne's avatar
Don Gagne committed
393
        QString dir = px4MapFirmwareTypeToDir[firmwareType];
394 395 396 397 398
        _rgFMUV5Firmware.insert     (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v5"));
        _rgFMUV4PROFirmware.insert  (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v4pro"));
        _rgFMUV4Firmware.insert     (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v4"));
        _rgFMUV3Firmware.insert     (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v3"));
        _rgPX4FMUV2Firmware.insert  (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v2"));
Don Gagne's avatar
Don Gagne committed
399 400
    }

huangjian's avatar
huangjian committed
401 402 403 404 405 406
    QString px4CUAVX7Url          ("http://px4-travis.s3.amazonaws.com/Firmware/%1/cuav_%2_default.px4");
    for (const FirmwareBuildType_t& firmwareType: px4MapFirmwareTypeToDir.keys()) {
        QString dir = px4MapFirmwareTypeToDir[firmwareType];
        _rgPX4CUAVX7Fireware.insert     (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4CUAVX7Url.arg(dir).arg("x7pro"));
    }

Don Gagne's avatar
Don Gagne committed
407
    int size = sizeof(rgAeroCoreFirmwareArray)/sizeof(rgAeroCoreFirmwareArray[0]);
Pritam Ghanghas's avatar
Pritam Ghanghas committed
408 409 410 411
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgAeroCoreFirmwareArray[i];
        _rgAeroCoreFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
412

czhj's avatar
czhj committed
413 414 415 416 417 418
    size = sizeof(rgCUAVNoraFirmwareArray)/sizeof(rgCUAVNoraFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgCUAVNoraFirmwareArray[i];
        _rgCUAVNoraFireware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

419 420 421 422 423 424
    size = sizeof(rgAUAVX2_1FirmwareArray)/sizeof(rgAUAVX2_1FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgAUAVX2_1FirmwareArray[i];
        _rgAUAVX2_1Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

Henry Zhang's avatar
Henry Zhang committed
425 426 427 428 429 430
    size = sizeof(rgMindPXFMUV2FirmwareArray)/sizeof(rgMindPXFMUV2FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgMindPXFMUV2FirmwareArray[i];
        _rgMindPXFMUV2Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

431 432 433 434 435 436 437 438 439 440 441 442
    size = sizeof(rgTAPV1FirmwareArray)/sizeof(rgTAPV1FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgTAPV1FirmwareArray[i];
        _rgTAPV1Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

    size = sizeof(rgASCV1FirmwareArray)/sizeof(rgASCV1FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgASCV1FirmwareArray[i];
        _rgASCV1Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

443 444 445 446 447 448
    size = sizeof(rgCrazyflie2FirmwareArray)/sizeof(rgCrazyflie2FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgCrazyflie2FirmwareArray[i];
        _rgCrazyflie2Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

449 450 451 452 453
    size = sizeof(rgOmnibusF4SDFirmwareArray)/sizeof(rgOmnibusF4SDFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgOmnibusF4SDFirmwareArray[i];
        _rgOmnibusF4SDFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
454
    
455 456 457 458 459 460
    size = sizeof(rgKakuteF7FirmwareArray)/sizeof(rgKakuteF7FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgKakuteF7FirmwareArray[i];
        _rgKakuteF7Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

461 462 463 464 465 466
    size = sizeof(rgDurandalV1FirmwareArray)/sizeof(rgDurandalV1FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgDurandalV1FirmwareArray[i];
        _rgDurandalV1Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

467 468 469 470 471
    size = sizeof(rgFMUK66V3FirmwareArray)/sizeof(rgFMUK66V3FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgFMUK66V3FirmwareArray[i];
        _rgFMUK66V3Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
472

473 474 475 476 477 478
    size = sizeof(rgModalFCV1FirmwareArray)/sizeof(rgModalFCV1FirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgModalFCV1FirmwareArray[i];
        _rgModalFCV1Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

479 480 481 482 483 484
    size = sizeof(rgmRoCtrlZero)/sizeof(rgmRoCtrlZero[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgmRoCtrlZero[i];
        _rgmRoCtrlZeroF7Firmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

junwoo091400's avatar
junwoo091400 committed
485 486 487 488 489 490
    size = sizeof(rgUVifyCoreFirmwareArray)/sizeof(rgUVifyCoreFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgUVifyCoreFirmwareArray[i];
        _rgUVifyCoreFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }

Pritam Ghanghas's avatar
Pritam Ghanghas committed
491 492 493 494 495
    size = sizeof(rgPX4FLowFirmwareArray)/sizeof(rgPX4FLowFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rgPX4FLowFirmwareArray[i];
        _rgPX4FLowFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
496

Pritam Ghanghas's avatar
Pritam Ghanghas committed
497 498 499 500 501
    size = sizeof(rg3DRRadioFirmwareArray)/sizeof(rg3DRRadioFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rg3DRRadioFirmwareArray[i];
        _rg3DRRadioFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
502 503 504 505 506 507

    size = sizeof(rg3DRRadioFirmwareArray)/sizeof(rg3DRRadioFirmwareArray[0]);
    for (int i = 0; i < size; i++) {
        const FirmwareToUrlElement_t& element = rg3DRRadioFirmwareArray[i];
        _rg3DRRadioFirmware.insert(FirmwareIdentifier(element.stackType, element.firmwareType, element.vehicleType), element.url);
    }
Pritam Ghanghas's avatar
Pritam Ghanghas committed
508
}
509

Pritam Ghanghas's avatar
Pritam Ghanghas committed
510 511 512 513 514 515
/// @brief Called when the findBootloader process is unable to sync to the bootloader. Moves the state
///         machine to the appropriate error state.
void FirmwareUpgradeController::_bootloaderSyncFailed(void)
{
    _errorCancel("Unable to sync with bootloader.");
}
516

517
QHash<FirmwareUpgradeController::FirmwareIdentifier, QString>* FirmwareUpgradeController::_firmwareHashForBoardId(int boardId)
Pritam Ghanghas's avatar
Pritam Ghanghas committed
518
{
519 520

    _rgFirmwareDynamic.clear();
521

522 523
    switch (boardId) {
    case Bootloader::boardIDPX4Flow:
524
        _rgFirmwareDynamic = _rgPX4FLowFirmware;
525
        break;
526
    case Bootloader::boardIDPX4FMUV2:
527
        _rgFirmwareDynamic = _rgPX4FMUV2Firmware;
528
        break;
DonLakeFlyer's avatar
DonLakeFlyer committed
529
    case Bootloader::boardIDPX4FMUV3:
530
        _rgFirmwareDynamic = _rgFMUV3Firmware;
531
        break;
532
    case Bootloader::boardIDPX4FMUV4:
533
        _rgFirmwareDynamic = _rgFMUV4Firmware;
534
        break;
535
    case Bootloader::boardIDPX4FMUV4PRO:
536
        _rgFirmwareDynamic = _rgFMUV4PROFirmware;
537
        break;
538
    case Bootloader::boardIDPX4FMUV5:
539
        _rgFirmwareDynamic = _rgFMUV5Firmware;
540
        break;
541
    case Bootloader::boardIDAeroCore:
542
        _rgFirmwareDynamic = _rgAeroCoreFirmware;
543
        break;
544
    case Bootloader::boardIDAUAVX2_1:
545
        _rgFirmwareDynamic = _rgAUAVX2_1Firmware;
546
        break;
Henry Zhang's avatar
Henry Zhang committed
547
    case Bootloader::boardIDMINDPXFMUV2:
548
        _rgFirmwareDynamic = _rgMindPXFMUV2Firmware;
549
        break;
550
    case Bootloader::boardIDTAPV1:
551
        _rgFirmwareDynamic = _rgTAPV1Firmware;
552
        break;
553
    case Bootloader::boardIDASCV1:
554
        _rgFirmwareDynamic = _rgASCV1Firmware;
555
        break;
556
    case Bootloader::boardIDCrazyflie2:
557
        _rgFirmwareDynamic = _rgCrazyflie2Firmware;
558
        break;
559
    case Bootloader::boardIDOmnibusF4SD:
560
        _rgFirmwareDynamic = _rgOmnibusF4SDFirmware;
561
        break;
562 563 564
    case Bootloader::boardIDKakuteF7:
        _rgFirmwareDynamic = _rgKakuteF7Firmware;
        break;
565 566 567
    case Bootloader::boardIDDurandalV1:
        _rgFirmwareDynamic = _rgDurandalV1Firmware;
        break;
568 569
    case Bootloader::boardIDFMUK66V3:
        _rgFirmwareDynamic = _rgFMUK66V3Firmware;
570
        break;
571 572 573
    case Bootloader::boardIDModalFCV1:
        _rgFirmwareDynamic = _rgModalFCV1Firmware;
        break;
574 575 576
    case Bootloader::boardIDmRoCtrlZeroF7:
        _rgFirmwareDynamic = _rgmRoCtrlZeroF7Firmware;
        break;
junwoo091400's avatar
junwoo091400 committed
577 578 579
    case Bootloader::boardIDUVifyCore:
        _rgFirmwareDynamic = _rgUVifyCoreFirmware;
        break;
580
    case Bootloader::boardID3DRRadio:
581
        _rgFirmwareDynamic = _rg3DRRadioFirmware;
582
        break;
huangjian's avatar
huangjian committed
583 584 585
    case Bootloader::boardIDCUAVX7:
        _rgFirmwareDynamic = _rgPX4CUAVX7Fireware;
        break;
czhj's avatar
czhj committed
586 587 588
    case Bootloader::boardIDCUAVNora:
        _rgFirmwareDynamic = _rgCUAVNoraFireware;
        break;
589
    default:
590 591
        // Unknown board id
        break;
592 593 594
    }

    return &_rgFirmwareDynamic;
595
}
Lorenz Meier's avatar
Lorenz Meier committed
596

597 598
void FirmwareUpgradeController::_getFirmwareFile(FirmwareIdentifier firmwareId)
{
599
    QHash<FirmwareIdentifier, QString>* prgFirmware = _firmwareHashForBoardId(static_cast<int>(_bootloaderBoardID));
600
    if (firmwareId.firmwareType == CustomFirmware) {
601 602
        _firmwareFilename = QString();
        _errorCancel(tr("Custom firmware selected but no filename given."));
603
    } else {
604 605
        if (prgFirmware->contains(firmwareId)) {
            _firmwareFilename = prgFirmware->value(firmwareId);
606
        } else {
607
            _errorCancel(tr("Unable to find specified firmware for board type"));
608 609
            return;
        }
610 611 612
    }
    
    if (_firmwareFilename.isEmpty()) {
613
        _errorCancel(tr("No firmware file selected"));
614 615 616 617 618 619 620 621 622 623
    } else {
        _downloadFirmware();
    }
}

/// @brief Begins the process of downloading the selected firmware file.
void FirmwareUpgradeController::_downloadFirmware(void)
{
    Q_ASSERT(!_firmwareFilename.isEmpty());
    
624 625
    _appendStatusLog(tr("Downloading firmware..."));
    _appendStatusLog(tr(" From: %1").arg(_firmwareFilename));
626
    
627
    QGCFileDownload* downloader = new QGCFileDownload(this);
628
    connect(downloader, &QGCFileDownload::downloadComplete, this, &FirmwareUpgradeController::_firmwareDownloadComplete);
629 630
    connect(downloader, &QGCFileDownload::downloadProgress, this, &FirmwareUpgradeController::_firmwareDownloadProgress);
    downloader->download(_firmwareFilename);
631 632 633
}

/// @brief Updates the progress indicator while downloading
634
void FirmwareUpgradeController::_firmwareDownloadProgress(qint64 curr, qint64 total)
635 636 637
{
    // Take care of cases where 0 / 0 is emitted as error return value
    if (total > 0) {
638
        _progressBar->setProperty("value", static_cast<float>(curr) / static_cast<float>(total));
639 640 641 642
    }
}

/// @brief Called when the firmware download completes.
643
void FirmwareUpgradeController::_firmwareDownloadComplete(QString /*remoteFile*/, QString localFile, QString errorMsg)
644
{
645
    if (errorMsg.isEmpty()) {
646
    _appendStatusLog(tr("Download complete"));
647
    
648
    FirmwareImage* image = new FirmwareImage(this);
649
    
650 651
    connect(image, &FirmwareImage::statusMessage, this, &FirmwareUpgradeController::_status);
    connect(image, &FirmwareImage::errorMessage, this, &FirmwareUpgradeController::_error);
652
    
653
    if (!image->load(localFile, _bootloaderBoardID)) {
654
        _errorCancel(tr("Image load failed"));
655
        return;
656 657
    }
    
658 659
    // We can't proceed unless we have the bootloader
    if (!_bootloaderFound) {
660
        _errorCancel(tr("Bootloader not found"));
661 662
        return;
    }
663
    
664
    if (_bootloaderBoardFlashSize != 0 && image->imageSize() > _bootloaderBoardFlashSize) {
665
        _errorCancel(tr("Image size of %1 is too large for board flash size %2").arg(image->imageSize()).arg(_bootloaderBoardFlashSize));
666
        return;
667
    }
668 669

    _threadController->flash(image);
670 671 672
    } else {
        _errorCancel(errorMsg);
    }
673 674
}

675
/// @brief returns firmware type as a string
676
QString FirmwareUpgradeController::firmwareTypeAsString(FirmwareBuildType_t type) const
677 678 679 680 681 682 683 684 685 686 687 688 689
{
    switch (type) {
    case StableFirmware:
        return "stable";
    case DeveloperFirmware:
        return "developer";
    case BetaFirmware:
        return "beta";
    default:
        return "custom";
    }
}

690 691 692
/// @brief Signals completion of one of the specified bootloader commands. Moves the state machine to the
///         appropriate next step.
void FirmwareUpgradeController::_flashComplete(void)
693
{
694
    delete _image;
695
    _image = nullptr;
696
    
697
    _appendStatusLog(tr("Upgrade complete"), true);
698 699
    _appendStatusLog("------------------------------------------", false);
    emit flashComplete();
700
    qgcApp()->toolbox()->linkManager()->setConnectionsAllowed();
701 702
}

703
void FirmwareUpgradeController::_error(const QString& errorString)
704
{
705
    delete _image;
706
    _image = nullptr;
707 708
    
    _errorCancel(QString("Error: %1").arg(errorString));
709 710
}

711
void FirmwareUpgradeController::_status(const QString& statusString)
712
{
713
    _appendStatusLog(statusString);
714 715 716 717 718
}

/// @brief Updates the progress bar from long running bootloader commands
void FirmwareUpgradeController::_updateProgress(int curr, int total)
{
719 720
    // Take care of cases where 0 / 0 is emitted as error return value
    if (total > 0) {
721
        _progressBar->setProperty("value", static_cast<float>(curr) / static_cast<float>(total));
722
    }
723 724 725 726 727 728
}

/// @brief Moves the progress bar ahead on tick while erasing the board
void FirmwareUpgradeController::_eraseProgressTick(void)
{
    _eraseTickCount++;
729
    _progressBar->setProperty("value", static_cast<float>(_eraseTickCount*_eraseTickMsec) / static_cast<float>(_eraseTotalMsec));
730 731 732
}

/// Appends the specified text to the status log area in the ui
733
void FirmwareUpgradeController::_appendStatusLog(const QString& text, bool critical)
734 735 736 737
{
    Q_ASSERT(_statusLog);
    
    QVariant returnedValue;
738 739 740 741 742 743 744 745
    QVariant varText;
    
    if (critical) {
        varText = QString("<font color=\"yellow\">%1</font>").arg(text);
    } else {
        varText = text;
    }
    
746 747 748 749
    QMetaObject::invokeMethod(_statusLog,
                              "append",
                              Q_RETURN_ARG(QVariant, returnedValue),
                              Q_ARG(QVariant, varText));
Don Gagne's avatar
Don Gagne committed
750
}
751

752 753 754
void FirmwareUpgradeController::_errorCancel(const QString& msg)
{
    _appendStatusLog(msg, false);
755
    _appendStatusLog(tr("Upgrade cancelled"), true);
756 757 758
    _appendStatusLog("------------------------------------------", false);
    emit error();
    cancel();
759
    qgcApp()->toolbox()->linkManager()->setConnectionsAllowed();
760 761 762 763 764 765 766 767 768 769
}

void FirmwareUpgradeController::_eraseStarted(void)
{
    // We set up our own progress bar for erase since the erase command does not provide one
    _eraseTickCount = 0;
    _eraseTimer.start(_eraseTickMsec);
}

void FirmwareUpgradeController::_eraseComplete(void)
770
{
771
    _eraseTimer.stop();
772
}
773

774
void FirmwareUpgradeController::setSelectedFirmwareBuildType(FirmwareBuildType_t firmwareType)
775
{
776 777 778
    _selectedFirmwareBuildType = firmwareType;
    emit selectedFirmwareBuildTypeChanged(_selectedFirmwareBuildType);
    _buildAPMFirmwareNames();
779 780
}

781
void FirmwareUpgradeController::_buildAPMFirmwareNames(void)
782
{
783
#if !defined(NO_ARDUPILOT_DIALECT)
Don Gagne's avatar
Don Gagne committed
784 785
    bool                    chibios =           _apmChibiOSSetting->rawValue().toInt() == 0;
    FirmwareVehicleType_t   vehicleType =       static_cast<FirmwareVehicleType_t>(_apmVehicleTypeSetting->rawValue().toInt());
786 787 788
    QString                 boardDescription =  _boardInfo.description();
    quint16                 boardVID =          _boardInfo.vendorIdentifier();
    quint16                 boardPID =          _boardInfo.productIdentifier();
789
    uint32_t                rawBoardId =        _bootloaderBoardID == Bootloader::boardIDPX4FMUV3 ? Bootloader::boardIDPX4FMUV2 : _bootloaderBoardID;
Don Gagne's avatar
Don Gagne committed
790

DonLakeFlyer's avatar
DonLakeFlyer committed
791 792 793 794
    if (_boardType == QGCSerialPortInfo::BoardTypePX4Flow) {
        return;
    }

Don Gagne's avatar
Don Gagne committed
795
    qCDebug(FirmwareUpgradeLog) << QStringLiteral("_buildAPMFirmwareNames description(%1) vid(%2/0x%3) pid(%4/0x%5)").arg(boardDescription).arg(boardVID).arg(boardVID, 1, 16).arg(boardPID).arg(boardPID, 1, 16);
796

797
    _apmFirmwareNames.clear();
798
    _apmFirmwareNamesBestIndex = -1;
799
    _apmFirmwareUrls.clear();
800

801
    QString apmDescriptionSuffix("-BL");
802
    QString boardDescriptionPrefix;
Don Gagne's avatar
Don Gagne committed
803
    bool    bootloaderMatch = boardDescription.endsWith(apmDescriptionSuffix);
804

805
    int currentIndex = 0;
806 807
    for (const ManifestFirmwareInfo_t& firmwareInfo: _rgManifestFirmwareInfo) {
        bool match = false;
808 809 810
        if (firmwareInfo.firmwareBuildType == _selectedFirmwareBuildType && firmwareInfo.chibios == chibios && firmwareInfo.vehicleType == vehicleType && firmwareInfo.boardId == rawBoardId) {
            if (firmwareInfo.fmuv2 && _bootloaderBoardID == Bootloader::boardIDPX4FMUV3) {
                qCDebug(FirmwareUpgradeLog) << "Skipping fmuv2 manifest entry for fmuv3 board:" << firmwareInfo.friendlyName << boardDescription << firmwareInfo.rgBootloaderPortString << firmwareInfo.url << firmwareInfo.vehicleType;
811
            } else {
812 813 814 815 816
                qCDebug(FirmwareUpgradeLog) << "Board id match:" << firmwareInfo.friendlyName << boardDescription << firmwareInfo.rgBootloaderPortString << firmwareInfo.url << firmwareInfo.vehicleType;
                match = true;
                if (bootloaderMatch && _apmFirmwareNamesBestIndex == -1 && firmwareInfo.rgBootloaderPortString.contains(boardDescription)) {
                    _apmFirmwareNamesBestIndex = currentIndex;
                    qCDebug(FirmwareUpgradeLog) << "Bootloader best match:" << firmwareInfo.friendlyName << boardDescription << firmwareInfo.rgBootloaderPortString << firmwareInfo.url << firmwareInfo.vehicleType;
817
                }
818
            }
Don Gagne's avatar
Don Gagne committed
819
        }
820

821 822 823
        if (match) {
            _apmFirmwareNames.append(firmwareInfo.friendlyName);
            _apmFirmwareUrls.append(firmwareInfo.url);
824
            currentIndex++;
825 826 827
        }
    }

828 829 830 831 832 833
    if (_apmFirmwareNamesBestIndex == -1) {
        _apmFirmwareNamesBestIndex++;
        if (_apmFirmwareNames.count() > 1) {
            _apmFirmwareNames.prepend(tr("Choose board type"));
            _apmFirmwareUrls.prepend(QString());
        }
834 835
    }

836
    emit apmFirmwareNamesChanged();
837
#endif
838 839
}

840
FirmwareUpgradeController::FirmwareVehicleType_t FirmwareUpgradeController::vehicleTypeFromFirmwareSelectionIndex(int index)
841 842 843
{
    if (index < 0 || index >= _apmVehicleTypeFromCurrentVersionList.count()) {
        qWarning() << "Invalid index, index:count" << index << _apmVehicleTypeFromCurrentVersionList.count();
Don Gagne's avatar
Don Gagne committed
844
        return CopterFirmware;
845 846 847 848
    }

    return _apmVehicleTypeFromCurrentVersionList[index];
}
Don Gagne's avatar
Don Gagne committed
849 850 851 852

void FirmwareUpgradeController::_determinePX4StableVersion(void)
{
    QGCFileDownload* downloader = new QGCFileDownload(this);
853
    connect(downloader, &QGCFileDownload::downloadComplete, this, &FirmwareUpgradeController::_px4ReleasesGithubDownloadComplete);
854
    downloader->download(QStringLiteral("https://api.github.com/repos/PX4/Firmware/releases"));
Don Gagne's avatar
Don Gagne committed
855 856
}

857
void FirmwareUpgradeController::_px4ReleasesGithubDownloadComplete(QString /*remoteFile*/, QString localFile, QString errorMsg)
Don Gagne's avatar
Don Gagne committed
858
{
859 860 861 862 863 864 865 866
    if (errorMsg.isEmpty()) {
        QFile jsonFile(localFile);
        if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            qCWarning(FirmwareUpgradeLog) << "Unable to open github px4 releases json file" << localFile << jsonFile.errorString();
            return;
        }
        QByteArray bytes = jsonFile.readAll();
        jsonFile.close();
Don Gagne's avatar
Don Gagne committed
867

868 869 870 871 872 873
        QJsonParseError jsonParseError;
        QJsonDocument doc = QJsonDocument::fromJson(bytes, &jsonParseError);
        if (jsonParseError.error != QJsonParseError::NoError) {
            qCWarning(FirmwareUpgradeLog) <<  "Unable to open px4 releases json document" << localFile << jsonParseError.errorString();
            return;
        }
Don Gagne's avatar
Don Gagne committed
874

875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
        // Json should be an array of release objects
        if (!doc.isArray()) {
            qCWarning(FirmwareUpgradeLog) <<  "px4 releases json document is not an array" << localFile;
            return;
        }
        QJsonArray releases = doc.array();

        // The first release marked prerelease=false is stable
        // The first release marked prerelease=true is beta
        bool foundStable = false;
        bool foundBeta = false;
        for (int i=0; i<releases.count() && (!foundStable || !foundBeta); i++) {
            QJsonObject release = releases[i].toObject();
            if (!foundStable && !release["prerelease"].toBool()) {
                _px4StableVersion = release["name"].toString();
                emit px4StableVersionChanged(_px4StableVersion);
                qCDebug(FirmwareUpgradeLog()) << "Found px4 stable version" << _px4StableVersion;
                foundStable = true;
            } else if (!foundBeta && release["prerelease"].toBool()) {
                _px4BetaVersion = release["name"].toString();
                emit px4StableVersionChanged(_px4BetaVersion);
                qCDebug(FirmwareUpgradeLog()) << "Found px4 beta version" << _px4BetaVersion;
                foundBeta = true;
            }
899 900
        }

901 902 903 904 905 906 907 908
        if (!foundStable) {
            qCDebug(FirmwareUpgradeLog()) << "Unable to find px4 stable version" << localFile;
        }
        if (!foundBeta) {
            qCDebug(FirmwareUpgradeLog()) << "Unable to find px4 beta version" << localFile;
        }
    } else {
        qCWarning(FirmwareUpgradeLog) << "PX4 releases github download failed" << errorMsg;
909
    }
Don Gagne's avatar
Don Gagne committed
910 911
}

912 913 914 915 916 917
void FirmwareUpgradeController::_downloadArduPilotManifest(void)
{
    _downloadingFirmwareList = true;
    emit downloadingFirmwareListChanged(true);

    QGCFileDownload* downloader = new QGCFileDownload(this);
918
    connect(downloader, &QGCFileDownload::downloadComplete, this, &FirmwareUpgradeController::_ardupilotManifestDownloadComplete);
919 920 921
    downloader->download(QStringLiteral("http://firmware.ardupilot.org/manifest.json.gz"));
}

922
void FirmwareUpgradeController::_ardupilotManifestDownloadComplete(QString remoteFile, QString localFile, QString errorMsg)
923
{
924 925 926
    if (errorMsg.isEmpty()) {
        // Delete the QGCFileDownload object
        sender()->deleteLater();
927

928
        qCDebug(FirmwareUpgradeLog) << "_ardupilotManifestDownloadFinished" << remoteFile << localFile;
929

930 931 932 933 934
        QString jsonFileName(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).absoluteFilePath("ArduPilot.Manifest.json"));
        if (!QGCZlib::inflateGzipFile(localFile, jsonFileName)) {
            qCWarning(FirmwareUpgradeLog) << "Inflate of compressed manifest failed" << localFile;
            return;
        }
935

936 937 938 939 940 941
        QString         errorString;
        QJsonDocument   doc;
        if (!JsonHelper::isJsonFile(jsonFileName, doc, errorString)) {
            qCWarning(FirmwareUpgradeLog) << "Json file read failed" << errorString;
            return;
        }
942

943 944
        QJsonObject json =          doc.object();
        QJsonArray  rgFirmware =    json[_manifestFirmwareJsonKey].toArray();
945

946 947
        for (int i=0; i<rgFirmware.count(); i++) {
            const QJsonObject& firmwareJson = rgFirmware[i].toObject();
948

949 950 951 952
            FirmwareVehicleType_t   firmwareVehicleType =   _manifestMavTypeToFirmwareVehicleType(firmwareJson[_manifestMavTypeJsonKey].toString());
            FirmwareBuildType_t     firmwareBuildType =     _manifestMavFirmwareVersionTypeToFirmwareBuildType(firmwareJson[_manifestMavFirmwareVersionTypeJsonKey].toString());
            QString                 format =                firmwareJson[_manifestFormatJsonKey].toString();
            QString                 platform =              firmwareJson[_manifestPlatformKey].toString();
953

954 955 956 957
            if (firmwareVehicleType != DefaultVehicleFirmware && firmwareBuildType != CustomFirmware && (format == QStringLiteral("apj") || format == QStringLiteral("px4"))) {
                if (platform.contains("-heli") && firmwareVehicleType != HeliFirmware) {
                    continue;
                }
958

959 960
                _rgManifestFirmwareInfo.append(ManifestFirmwareInfo_t());
                ManifestFirmwareInfo_t& firmwareInfo = _rgManifestFirmwareInfo.last();
961

962 963 964 965 966 967
                firmwareInfo.boardId =              static_cast<uint32_t>(firmwareJson[_manifestBoardIdJsonKey].toInt());
                firmwareInfo.firmwareBuildType =    firmwareBuildType;
                firmwareInfo.vehicleType =          firmwareVehicleType;
                firmwareInfo.url =                  firmwareJson[_manifestUrlJsonKey].toString();
                firmwareInfo.version =              firmwareJson[_manifestMavFirmwareVersionJsonKey].toString();
                firmwareInfo.chibios =              format == QStringLiteral("apj");                firmwareInfo.fmuv2 =                platform.contains(QStringLiteral("fmuv2"));
968

969 970 971 972
                QJsonArray bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray();
                for (int j=0; j<bootloaderArray.count(); j++) {
                    firmwareInfo.rgBootloaderPortString.append(bootloaderArray[j].toString());
                }
973

974 975 976 977 978
                QJsonArray usbidArray = firmwareJson[_manifestUSBIDJsonKey].toArray();
                for (int j=0; j<usbidArray.count(); j++) {
                    QStringList vidpid = usbidArray[j].toString().split('/');
                    QString vid = vidpid[0];
                    QString pid = vidpid[1];
979

980 981 982 983
                    bool ok;
                    firmwareInfo.rgVID.append(vid.right(vid.count() - 2).toInt(&ok, 16));
                    firmwareInfo.rgPID.append(pid.right(pid.count() - 2).toInt(&ok, 16));
                }
984

985 986
                QString brandName = firmwareJson[_manifestBrandNameKey].toString();
                firmwareInfo.friendlyName = QStringLiteral("%1 - %2").arg(brandName.isEmpty() ? platform : brandName).arg(firmwareInfo.version);
987
            }
988
        }
989

990 991
        if (_bootloaderFound) {
            _buildAPMFirmwareNames();
992 993
        }

994 995 996 997
        _downloadingFirmwareList = false;
        emit downloadingFirmwareListChanged(false);
    } else {
        qCWarning(FirmwareUpgradeLog) << "ArduPilot Manifest download failed" << errorMsg;
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    }
}

FirmwareUpgradeController::FirmwareBuildType_t FirmwareUpgradeController::_manifestMavFirmwareVersionTypeToFirmwareBuildType(const QString& manifestMavFirmwareVersionType)
{
    if (_manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap.contains(manifestMavFirmwareVersionType)) {
        return _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap[manifestMavFirmwareVersionType];
    } else {
        return CustomFirmware;
    }
}

FirmwareUpgradeController::FirmwareVehicleType_t FirmwareUpgradeController::_manifestMavTypeToFirmwareVehicleType(const QString& manifestMavType)
{
    if (_manifestMavTypeToFirmwareVehicleTypeMap.contains(manifestMavType)) {
        return _manifestMavTypeToFirmwareVehicleTypeMap[manifestMavType];
    } else {
        return DefaultVehicleFirmware;
    }
}