Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 79 additions & 66 deletions src/Vehicle/VehicleSetup/FirmwareImage.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "FirmwareImage.h"
#include "JsonParsing.h"
#include "QGCApplication.h"

#include <QtCore/QDir>

#include "Bootloader.h"
#include "FirmwarePlugin.h"
#include "FirmwarePluginManager.h"
#include "Bootloader.h"
#include "JsonParsing.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"

#include <QtCore/QDir>

QGC_LOGGING_CATEGORY(FirmwareImageLog, "Vehicle.VehicleSetup.FirmwareImage")
QGC_LOGGING_CATEGORY(FirmwareImageVerboseLog, "Vehicle.VehicleSetup.FirmwareImage.Verbose")
#include <QtCore/QFile>
Expand All @@ -16,12 +17,7 @@ QGC_LOGGING_CATEGORY(FirmwareImageVerboseLog, "Vehicle.VehicleSetup.FirmwareImag
#include <QtCore/QJsonObject>
#include <QtCore/QTextStream>

FirmwareImage::FirmwareImage(QObject* parent) :
QObject(parent),
_imageSize(0)
{

}
FirmwareImage::FirmwareImage(QObject* parent) : QObject(parent), _imageSize(0) {}

bool FirmwareImage::load(const QString& imageFilename, uint32_t boardId)
{
Expand Down Expand Up @@ -55,7 +51,7 @@ bool FirmwareImage::_readByteFromStream(QTextStream& stream, uint8_t& byte)
}

bool success;
byte = (uint8_t)hex.toInt(&success, 16);
byte = (uint8_t) hex.toInt(&success, 16);

return success;
}
Expand All @@ -69,7 +65,7 @@ bool FirmwareImage::_readWordFromStream(QTextStream& stream, uint16_t& word)
}

bool success;
word = (uint16_t)hex.toInt(&success, 16);
word = (uint16_t) hex.toInt(&success, 16);

return success;
}
Expand Down Expand Up @@ -99,7 +95,8 @@ bool FirmwareImage::_ihxLoad(const QString& ihxFilename)

QFile ihxFile(ihxFilename);
if (!ihxFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
emit statusMessage(QString("Unable to open firmware file %1, error: %2").arg(ihxFilename, ihxFile.errorString()));
emit statusMessage(
QString("Unable to open firmware file %1, error: %2").arg(ihxFilename, ihxFile.errorString()));
return false;
}

Expand All @@ -111,16 +108,14 @@ bool FirmwareImage::_ihxLoad(const QString& ihxFilename)
return false;
}

uint8_t blockByteCount;
uint16_t address;
uint8_t recordType;
QByteArray bytes;
uint8_t crc;
uint8_t blockByteCount;
uint16_t address;
uint8_t recordType;
QByteArray bytes;
uint8_t crc;

if (!_readByteFromStream(stream, blockByteCount) ||
!_readWordFromStream(stream, address) ||
!_readByteFromStream(stream, recordType) ||
!_readBytesFromStream(stream, blockByteCount, bytes) ||
if (!_readByteFromStream(stream, blockByteCount) || !_readWordFromStream(stream, address) ||
!_readByteFromStream(stream, recordType) || !_readBytesFromStream(stream, blockByteCount, bytes) ||
!_readByteFromStream(stream, crc)) {
emit statusMessage(tr("Incorrectly formatted line in .ihx file, line too short"));
return false;
Expand All @@ -147,15 +142,19 @@ bool FirmwareImage::_ihxLoad(const QString& ihxFilename)
if (appendToLastBlock) {
_ihxBlocks[_ihxBlocks.length() - 1].bytes += bytes;
// Too noisy even for verbose
//qCDebug(FirmwareImageVerboseLog) << QString("_ihxLoad - append - address:%1 size:%2 block:%3").arg(address).arg(blockByteCount).arg(ihxBlockCount());
// qCDebug(FirmwareImageVerboseLog) << QString("_ihxLoad - append - address:%1 size:%2
// block:%3").arg(address).arg(blockByteCount).arg(ihxBlockCount());
} else {
IntelHexBlock_t block;

block.address = address;
block.bytes = bytes;

_ihxBlocks += block;
qCDebug(FirmwareImageVerboseLog) << QString("_ihxLoad - new block - address:%1 size:%2 block:%3").arg(address).arg(blockByteCount).arg(ihxBlockCount());
qCDebug(FirmwareImageVerboseLog) << QString("_ihxLoad - new block - address:%1 size:%2 block:%3")
.arg(address)
.arg(blockByteCount)
.arg(ihxBlockCount());
}

_imageSize += blockByteCount;
Expand All @@ -174,17 +173,19 @@ bool FirmwareImage::_ihxLoad(const QString& ihxFilename)
return true;
}

bool FirmwareImage::isCompatible(uint32_t boardId, uint32_t firmwareId) {
bool FirmwareImage::isCompatible(uint32_t boardId, uint32_t firmwareId)
{
bool result = false;
if (boardId == firmwareId ) {
if (boardId == firmwareId) {
result = true;
}
switch(boardId) {
case Bootloader::boardIDPX4FMUV3:
if (firmwareId == 9) result = true;
break;
default:
break;
switch (boardId) {
case Bootloader::boardIDPX4FMUV3:
if (firmwareId == 9)
result = true;
break;
default:
break;
}
return result;
}
Expand Down Expand Up @@ -224,21 +225,25 @@ bool FirmwareImage::_px4Load(const QString& imageFilename)
// Make sure the keys are the correct type
QStringList keys;
QList<QJsonValue::Type> types;
keys << _jsonBoardIdKey << _jsonParamXmlSizeKey << _jsonParamXmlKey << _jsonAirframeXmlSizeKey << _jsonAirframeXmlKey << _jsonImageSizeKey << _jsonImageKey << _jsonMavAutopilotKey;
types << QJsonValue::Double << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::String << QJsonValue::Double;
keys << _jsonBoardIdKey << _jsonParamXmlSizeKey << _jsonParamXmlKey << _jsonAirframeXmlSizeKey
<< _jsonAirframeXmlKey << _jsonImageSizeKey << _jsonImageKey << _jsonMavAutopilotKey;
types << QJsonValue::Double << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::String
<< QJsonValue::Double << QJsonValue::String << QJsonValue::Double;
if (!JsonParsing::validateKeyTypes(px4Json, keys, types, errorString)) {
emit statusMessage(tr("Firmware file has invalid key: %1").arg(errorString));
return false;
}

uint32_t firmwareBoardId = (uint32_t)px4Json.value(_jsonBoardIdKey).toInt();
uint32_t firmwareBoardId = (uint32_t) px4Json.value(_jsonBoardIdKey).toInt();
if (!isCompatible(_boardId, firmwareBoardId)) {
emit statusMessage(tr("Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardId).arg(_boardId));
emit statusMessage(tr("Downloaded firmware board id does not match hardware board id: %1 != %2")
.arg(firmwareBoardId)
.arg(_boardId));
return false;
}

// What firmware type is this?
MAV_AUTOPILOT firmwareType = (MAV_AUTOPILOT)px4Json[_jsonMavAutopilotKey].toInt(MAV_AUTOPILOT_PX4);
MAV_AUTOPILOT firmwareType = (MAV_AUTOPILOT) px4Json[_jsonMavAutopilotKey].toInt(MAV_AUTOPILOT_PX4);

// NOTE: PX4 firmware currently embeds parameter metadata as XML
// ("parameter_xml" key), but the metadata system now expects JSON.
Expand All @@ -260,55 +265,60 @@ bool FirmwareImage::_px4Load(const QString& imageFilename)
if (parameterFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qint64 bytesWritten = parameterFile.write(decompressedBytes);
if (bytesWritten != decompressedBytes.length()) {
emit statusMessage(tr("Write failed for parameter meta data file, error: %1").arg(parameterFile.errorString()));
emit statusMessage(
tr("Write failed for parameter meta data file, error: %1").arg(parameterFile.errorString()));
parameterFile.close();
QFile::remove(parameterFilename);
} else {
parameterFile.close();
}
} else {
emit statusMessage(tr("Unable to open parameter meta data file %1 for writing, error: %2").arg(parameterFilename, parameterFile.errorString()));
emit statusMessage(tr("Unable to open parameter meta data file %1 for writing, error: %2")
.arg(parameterFilename, parameterFile.errorString()));
}

FirmwarePlugin *fwPlugin = FirmwarePluginManager::instance()->firmwarePluginForAutopilot(firmwareType, MAV_TYPE_GENERIC);
FirmwarePlugin* fwPlugin =
FirmwarePluginManager::instance()->firmwarePluginForAutopilot(firmwareType, MAV_TYPE_GENERIC);
if (fwPlugin) {
fwPlugin->cacheParameterMetaDataFile(parameterFilename);
}
}

// Decompress the airframe xml and save to file
success = _decompressJsonValue(px4Json, // JSON object
bytes, // Raw bytes of JSON document
_jsonAirframeXmlSizeKey, // key which holds byte size
_jsonAirframeXmlKey, // key which holds compressed bytes
decompressedBytes); // Returned decompressed bytes
success = _decompressJsonValue(px4Json, // JSON object
bytes, // Raw bytes of JSON document
_jsonAirframeXmlSizeKey, // key which holds byte size
_jsonAirframeXmlKey, // key which holds compressed bytes
decompressedBytes); // Returned decompressed bytes
if (success) {
QString airframeFilename = QGCApplication::cachedAirframeMetaDataFile();
//qDebug() << airframeFilename;
// qDebug() << airframeFilename;
QFile airframeFile(QGCApplication::cachedAirframeMetaDataFile());

if (airframeFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qint64 bytesWritten = airframeFile.write(decompressedBytes);
if (bytesWritten != decompressedBytes.length()) {
// FIXME: What about these warnings?
emit statusMessage(tr("Write failed for airframe meta data file, error: %1").arg(airframeFile.errorString()));
emit statusMessage(
tr("Write failed for airframe meta data file, error: %1").arg(airframeFile.errorString()));
airframeFile.close();
QFile::remove(airframeFilename);
} else {
airframeFile.close();
}
} else {
emit statusMessage(tr("Unable to open airframe meta data file %1 for writing, error: %2").arg(airframeFilename, airframeFile.errorString()));
emit statusMessage(tr("Unable to open airframe meta data file %1 for writing, error: %2")
.arg(airframeFilename, airframeFile.errorString()));
}
}

// Decompress the image and save to file
_imageSize = px4Json.value(QString("image_size")).toInt();
success = _decompressJsonValue(px4Json, // JSON object
bytes, // Raw bytes of JSON document
_jsonImageSizeKey, // key which holds byte size
_jsonImageKey, // key which holds compressed bytes
decompressedBytes); // Returned decompressed bytes
success = _decompressJsonValue(px4Json, // JSON object
bytes, // Raw bytes of JSON document
_jsonImageSizeKey, // key which holds byte size
_jsonImageKey, // key which holds compressed bytes
decompressedBytes); // Returned decompressed bytes
if (!success) {
return false;
}
Expand All @@ -324,7 +334,8 @@ bool FirmwareImage::_px4Load(const QString& imageFilename)

QFile decompressFile(decompressFilename);
if (!decompressFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
emit statusMessage(tr("Unable to open decompressed file %1 for writing, error: %2").arg(decompressFilename, decompressFile.errorString()));
emit statusMessage(tr("Unable to open decompressed file %1 for writing, error: %2")
.arg(decompressFilename, decompressFile.errorString()));
return false;
}

Expand All @@ -341,11 +352,11 @@ bool FirmwareImage::_px4Load(const QString& imageFilename)
}

/// Decompress a set of bytes stored in a Json document.
bool FirmwareImage::_decompressJsonValue(const QJsonObject& jsonObject, ///< JSON object
const QByteArray& jsonDocBytes, ///< Raw bytes of JSON document
const QString& sizeKey, ///< key which holds byte size
const QString& bytesKey, ///< key which holds compress bytes
QByteArray& decompressedBytes) ///< Returned decompressed bytes
bool FirmwareImage::_decompressJsonValue(const QJsonObject& jsonObject, ///< JSON object
const QByteArray& jsonDocBytes, ///< Raw bytes of JSON document
const QString& sizeKey, ///< key which holds byte size
const QString& bytesKey, ///< key which holds compress bytes
QByteArray& decompressedBytes) ///< Returned decompressed bytes
{
// Validate decompressed size key
if (!jsonObject.contains(sizeKey)) {
Expand Down Expand Up @@ -377,10 +388,10 @@ bool FirmwareImage::_decompressJsonValue(const QJsonObject& jsonObject, ///< J

// Store decompressed size as first four bytes. This is required by qUncompress routine.
QByteArray raw;
raw.append((unsigned char)((decompressedSize >> 24) & 0xFF));
raw.append((unsigned char)((decompressedSize >> 16) & 0xFF));
raw.append((unsigned char)((decompressedSize >> 8) & 0xFF));
raw.append((unsigned char)((decompressedSize >> 0) & 0xFF));
raw.append((unsigned char) ((decompressedSize >> 24) & 0xFF));
raw.append((unsigned char) ((decompressedSize >> 16) & 0xFF));
raw.append((unsigned char) ((decompressedSize >> 8) & 0xFF));
raw.append((unsigned char) ((decompressedSize >> 0) & 0xFF));

QByteArray raw64 = parts.first().toUtf8();
raw.append(QByteArray::fromBase64(raw64));
Expand All @@ -391,7 +402,9 @@ bool FirmwareImage::_decompressJsonValue(const QJsonObject& jsonObject, ///< J
return false;
}
if (decompressedBytes.length() != decompressedSize) {
emit statusMessage(tr("Size for decompressed %1 does not match stored size: Expected(%1) Actual(%2)").arg(decompressedSize).arg(decompressedBytes.length()));
emit statusMessage(tr("Size for decompressed %1 does not match stored size: Expected(%1) Actual(%2)")
.arg(decompressedSize)
.arg(decompressedBytes.length()));
return false;
}

Expand Down Expand Up @@ -425,7 +438,7 @@ bool FirmwareImage::_binLoad(const QString& imageFilename)
return false;
}

_imageSize = (uint32_t)binFile.size();
_imageSize = (uint32_t) binFile.size();

binFile.close();

Expand Down
48 changes: 23 additions & 25 deletions src/Vehicle/VehicleSetup/FirmwareImage.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once

#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QTextStream>

/// \brief Support for Intel Hex firmware file
Expand All @@ -13,7 +13,7 @@ class FirmwareImage : public QObject
Q_OBJECT

public:
FirmwareImage(QObject *parent = 0);
FirmwareImage(QObject* parent = 0);

/// Loads the specified image file. Supported formats: .px4, .bin, .ihx.
/// Emits errorMesssage and statusMessage signals while loading.
Expand Down Expand Up @@ -57,29 +57,27 @@ class FirmwareImage : public QObject
bool _readWordFromStream(QTextStream& stream, uint16_t& word);
bool _readBytesFromStream(QTextStream& stream, uint8_t byteCount, QByteArray& bytes);

bool _decompressJsonValue(const QJsonObject& jsonObject,
const QByteArray& jsonDocBytes,
const QString& sizeKey,
const QString& bytesKey,
QByteArray& decompressedBytes);
bool _decompressJsonValue(const QJsonObject& jsonObject, const QByteArray& jsonDocBytes, const QString& sizeKey,
const QString& bytesKey, QByteArray& decompressedBytes);

typedef struct {
uint16_t address;
QByteArray bytes;
typedef struct
{
uint16_t address;
QByteArray bytes;
} IntelHexBlock_t;

bool _binFormat;
uint32_t _boardId;
QString _binFilename;
QList<IntelHexBlock_t> _ihxBlocks;
uint32_t _imageSize;

static constexpr const char* _jsonBoardIdKey = "board_id";
static constexpr const char* _jsonParamXmlSizeKey = "parameter_xml_size";
static constexpr const char* _jsonParamXmlKey = "parameter_xml";
static constexpr const char* _jsonAirframeXmlSizeKey = "airframe_xml_size";
static constexpr const char* _jsonAirframeXmlKey = "airframe_xml";
static constexpr const char* _jsonImageSizeKey = "image_size";
static constexpr const char* _jsonImageKey = "image";
static constexpr const char* _jsonMavAutopilotKey = "mav_autopilot";
bool _binFormat;
uint32_t _boardId;
QString _binFilename;
QList<IntelHexBlock_t> _ihxBlocks;
uint32_t _imageSize;

static constexpr const char* _jsonBoardIdKey = "board_id";
static constexpr const char* _jsonParamXmlSizeKey = "parameter_xml_size";
static constexpr const char* _jsonParamXmlKey = "parameter_xml";
static constexpr const char* _jsonAirframeXmlSizeKey = "airframe_xml_size";
static constexpr const char* _jsonAirframeXmlKey = "airframe_xml";
static constexpr const char* _jsonImageSizeKey = "image_size";
static constexpr const char* _jsonImageKey = "image";
static constexpr const char* _jsonMavAutopilotKey = "mav_autopilot";
};
Loading
Loading