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

10 11

/// @file
Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
12
///     @brief PX4 Firmware Upgrade operations which occur on a separate thread.
13 14 15
///     @author Don Gagne <don@thegagnes.com>

#include "PX4FirmwareUpgradeThread.h"
16 17 18
#include "Bootloader.h"
#include "QGCLoggingCategory.h"
#include "QGC.h"
19 20 21

#include <QTimer>
#include <QDebug>
Don Gagne's avatar
Don Gagne committed
22
#include <QSerialPort>
23

24 25
PX4FirmwareUpgradeThreadWorker::PX4FirmwareUpgradeThreadWorker(PX4FirmwareUpgradeThreadController* controller)
    : _controller(controller)
26
{
27 28 29 30 31
    connect(_controller, &PX4FirmwareUpgradeThreadController::_initThreadWorker,            this, &PX4FirmwareUpgradeThreadWorker::_init);
    connect(_controller, &PX4FirmwareUpgradeThreadController::_startFindBoardLoopOnThread,  this, &PX4FirmwareUpgradeThreadWorker::_startFindBoardLoop);
    connect(_controller, &PX4FirmwareUpgradeThreadController::_flashOnThread,               this, &PX4FirmwareUpgradeThreadWorker::_flash);
    connect(_controller, &PX4FirmwareUpgradeThreadController::_rebootOnThread,              this, &PX4FirmwareUpgradeThreadWorker::_reboot);
    connect(_controller, &PX4FirmwareUpgradeThreadController::_cancel,                      this, &PX4FirmwareUpgradeThreadWorker::_cancel);
32 33 34 35
}

PX4FirmwareUpgradeThreadWorker::~PX4FirmwareUpgradeThreadWorker()
{
36

37 38
}

39
void PX4FirmwareUpgradeThreadWorker::_init(void)
40 41 42
{
    // We create the timers here so that they are on the right thread
    
43 44 45 46
    _findBoardTimer = new QTimer(this);
    _findBoardTimer->setSingleShot(true);
    _findBoardTimer->setInterval(500);
    connect(_findBoardTimer, &QTimer::timeout, this, &PX4FirmwareUpgradeThreadWorker::_findBoardOnce);
47 48
}

49
void PX4FirmwareUpgradeThreadWorker::_cancel(void)
50
{
51 52 53 54 55 56
    qCDebug(FirmwareUpgradeVerboseLog) << "_cancel";
    if (_bootloader) {
        _bootloader->reboot();
        _bootloader->close();
        _bootloader->deleteLater();
        _bootloader = nullptr;
57 58 59 60 61 62
    }
}

void PX4FirmwareUpgradeThreadWorker::_startFindBoardLoop(void)
{
    _foundBoard = false;
Don Gagne's avatar
Don Gagne committed
63
    _findBoardFirstAttempt = true;
64 65 66 67 68
    _findBoardOnce();
}

void PX4FirmwareUpgradeThreadWorker::_findBoardOnce(void)
{
Don Gagne's avatar
Don Gagne committed
69
    qCDebug(FirmwareUpgradeVerboseLog) << "_findBoardOnce";
70
    
Don Gagne's avatar
Don Gagne committed
71 72
    QGCSerialPortInfo               portInfo;
    QGCSerialPortInfo::BoardType_t  boardType;
73
    QString                         boardName;
74
    
75
    if (_findBoardFromPorts(portInfo, boardType, boardName)) {
76 77 78
        if (!_foundBoard) {
            _foundBoard = true;
            _foundBoardPortInfo = portInfo;
79
            emit foundBoard(_findBoardFirstAttempt, portInfo, boardType, boardName);
80
            if (!_findBoardFirstAttempt) {
81 82 83 84 85 86 87 88 89 90 91 92 93 94

                _bootloader = new Bootloader(boardType == QGCSerialPortInfo::BoardTypeSiKRadio, this);
                connect(_bootloader, &Bootloader::updateProgress, this, &PX4FirmwareUpgradeThreadWorker::_updateProgress);

                if (_bootloader->open(portInfo.portName())) {
                    uint32_t    bootloaderVersion;
                    uint32_t    boardId;
                    uint32_t    flashSize;
                    if (_bootloader->getBoardInfo(bootloaderVersion, boardId, flashSize)) {
                        emit foundBoardInfo(bootloaderVersion, boardId, flashSize);
                    } else {
                        emit error(_bootloader->errorString());
                        return;
                    }
95
                } else {
96
                    emit error(_bootloader->errorString());
97 98 99 100 101 102 103 104 105 106 107
                    return;
                }
            }
        }
    } else {
        if (_foundBoard) {
            _foundBoard = false;
            qCDebug(FirmwareUpgradeLog) << "Board gone";
            emit boardGone();
        } else if (_findBoardFirstAttempt) {
            emit noBoardFound();
108 109 110
        }
    }
    
Don Gagne's avatar
Don Gagne committed
111
    _findBoardFirstAttempt = false;
112
    _findBoardTimer->start();
113 114
}

115
bool PX4FirmwareUpgradeThreadWorker::_findBoardFromPorts(QGCSerialPortInfo& portInfo, QGCSerialPortInfo::BoardType_t& boardType, QString& boardName)
116
{
117
    for (const QGCSerialPortInfo& info: QGCSerialPortInfo::availablePorts()) {
118 119
        info.getBoardInfo(boardType, boardName);

Don Gagne's avatar
Don Gagne committed
120
        qCDebug(FirmwareUpgradeVerboseLog) << "Serial Port --------------";
121 122
        qCDebug(FirmwareUpgradeVerboseLog) << "\tboard type" << boardType;
        qCDebug(FirmwareUpgradeVerboseLog) << "\tboard name" << boardName;
123
        qCDebug(FirmwareUpgradeVerboseLog) << "\tmanufacturer:" << info.manufacturer();
Don Gagne's avatar
Don Gagne committed
124 125 126 127 128
        qCDebug(FirmwareUpgradeVerboseLog) << "\tport name:" << info.portName();
        qCDebug(FirmwareUpgradeVerboseLog) << "\tdescription:" << info.description();
        qCDebug(FirmwareUpgradeVerboseLog) << "\tsystem location:" << info.systemLocation();
        qCDebug(FirmwareUpgradeVerboseLog) << "\tvendor ID:" << info.vendorIdentifier();
        qCDebug(FirmwareUpgradeVerboseLog) << "\tproduct ID:" << info.productIdentifier();
129
        
130
        if (info.canFlash()) {
131
            portInfo = info;
132 133 134 135 136 137 138
            return true;
        }
    }
    
    return false;
}

139
void PX4FirmwareUpgradeThreadWorker::_reboot(void)
140
{
141
    _bootloader->reboot();
142 143
}

144
void PX4FirmwareUpgradeThreadWorker::_flash(void)
145
{
146
    qCDebug(FirmwareUpgradeLog) << "PX4FirmwareUpgradeThreadWorker::_flash";
147

148
    if (!_bootloader->initFlashSequence()) {
149
        emit error(_bootloader->errorString());
150
        return;
151
    }
152

153
    if (_erase()) {
154
        emit status(tr("Programming new version..."));
155
        
156
        if (_bootloader->program(_controller->image())) {
157 158 159 160
            qCDebug(FirmwareUpgradeLog) << "Program complete";
            emit status("Program complete");
        } else {
            qCDebug(FirmwareUpgradeLog) << "Program failed:" << _bootloader->errorString();
161
            goto Error;
162 163
        }
        
164
        emit status(tr("Verifying program..."));
165
        
166
        if (_bootloader->verify(_controller->image())) {
167
            qCDebug(FirmwareUpgradeLog) << "Verify complete";
168
            emit status(tr("Verify complete"));
169 170
        } else {
            qCDebug(FirmwareUpgradeLog) << "Verify failed:" << _bootloader->errorString();
171
            goto Error;
172
        }
173
    }
174
    
175 176 177 178 179 180
    emit status(tr("Rebooting board"));
    _reboot();

    _bootloader->close();
    _bootloader->deleteLater();
    _bootloader = nullptr;
181 182
    
    emit flashComplete();
183 184 185 186 187 188 189 190 191

    return;

Error:
    emit error(_bootloader->errorString());
    _reboot();
    _bootloader->close();
    _bootloader->deleteLater();
    _bootloader = nullptr;
192 193
}

194
bool PX4FirmwareUpgradeThreadWorker::_erase(void)
195
{
196 197 198
    qCDebug(FirmwareUpgradeLog) << "PX4FirmwareUpgradeThreadWorker::_erase";
    
    emit eraseStarted();
199
    emit status(tr("Erasing previous program..."));
200
    
201
    if (_bootloader->erase()) {
202
        qCDebug(FirmwareUpgradeLog) << "Erase complete";
203
        emit status(tr("Erase complete"));
204 205
        emit eraseComplete();
        return true;
206
    } else {
207 208 209
        qCDebug(FirmwareUpgradeLog) << "Erase failed:" << _bootloader->errorString();
        emit error(_bootloader->errorString());
        return false;
210 211 212 213 214 215
    }
}

PX4FirmwareUpgradeThreadController::PX4FirmwareUpgradeThreadController(QObject* parent) :
    QObject(parent)
{
216 217
    _worker         = new PX4FirmwareUpgradeThreadWorker(this);
    _workerThread   = new QThread(this);
218 219
    _worker->moveToThread(_workerThread);
    
220 221 222 223
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::updateProgress,       this, &PX4FirmwareUpgradeThreadController::_updateProgress);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::foundBoard,           this, &PX4FirmwareUpgradeThreadController::_foundBoard);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::noBoardFound,         this, &PX4FirmwareUpgradeThreadController::_noBoardFound);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::boardGone,            this, &PX4FirmwareUpgradeThreadController::_boardGone);
224
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::foundBoardInfo,       this, &PX4FirmwareUpgradeThreadController::_foundBoardInfo);
225 226 227 228 229
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::error,                this, &PX4FirmwareUpgradeThreadController::_error);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::status,               this, &PX4FirmwareUpgradeThreadController::_status);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::eraseStarted,         this, &PX4FirmwareUpgradeThreadController::_eraseStarted);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::eraseComplete,        this, &PX4FirmwareUpgradeThreadController::_eraseComplete);
    connect(_worker, &PX4FirmwareUpgradeThreadWorker::flashComplete,        this, &PX4FirmwareUpgradeThreadController::_flashComplete);
230 231 232 233 234 235 236 237 238 239

    _workerThread->start();
    
    emit _initThreadWorker();
}

PX4FirmwareUpgradeThreadController::~PX4FirmwareUpgradeThreadController()
{
    _workerThread->quit();
    _workerThread->wait();
240 241
    
    delete _workerThread;
242 243
}

244
void PX4FirmwareUpgradeThreadController::startFindBoardLoop(void)
245
{
246 247
    qCDebug(FirmwareUpgradeLog) << "PX4FirmwareUpgradeThreadController::findBoard";
    emit _startFindBoardLoopOnThread();
248 249
}

250
void PX4FirmwareUpgradeThreadController::cancel(void)
251
{
252 253
    qCDebug(FirmwareUpgradeLog) << "PX4FirmwareUpgradeThreadController::cancel";
    emit _cancel();
254 255
}

256
void PX4FirmwareUpgradeThreadController::flash(const FirmwareImage* image)
257
{
258 259
    _image = image;
    emit _flashOnThread();
260
}