13#include <QtCore/QFile>
14#include <QtCore/QFileInfo>
15#include <QtCore/QJsonDocument>
16#include <QtCore/QJsonObject>
17#include <QtCore/QTextStream>
31 if (imageFilename.endsWith(
".bin")) {
33 return _binLoad(imageFilename);
34 }
else if (imageFilename.endsWith(
".px4")) {
36 return _px4Load(imageFilename);
37 }
else if (imageFilename.endsWith(
".apj")) {
39 return _px4Load(imageFilename);
40 }
else if (imageFilename.endsWith(
".ihx")) {
42 return _ihxLoad(imageFilename);
49bool FirmwareImage::_readByteFromStream(QTextStream& stream, uint8_t&
byte)
51 QString hex = stream.read(2);
53 if (hex.length() != 2) {
58 byte = (uint8_t)hex.toInt(&success, 16);
63bool FirmwareImage::_readWordFromStream(QTextStream& stream, uint16_t& word)
65 QString hex = stream.read(4);
67 if (hex.length() != 4) {
72 word = (uint16_t)hex.toInt(&success, 16);
77bool FirmwareImage::_readBytesFromStream(QTextStream& stream, uint8_t byteCount, QByteArray& bytes)
84 if (!_readByteFromStream(stream,
byte)) {
95bool FirmwareImage::_ihxLoad(
const QString& ihxFilename)
100 QFile ihxFile(ihxFilename);
101 if (!ihxFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
102 emit
statusMessage(QString(
"Unable to open firmware file %1, error: %2").arg(ihxFilename, ihxFile.errorString()));
106 QTextStream stream(&ihxFile);
109 if (stream.read(1) !=
":") {
110 emit
statusMessage(
"Incorrectly formatted .ihx file, line does not begin with :");
114 uint8_t blockByteCount;
120 if (!_readByteFromStream(stream, blockByteCount) ||
121 !_readWordFromStream(stream, address) ||
122 !_readByteFromStream(stream, recordType) ||
123 !_readBytesFromStream(stream, blockByteCount, bytes) ||
124 !_readByteFromStream(stream, crc)) {
125 emit
statusMessage(tr(
"Incorrectly formatted line in .ihx file, line too short"));
129 if (!(recordType == 0 || recordType == 1)) {
130 emit
statusMessage(tr(
"Unsupported record type in file: %1").arg(recordType));
134 if (recordType == 0) {
135 bool appendToLastBlock =
false;
139 if (_ihxBlocks.length()) {
140 int lastBlockIndex = _ihxBlocks.length() - 1;
142 if (_ihxBlocks[lastBlockIndex].address + _ihxBlocks[lastBlockIndex].bytes.length() == address) {
143 appendToLastBlock =
true;
147 if (appendToLastBlock) {
148 _ihxBlocks[_ihxBlocks.length() - 1].bytes += bytes;
152 IntelHexBlock_t block;
154 block.address = address;
158 qCDebug(FirmwareImageVerboseLog) << QString(
"_ihxLoad - new block - address:%1 size:%2 block:%3").arg(address).arg(blockByteCount).arg(
ihxBlockCount());
161 _imageSize += blockByteCount;
162 }
else if (recordType == 1) {
164 qCDebug(FirmwareImageLog) << QString(
"_ihxLoad - EOF");
179 if (boardId == firmwareId ) {
184 if (firmwareId == 9) result =
true;
192bool FirmwareImage::_px4Load(
const QString& imageFilename)
198 QFile px4File(imageFilename);
199 if (!px4File.open(QIODevice::ReadOnly | QIODevice::Text)) {
200 emit
statusMessage(tr(
"Unable to open firmware file %1, error: %2").arg(imageFilename, px4File.errorString()));
204 QByteArray bytes = px4File.readAll();
206 QJsonDocument doc = QJsonDocument::fromJson(bytes);
209 emit
statusMessage(tr(
"Supplied file is not a valid JSON document"));
213 QJsonObject px4Json = doc.object();
217 QStringList requiredKeys;
218 requiredKeys << _jsonBoardIdKey << _jsonImageKey << _jsonImageSizeKey;
226 QList<QJsonValue::Type> types;
227 keys << _jsonBoardIdKey << _jsonParamXmlSizeKey << _jsonParamXmlKey << _jsonAirframeXmlSizeKey << _jsonAirframeXmlKey << _jsonImageSizeKey << _jsonImageKey << _jsonMavAutopilotKey;
228 types << QJsonValue::Double << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::String << QJsonValue::Double << QJsonValue::String << QJsonValue::Double;
234 uint32_t firmwareBoardId = (uint32_t)px4Json.value(_jsonBoardIdKey).toInt();
236 emit
statusMessage(tr(
"Downloaded firmware board id does not match hardware board id: %1 != %2").arg(firmwareBoardId).arg(_boardId));
241 MAV_AUTOPILOT firmwareType = (MAV_AUTOPILOT)px4Json[_jsonMavAutopilotKey].toInt(MAV_AUTOPILOT_PX4);
250 QByteArray decompressedBytes;
251 bool success = _decompressJsonValue(px4Json,
253 _jsonParamXmlSizeKey,
258 QFile parameterFile(parameterFilename);
260 if (parameterFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
261 qint64 bytesWritten = parameterFile.write(decompressedBytes);
262 if (bytesWritten != decompressedBytes.length()) {
263 emit
statusMessage(tr(
"Write failed for parameter meta data file, error: %1").arg(parameterFile.errorString()));
264 parameterFile.close();
265 QFile::remove(parameterFilename);
267 parameterFile.close();
270 emit
statusMessage(tr(
"Unable to open parameter meta data file %1 for writing, error: %2").arg(parameterFilename, parameterFile.errorString()));
280 success = _decompressJsonValue(px4Json,
282 _jsonAirframeXmlSizeKey,
290 if (airframeFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
291 qint64 bytesWritten = airframeFile.write(decompressedBytes);
292 if (bytesWritten != decompressedBytes.length()) {
294 emit
statusMessage(tr(
"Write failed for airframe meta data file, error: %1").arg(airframeFile.errorString()));
295 airframeFile.close();
296 QFile::remove(airframeFilename);
298 airframeFile.close();
301 emit
statusMessage(tr(
"Unable to open airframe meta data file %1 for writing, error: %2").arg(airframeFilename, airframeFile.errorString()));
306 _imageSize = px4Json.value(QString(
"image_size")).toInt();
307 success = _decompressJsonValue(px4Json,
317 while ((decompressedBytes.length() % 4) != 0) {
318 decompressedBytes.append(
static_cast<char>(
static_cast<unsigned char>(0xFF)));
322 QDir imageDir = QFileInfo(imageFilename).dir();
323 QString decompressFilename = imageDir.filePath(
"PX4FlashUpgrade.bin");
326 if (!
decompressFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
327 emit
statusMessage(tr(
"Unable to open decompressed file %1 for writing, error: %2").arg(decompressFilename,
decompressFile.errorString()));
332 if (bytesWritten != decompressedBytes.length()) {
338 _binFilename = decompressFilename;
344bool FirmwareImage::_decompressJsonValue(
const QJsonObject& jsonObject,
345 const QByteArray& jsonDocBytes,
346 const QString& sizeKey,
347 const QString& bytesKey,
348 QByteArray& decompressedBytes)
351 if (!jsonObject.contains(sizeKey)) {
352 emit
statusMessage(QString(
"Firmware file missing %1 key").arg(sizeKey));
355 int decompressedSize = jsonObject.value(QString(sizeKey)).toInt();
356 if (decompressedSize == 0) {
357 emit
statusMessage(tr(
"Firmware file has invalid decompressed size for %1").arg(sizeKey));
367 QStringList parts = QString(jsonDocBytes).split(QString(
"\"%1\": \"").arg(bytesKey));
368 if (parts.length() == 1) {
369 emit
statusMessage(tr(
"Could not find compressed bytes for %1 in Firmware file").arg(bytesKey));
372 parts = parts.last().split(
"\"");
373 if (parts.length() == 1) {
374 emit
statusMessage(tr(
"Incorrectly formed compressed bytes section for %1 in Firmware file").arg(bytesKey));
380 raw.append((
unsigned char)((decompressedSize >> 24) & 0xFF));
381 raw.append((
unsigned char)((decompressedSize >> 16) & 0xFF));
382 raw.append((
unsigned char)((decompressedSize >> 8) & 0xFF));
383 raw.append((
unsigned char)((decompressedSize >> 0) & 0xFF));
385 QByteArray raw64 = parts.first().toUtf8();
386 raw.append(QByteArray::fromBase64(raw64));
387 decompressedBytes = qUncompress(raw);
389 if (decompressedBytes.length() == 0) {
390 emit
statusMessage(tr(
"Firmware file has 0 length %1").arg(bytesKey));
393 if (decompressedBytes.length() != decompressedSize) {
394 emit
statusMessage(tr(
"Size for decompressed %1 does not match stored size: Expected(%1) Actual(%2)").arg(decompressedSize).arg(decompressedBytes.length()));
403 return _ihxBlocks.length();
412 address = _ihxBlocks[index].address;
413 bytes = _ihxBlocks[index].bytes;
420bool FirmwareImage::_binLoad(
const QString& imageFilename)
422 QFile binFile(imageFilename);
423 if (!binFile.open(QIODevice::ReadOnly)) {
424 emit
statusMessage(tr(
"Unabled to open firmware file %1, %2").arg(imageFilename, binFile.errorString()));
428 _imageSize = (uint32_t)binFile.size();
432 _binFilename = imageFilename;
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static const int boardIDPX4FMUV3
Support for Intel Hex firmware file.
bool isCompatible(uint32_t boardId, uint32_t firmwareId)
bool load(const QString &imageFilename, uint32_t boardId)
void statusMessage(const QString &warningtring)
bool ihxGetBlock(uint16_t index, uint16_t &address, QByteArray &bytes) const
FirmwareImage(QObject *parent=0)
uint16_t ihxBlockCount(void) const
FirmwarePlugin * firmwarePluginForAutopilot(MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType)
static FirmwarePluginManager * instance()
The FirmwarePlugin class represents the methods and objects which are specific to a certain Firmware ...
void cacheParameterMetaDataFile(const QString &metaDataFile)
static QString cachedParameterMetaDataFile()
static QString cachedAirframeMetaDataFile()
bool validateKeyTypes(const QJsonObject &jsonObject, const QStringList &keys, const QList< QJsonValue::Type > &types, QString &errorString)
bool validateRequiredKeys(const QJsonObject &jsonObject, const QStringList &keys, QString &errorString)
Validates that all listed keys are present in the object.
bool decompressFile(const QString &inputPath, const QString &outputPath, Format format, ProgressCallback progress, qint64 maxDecompressedBytes)