Unverified Commit 4450945e authored by Don Gagne's avatar Don Gagne Committed by GitHub

Merge pull request #8872 from DonLakeFlyer/CompInfoParameterMetaData

COMPONENT_INFORMATION work
parents ef99212f 1c95fb26
...@@ -644,6 +644,7 @@ HEADERS += \ ...@@ -644,6 +644,7 @@ HEADERS += \
src/QGCQGeoCoordinate.h \ src/QGCQGeoCoordinate.h \
src/QGCTemporaryFile.h \ src/QGCTemporaryFile.h \
src/QGCToolbox.h \ src/QGCToolbox.h \
src/QGCZlib.h \
src/QmlControls/AppMessages.h \ src/QmlControls/AppMessages.h \
src/QmlControls/EditPositionDialogController.h \ src/QmlControls/EditPositionDialogController.h \
src/QmlControls/FlightPathSegment.h \ src/QmlControls/FlightPathSegment.h \
...@@ -859,6 +860,7 @@ SOURCES += \ ...@@ -859,6 +860,7 @@ SOURCES += \
src/QGCQGeoCoordinate.cc \ src/QGCQGeoCoordinate.cc \
src/QGCTemporaryFile.cc \ src/QGCTemporaryFile.cc \
src/QGCToolbox.cc \ src/QGCToolbox.cc \
src/QGCZlib.cc \
src/QmlControls/AppMessages.cc \ src/QmlControls/AppMessages.cc \
src/QmlControls/EditPositionDialogController.cc \ src/QmlControls/EditPositionDialogController.cc \
src/QmlControls/FlightPathSegment.cc \ src/QmlControls/FlightPathSegment.cc \
......
...@@ -337,5 +337,7 @@ ...@@ -337,5 +337,7 @@
<file alias="APMArduSubMockLink.params">src/comm/APMArduSubMockLink.params</file> <file alias="APMArduSubMockLink.params">src/comm/APMArduSubMockLink.params</file>
<file alias="PX4MockLink.params">src/comm/PX4MockLink.params</file> <file alias="PX4MockLink.params">src/comm/PX4MockLink.params</file>
<file alias="Version.MetaData.json">src/comm/MockLink.Version.MetaData.json</file> <file alias="Version.MetaData.json">src/comm/MockLink.Version.MetaData.json</file>
<file alias="Version.MetaData.json.gz">src/comm/MockLink.Version.MetaData.json.gz</file>
<file alias="Parameter.MetaData.json">src/comm/MockLink.Parameter.MetaData.json</file>
</qresource> </qresource>
</RCC> </RCC>
...@@ -84,6 +84,40 @@ const FactMetaData::AppSettingsTranslation_s FactMetaData::_rgAppSettingsTransla ...@@ -84,6 +84,40 @@ const FactMetaData::AppSettingsTranslation_s FactMetaData::_rgAppSettingsTransla
{ "g", "lbs", FactMetaData::UnitWeight, UnitsSettings::WeightUnitsLbs, FactMetaData::_gramsToPunds, FactMetaData::_poundsToGrams }, { "g", "lbs", FactMetaData::UnitWeight, UnitsSettings::WeightUnitsLbs, FactMetaData::_gramsToPunds, FactMetaData::_poundsToGrams },
}; };
const char* FactMetaData::_rgKnownTypeStrings[] = {
"Uint8",
"Int8",
"Uint16",
"Int16",
"Uint32",
"Int32",
"Uint64",
"Int64",
"Float",
"Double",
"String",
"Bool",
"ElapsedSeconds",
"Custom",
};
const FactMetaData::ValueType_t FactMetaData::_rgKnownValueTypes[] = {
valueTypeUint8,
valueTypeInt8,
valueTypeUint16,
valueTypeInt16,
valueTypeUint32,
valueTypeInt32,
valueTypeUint64,
valueTypeInt64,
valueTypeFloat,
valueTypeDouble,
valueTypeString,
valueTypeBool,
valueTypeElapsedTimeInSeconds,
valueTypeCustom,
};
const char* FactMetaData::_decimalPlacesJsonKey = "decimalPlaces"; const char* FactMetaData::_decimalPlacesJsonKey = "decimalPlaces";
const char* FactMetaData::_nameJsonKey = "name"; const char* FactMetaData::_nameJsonKey = "name";
const char* FactMetaData::_typeJsonKey = "type"; const char* FactMetaData::_typeJsonKey = "type";
...@@ -880,44 +914,11 @@ void FactMetaData::setRawUnits(const QString& rawUnits) ...@@ -880,44 +914,11 @@ void FactMetaData::setRawUnits(const QString& rawUnits)
FactMetaData::ValueType_t FactMetaData::stringToType(const QString& typeString, bool& unknownType) FactMetaData::ValueType_t FactMetaData::stringToType(const QString& typeString, bool& unknownType)
{ {
QStringList knownTypeStrings;
QList<ValueType_t> knownTypes;
unknownType = false; unknownType = false;
knownTypeStrings << QStringLiteral("Uint8") for (size_t i=0; i<sizeof(_rgKnownTypeStrings)/sizeof(_rgKnownTypeStrings[0]); i++) {
<< QStringLiteral("Int8") if (typeString.compare(_rgKnownTypeStrings[i], Qt::CaseInsensitive) == 0) {
<< QStringLiteral("Uint16") return _rgKnownValueTypes[i];
<< QStringLiteral("Int16")
<< QStringLiteral("Uint32")
<< QStringLiteral("Int32")
<< QStringLiteral("Uint64")
<< QStringLiteral("Int64")
<< QStringLiteral("Float")
<< QStringLiteral("Double")
<< QStringLiteral("String")
<< QStringLiteral("Bool")
<< QStringLiteral("ElapsedSeconds")
<< QStringLiteral("Custom");
knownTypes << valueTypeUint8
<< valueTypeInt8
<< valueTypeUint16
<< valueTypeInt16
<< valueTypeUint32
<< valueTypeInt32
<< valueTypeUint64
<< valueTypeInt64
<< valueTypeFloat
<< valueTypeDouble
<< valueTypeString
<< valueTypeBool
<< valueTypeElapsedTimeInSeconds
<< valueTypeCustom;
for (int i=0; i<knownTypeStrings.count(); i++) {
if (knownTypeStrings[i].compare(typeString, Qt::CaseInsensitive) == 0) {
return knownTypes[i];
} }
} }
...@@ -926,6 +927,17 @@ FactMetaData::ValueType_t FactMetaData::stringToType(const QString& typeString, ...@@ -926,6 +927,17 @@ FactMetaData::ValueType_t FactMetaData::stringToType(const QString& typeString,
return valueTypeDouble; return valueTypeDouble;
} }
QString FactMetaData::typeToString(ValueType_t type)
{
for (size_t i=0; i<sizeof(_rgKnownTypeStrings)/sizeof(_rgKnownTypeStrings[0]); i++) {
if (type == _rgKnownValueTypes[i]) {
return _rgKnownTypeStrings[i];
}
}
return QStringLiteral("UnknownType%1").arg(type);
}
size_t FactMetaData::typeToSize(ValueType_t type) size_t FactMetaData::typeToSize(ValueType_t type)
{ {
switch (type) { switch (type) {
......
...@@ -194,6 +194,7 @@ public: ...@@ -194,6 +194,7 @@ public:
static const int kUnknownDecimalPlaces = -1; ///< Number of decimal places to specify is not known static const int kUnknownDecimalPlaces = -1; ///< Number of decimal places to specify is not known
static ValueType_t stringToType(const QString& typeString, bool& unknownType); static ValueType_t stringToType(const QString& typeString, bool& unknownType);
static QString typeToString(ValueType_t type);
static size_t typeToSize(ValueType_t type); static size_t typeToSize(ValueType_t type);
static const char* qgcFileType; static const char* qgcFileType;
...@@ -342,6 +343,9 @@ private: ...@@ -342,6 +343,9 @@ private:
static const AppSettingsTranslation_s _rgAppSettingsTranslations[]; static const AppSettingsTranslation_s _rgAppSettingsTranslations[];
static const char* _rgKnownTypeStrings[];
static const ValueType_t _rgKnownValueTypes[];
static const char* _nameJsonKey; static const char* _nameJsonKey;
static const char* _decimalPlacesJsonKey; static const char* _decimalPlacesJsonKey;
static const char* _typeJsonKey; static const char* _typeJsonKey;
......
...@@ -401,7 +401,95 @@ void PX4ParameterMetaData::loadParameterFactMetaDataFile(const QString& metaData ...@@ -401,7 +401,95 @@ void PX4ParameterMetaData::loadParameterFactMetaDataFile(const QString& metaData
} }
xml.readNext(); xml.readNext();
} }
#ifdef GENERATE_PARAMETER_JSON
_generateParameterJson();
#endif
}
#ifdef GENERATE_PARAMETER_JSON
void _jsonWriteLine(QFile& file, int indent, const QString& line)
{
while (indent--) {
file.write(" ");
}
file.write(line.toLocal8Bit().constData());
file.write("\n");
}
void PX4ParameterMetaData::_generateParameterJson()
{
qCDebug(ParameterManagerLog) << "PX4ParameterMetaData::_generateParameterJson";
int indentLevel = 0;
QFile jsonFile(QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath("parameter.json"));
jsonFile.open(QFile::WriteOnly | QFile::Truncate | QFile::Text);
_jsonWriteLine(jsonFile, indentLevel++, "{");
_jsonWriteLine(jsonFile, indentLevel, "\"version\": 1,");
_jsonWriteLine(jsonFile, indentLevel, "\"uid\": 1,");
_jsonWriteLine(jsonFile, indentLevel, "\"scope\": \"Firmware\",");
_jsonWriteLine(jsonFile, indentLevel++, "\"parameters\": [");
int keyIndex = 0;
for (const QString& paramName: _mapParameterName2FactMetaData.keys()) {
const FactMetaData* metaData = _mapParameterName2FactMetaData[paramName];
_jsonWriteLine(jsonFile, indentLevel++, "{");
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"name\": \"%1\",").arg(paramName));
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"type\": \"%1\",").arg(metaData->typeToString(metaData->type())));
if (!metaData->group().isEmpty()) {
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"group\": \"%1\",").arg(metaData->group()));
}
if (!metaData->category().isEmpty()) {
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"category\": \"%1\",").arg(metaData->category()));
}
if (!metaData->shortDescription().isEmpty()) {
QString text = metaData->shortDescription();
text.replace("\"", "\\\"");
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"shortDescription\": \"%1\",").arg(text));
}
if (!metaData->longDescription().isEmpty()) {
QString text = metaData->longDescription();
text.replace("\"", "\\\"");
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"longDescription\": \"%1\",").arg(text));
}
if (!metaData->rawUnits().isEmpty()) {
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"units\": \"%1\",").arg(metaData->rawUnits()));
}
if (metaData->defaultValueAvailable()) {
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"defaultValue\": %1,").arg(metaData->rawDefaultValue().toDouble()));
}
if (!qIsNaN(metaData->rawIncrement())) {
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"increment\": %1,").arg(metaData->rawIncrement()));
}
if (metaData->enumValues().count()) {
_jsonWriteLine(jsonFile, indentLevel++, "\"values\": [");
for (int i=0; i<metaData->enumValues().count(); i++) {
_jsonWriteLine(jsonFile, indentLevel++, "{");
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"value\": %1,").arg(metaData->enumValues()[i].toDouble()));
QString text = metaData->enumStrings()[i];
text.replace("\"", "\\\"");
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"description\": \"%1\"").arg(text));
_jsonWriteLine(jsonFile, --indentLevel, QStringLiteral("}%1").arg(i == metaData->enumValues().count() - 1 ? "" : ","));
}
_jsonWriteLine(jsonFile, --indentLevel, "],");
}
if (metaData->vehicleRebootRequired()) {
_jsonWriteLine(jsonFile, indentLevel, "\"rebootRequired\": true,");
}
if (metaData->volatileValue()) {
_jsonWriteLine(jsonFile, indentLevel, "\"volatile\": true,");
}
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"decimalPlaces\": \"%1\",").arg(metaData->decimalPlaces()));
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"minValue\": %1,").arg(metaData->rawMin().toDouble()));
_jsonWriteLine(jsonFile, indentLevel, QStringLiteral("\"maxValue\": %1").arg(metaData->rawMax().toDouble()));
_jsonWriteLine(jsonFile, --indentLevel, QStringLiteral("}%1").arg(++keyIndex == _mapParameterName2FactMetaData.keys().count() ? "" : ","));
}
_jsonWriteLine(jsonFile, --indentLevel, "]");
_jsonWriteLine(jsonFile, --indentLevel, "}");
} }
#endif
FactMetaData* PX4ParameterMetaData::getMetaDataForFact(const QString& name, MAV_TYPE vehicleType) FactMetaData* PX4ParameterMetaData::getMetaDataForFact(const QString& name, MAV_TYPE vehicleType)
{ {
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
Q_DECLARE_LOGGING_CATEGORY(PX4ParameterMetaDataLog) Q_DECLARE_LOGGING_CATEGORY(PX4ParameterMetaDataLog)
//#define GENERATE_PARAMETER_JSON
/// Loads and holds parameter fact meta data for PX4 stack /// Loads and holds parameter fact meta data for PX4 stack
class PX4ParameterMetaData : public QObject class PX4ParameterMetaData : public QObject
{ {
...@@ -52,6 +54,10 @@ private: ...@@ -52,6 +54,10 @@ private:
QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool* convertOk); QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool* convertOk);
static void _outputFileWarning(const QString& metaDataFile, const QString& error1, const QString& error2); static void _outputFileWarning(const QString& metaDataFile, const QString& error1, const QString& error2);
#ifdef GENERATE_PARAMETER_JSON
void _generateParameterJson();
#endif
bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded
QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData
}; };
......
...@@ -225,11 +225,27 @@ bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QSt ...@@ -225,11 +225,27 @@ bool JsonHelper::isJsonFile(const QByteArray& bytes, QJsonDocument& jsonDoc, QSt
if (parseError.error == QJsonParseError::NoError) { if (parseError.error == QJsonParseError::NoError) {
return true; return true;
} else { } else {
int startPos = qMax(0, parseError.offset - 100);
int length = qMin(bytes.count() - startPos, 200);
qDebug() << QStringLiteral("Json read error '%1'").arg(bytes.mid(startPos, length).constData());
errorString = parseError.errorString(); errorString = parseError.errorString();
return false; return false;
} }
} }
bool JsonHelper::isJsonFile(const QString& fileName, QJsonDocument& jsonDoc, QString& errorString)
{
QFile jsonFile(fileName);
if (!jsonFile.open(QFile::ReadOnly)) {
errorString = tr("File open failed: file:error %1 %2").arg(jsonFile.fileName()).arg(jsonFile.errorString());
return false;
}
QByteArray jsonBytes = jsonFile.readAll();
jsonFile.close();
return isJsonFile(jsonBytes, jsonDoc, errorString);
}
bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject& jsonObject, bool JsonHelper::validateInternalQGCJsonFile(const QJsonObject& jsonObject,
const QString& expectedFileType, const QString& expectedFileType,
int minSupportedVersion, int minSupportedVersion,
......
...@@ -26,6 +26,12 @@ class JsonHelper ...@@ -26,6 +26,12 @@ class JsonHelper
Q_DECLARE_TR_FUNCTIONS(JsonHelper) Q_DECLARE_TR_FUNCTIONS(JsonHelper)
public: public:
/// Determines is the specified file is a json file
/// @return true: file is json, false: file is not json
static bool isJsonFile(const QString& fileName, ///< filename
QJsonDocument& jsonDoc, ///< returned json document
QString& errorString); ///< error on parse failure
/// Determines is the specified data is a json file /// Determines is the specified data is a json file
/// @return true: file is json, false: file is not json /// @return true: file is json, false: file is not json
static bool isJsonFile(const QByteArray& bytes, ///< json bytes static bool isJsonFile(const QByteArray& bytes, ///< json bytes
......
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "QGCZlib.h"
#include <QFile>
#include <QDir>
#include <QtDebug>
#include "zlib.h"
bool QGCZlib::inflateGzipFile(const QString& gzippedFileName, const QString& decompressedFilename)
{
bool success = true;
int ret;
const int cBuffer = 1024 * 5;
unsigned char inputBuffer[cBuffer];
unsigned char outputBuffer[cBuffer];
z_stream strm;
QFile inputFile(gzippedFileName);
if (!inputFile.open(QIODevice::ReadOnly)) {
qWarning() << "QGCZlib::inflateGzipFile: open input file failed" << gzippedFileName << inputFile.errorString();
return false;
}
QFile outputFile(decompressedFilename);
if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning() << "QGCZlib::inflateGzipFile: open input file failed" << outputFile.fileName() << outputFile.errorString();
return false;
}
strm.zalloc = nullptr;
strm.zfree = nullptr;
strm.opaque = nullptr;
strm.avail_in = 0;
strm.next_in = nullptr;
ret = inflateInit2(&strm, 16+MAX_WBITS);
if (ret != Z_OK) {
qWarning() << "QGCZlib::inflateGzipFile: inflateInit2 failed:" << ret;
goto Error;
}
do {
strm.avail_in = static_cast<unsigned>(inputFile.read((char*)inputBuffer, cBuffer));
if (strm.avail_in == 0) {
break;
}
strm.next_in = inputBuffer;
do {
strm.avail_out = cBuffer;
strm.next_out = outputBuffer;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
qWarning() << "QGCZlib::inflateGzipFile: inflate failed:" << ret;
goto Error;
}
unsigned cBytesInflated = cBuffer - strm.avail_out;
qint64 cBytesWritten = outputFile.write((char*)outputBuffer, static_cast<int>(cBytesInflated));
if (cBytesWritten != cBytesInflated) {
qWarning() << "QGCZlib::inflateGzipFile: output file write failed:" << outputFile.fileName() << outputFile.errorString();
goto Error;
}
} while (strm.avail_out == 0);
} while (ret != Z_STREAM_END);
Out:
inflateEnd(&strm);
return success;
Error:
success = false;
goto Out;
}
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include <QString>
class QGCZlib
{
public:
/// Decompresses the specified file to the specified directory
/// @param gzipFilename Fully qualified path to gzip file
/// @param decompressedFilename Fully qualified path to for file to decompress to
static bool inflateGzipFile(const QString& gzippedFileName, const QString& decompressedFilename);
};
...@@ -10,14 +10,21 @@ ...@@ -10,14 +10,21 @@
#include "ComponentInformationManager.h" #include "ComponentInformationManager.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "FTPManager.h" #include "FTPManager.h"
#include "QGCZlib.h"
#include "JsonHelper.h"
#include <QStandardPaths> #include <QStandardPaths>
#include <QJsonDocument>
#include <QJsonArray>
QGC_LOGGING_CATEGORY(ComponentInformationManagerLog, "ComponentInformationManagerLog") QGC_LOGGING_CATEGORY(ComponentInformationManagerLog, "ComponentInformationManagerLog")
const char* ComponentInformationManager::_jsonVersionKey = "version";
const char* ComponentInformationManager::_jsonSupportedCompMetadataTypesKey = "supportedCompMetadataTypes";
ComponentInformationManager::StateFn ComponentInformationManager::_rgStates[]= { ComponentInformationManager::StateFn ComponentInformationManager::_rgStates[]= {
ComponentInformationManager::_stateRequestCompInfoVersion, ComponentInformationManager::_stateRequestCompInfoVersion,
//ComponentInformationManager::_stateRequestCompInfoParam, ComponentInformationManager::_stateRequestCompInfoParam,
ComponentInformationManager::_stateRequestAllCompInfoComplete ComponentInformationManager::_stateRequestAllCompInfoComplete
}; };
...@@ -27,6 +34,7 @@ RequestMetaDataTypeStateMachine::StateFn RequestMetaDataTypeStateMachine::_rgSta ...@@ -27,6 +34,7 @@ RequestMetaDataTypeStateMachine::StateFn RequestMetaDataTypeStateMachine::_rgSta
RequestMetaDataTypeStateMachine::_stateRequestCompInfo, RequestMetaDataTypeStateMachine::_stateRequestCompInfo,
RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson, RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson,
RequestMetaDataTypeStateMachine::_stateRequestTranslationJson, RequestMetaDataTypeStateMachine::_stateRequestTranslationJson,
RequestMetaDataTypeStateMachine::_stateRequestComplete,
}; };
int RequestMetaDataTypeStateMachine::_cStates = sizeof(RequestMetaDataTypeStateMachine::_rgStates) / sizeof(RequestMetaDataTypeStateMachine::_rgStates[0]); int RequestMetaDataTypeStateMachine::_cStates = sizeof(RequestMetaDataTypeStateMachine::_rgStates) / sizeof(RequestMetaDataTypeStateMachine::_rgStates[0]);
...@@ -69,7 +77,12 @@ void ComponentInformationManager::_stateRequestCompInfoComplete(void) ...@@ -69,7 +77,12 @@ void ComponentInformationManager::_stateRequestCompInfoComplete(void)
void ComponentInformationManager::_stateRequestCompInfoParam(StateMachine* stateMachine) void ComponentInformationManager::_stateRequestCompInfoParam(StateMachine* stateMachine)
{ {
ComponentInformationManager* compMgr = static_cast<ComponentInformationManager*>(stateMachine); ComponentInformationManager* compMgr = static_cast<ComponentInformationManager*>(stateMachine);
if (compMgr->_isCompTypeSupported(COMP_METADATA_TYPE_PARAMETER)) {
compMgr->_requestTypeStateMachine.request(COMP_METADATA_TYPE_PARAMETER); compMgr->_requestTypeStateMachine.request(COMP_METADATA_TYPE_PARAMETER);
} else {
}
} }
void ComponentInformationManager::_stateRequestAllCompInfoComplete(StateMachine* stateMachine) void ComponentInformationManager::_stateRequestAllCompInfoComplete(StateMachine* stateMachine)
...@@ -80,6 +93,41 @@ void ComponentInformationManager::_stateRequestAllCompInfoComplete(StateMachine* ...@@ -80,6 +93,41 @@ void ComponentInformationManager::_stateRequestAllCompInfoComplete(StateMachine*
compMgr->_requestAllCompleteFnData = nullptr; compMgr->_requestAllCompleteFnData = nullptr;
} }
void ComponentInformationManager::_compInfoJsonAvailable(const QString& metadataJsonFileName, const QString& translationsJsonFileName)
{
qCDebug(ComponentInformationManagerLog) << "_compInfoJsonAvailable metadata:translation" << metadataJsonFileName << translationsJsonFileName;
if (!metadataJsonFileName.isEmpty()) {
QString errorString;
QJsonDocument jsonDoc;
if (!JsonHelper::isJsonFile(metadataJsonFileName, jsonDoc, errorString)) {
qCWarning(ComponentInformationManagerLog) << "Version json file read failed" << errorString;
return;
}
QJsonObject jsonObj = jsonDoc.object();
if (currentState() == _stateRequestCompInfoVersion) {
QList<JsonHelper::KeyValidateInfo> keyInfoList = {
{ _jsonVersionKey, QJsonValue::Double, true },
{ _jsonSupportedCompMetadataTypesKey, QJsonValue::Array, true },
};
if (!JsonHelper::validateKeys(jsonObj, keyInfoList, errorString)) {
qCWarning(ComponentInformationManagerLog) << "Version json validation failed:" << errorString;
return;
}
for (const QJsonValue& idValue: jsonObj[_jsonSupportedCompMetadataTypesKey].toArray()) {
_supportedMetaDataTypes.append(static_cast<COMP_METADATA_TYPE>(idValue.toInt()));
}
}
}
}
bool ComponentInformationManager::_isCompTypeSupported(COMP_METADATA_TYPE type)
{
return _supportedMetaDataTypes.contains(type);
}
RequestMetaDataTypeStateMachine::RequestMetaDataTypeStateMachine(ComponentInformationManager* compMgr) RequestMetaDataTypeStateMachine::RequestMetaDataTypeStateMachine(ComponentInformationManager* compMgr)
: _compMgr(compMgr) : _compMgr(compMgr)
{ {
...@@ -91,6 +139,8 @@ void RequestMetaDataTypeStateMachine::request(COMP_METADATA_TYPE type) ...@@ -91,6 +139,8 @@ void RequestMetaDataTypeStateMachine::request(COMP_METADATA_TYPE type)
_compInfoAvailable = false; _compInfoAvailable = false;
_type = type; _type = type;
_stateIndex = -1; _stateIndex = -1;
_jsonMetadataFileName.clear();
_jsonTranslationFileName.clear();
start(); start();
} }
...@@ -171,9 +221,47 @@ void RequestMetaDataTypeStateMachine::_stateRequestCompInfo(StateMachine* stateM ...@@ -171,9 +221,47 @@ void RequestMetaDataTypeStateMachine::_stateRequestCompInfo(StateMachine* stateM
} }
} }
void RequestMetaDataTypeStateMachine::_downloadComplete(const QString& file, const QString& errorMsg) QString RequestMetaDataTypeStateMachine::_downloadCompleteJsonWorker(const QString& fileName, const QString& inflatedFileName)
{ {
qCDebug(ComponentInformationManagerLog) << "RequestMetaDataTypeStateMachine::_downloadComplete" << file << errorMsg; QString outputFileName = fileName;
if (fileName.endsWith(".gz", Qt::CaseInsensitive)) {
outputFileName = (QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).absoluteFilePath(inflatedFileName));
if (QGCZlib::inflateGzipFile(fileName, outputFileName)) {
QFile(fileName).remove();
} else {
qCWarning(ComponentInformationManagerLog) << "Inflate of compressed json failed" << inflatedFileName;
outputFileName.clear();
}
} else {
outputFileName = fileName;
}
return outputFileName;
}
void RequestMetaDataTypeStateMachine::_downloadCompleteMetaDataJson(const QString& fileName, const QString& errorMsg)
{
qCDebug(ComponentInformationManagerLog) << "RequestMetaDataTypeStateMachine::_downloadCompleteMetaDataJson fileName:errorMsg" << fileName << errorMsg;
if (errorMsg.isEmpty()) {
_jsonMetadataFileName = _downloadCompleteJsonWorker(fileName, "metadata.json");
}
advance();
}
void RequestMetaDataTypeStateMachine::_downloadCompleteTranslationJson(const QString& fileName, const QString& errorMsg)
{
qCDebug(ComponentInformationManagerLog) << "RequestMetaDataTypeStateMachine::_downloadCompleteTranslationJson fileName:errorMsg" << fileName << errorMsg;
QString jsonTranslationFileName;
if (errorMsg.isEmpty()) {
jsonTranslationFileName = _downloadCompleteJsonWorker(fileName, "translation.json");
}
_compMgr->_compInfoJsonAvailable(_jsonMetadataFileName, jsonTranslationFileName);
advance(); advance();
} }
...@@ -186,9 +274,9 @@ void RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson(StateMachine* st ...@@ -186,9 +274,9 @@ void RequestMetaDataTypeStateMachine::_stateRequestMetaDataJson(StateMachine* st
if (requestMachine->_compInfoAvailable) { if (requestMachine->_compInfoAvailable) {
ComponentInformation_t& compInfo = requestMachine->_compInfo; ComponentInformation_t& compInfo = requestMachine->_compInfo;
qCDebug(ComponentInformationManagerLog) << "Downloading metadata json" << compInfo.translationURI; qCDebug(ComponentInformationManagerLog) << "Downloading metadata json" << compInfo.metadataURI;
if (_uriIsFTP(compInfo.metadataURI)) { if (_uriIsFTP(compInfo.metadataURI)) {
connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadComplete); connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadCompleteMetaDataJson);
ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation)); ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation));
} else { } else {
// FIXME: NYI // FIXME: NYI
...@@ -214,7 +302,7 @@ void RequestMetaDataTypeStateMachine::_stateRequestTranslationJson(StateMachine* ...@@ -214,7 +302,7 @@ void RequestMetaDataTypeStateMachine::_stateRequestTranslationJson(StateMachine*
} else { } else {
qCDebug(ComponentInformationManagerLog) << "Downloading translation json" << compInfo.translationURI; qCDebug(ComponentInformationManagerLog) << "Downloading translation json" << compInfo.translationURI;
if (_uriIsFTP(compInfo.translationURI)) { if (_uriIsFTP(compInfo.translationURI)) {
connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadComplete); connect(ftpManager, &FTPManager::downloadComplete, requestMachine, &RequestMetaDataTypeStateMachine::_downloadCompleteTranslationJson);
ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation)); ftpManager->download(compInfo.metadataURI, QStandardPaths::writableLocation(QStandardPaths::TempLocation));
} else { } else {
// FIXME: NYI // FIXME: NYI
...@@ -227,6 +315,14 @@ void RequestMetaDataTypeStateMachine::_stateRequestTranslationJson(StateMachine* ...@@ -227,6 +315,14 @@ void RequestMetaDataTypeStateMachine::_stateRequestTranslationJson(StateMachine*
} }
} }
void RequestMetaDataTypeStateMachine::_stateRequestComplete(StateMachine* stateMachine)
{
RequestMetaDataTypeStateMachine* requestMachine = static_cast<RequestMetaDataTypeStateMachine*>(stateMachine);
requestMachine->compMgr()->_compInfoJsonAvailable(requestMachine->_jsonMetadataFileName, requestMachine->_jsonTranslationFileName);
requestMachine->advance();
}
bool RequestMetaDataTypeStateMachine::_uriIsFTP(const QString& uri) bool RequestMetaDataTypeStateMachine::_uriIsFTP(const QString& uri)
{ {
return uri.startsWith("mavlinkftp", Qt::CaseInsensitive); return uri.startsWith("mavlinkftp", Qt::CaseInsensitive);
......
...@@ -43,12 +43,15 @@ public: ...@@ -43,12 +43,15 @@ public:
void statesCompleted (void) const final; void statesCompleted (void) const final;
private slots: private slots:
void _downloadComplete(const QString& file, const QString& errorMsg); void _downloadCompleteMetaDataJson (const QString& file, const QString& errorMsg);
void _downloadCompleteTranslationJson(const QString& file, const QString& errorMsg);
QString _downloadCompleteJsonWorker (const QString& jsonFileName, const QString& inflatedFileName);
private: private:
static void _stateRequestCompInfo (StateMachine* stateMachine); static void _stateRequestCompInfo (StateMachine* stateMachine);
static void _stateRequestMetaDataJson (StateMachine* stateMachine); static void _stateRequestMetaDataJson (StateMachine* stateMachine);
static void _stateRequestTranslationJson (StateMachine* stateMachine); static void _stateRequestTranslationJson (StateMachine* stateMachine);
static void _stateRequestComplete (StateMachine* stateMachine);
static bool _uriIsFTP (const QString& uri); static bool _uriIsFTP (const QString& uri);
...@@ -56,6 +59,8 @@ private: ...@@ -56,6 +59,8 @@ private:
COMP_METADATA_TYPE _type = COMP_METADATA_TYPE_VERSION; COMP_METADATA_TYPE _type = COMP_METADATA_TYPE_VERSION;
bool _compInfoAvailable = false; bool _compInfoAvailable = false;
ComponentInformation_t _compInfo; ComponentInformation_t _compInfo;
QString _jsonMetadataFileName;
QString _jsonTranslationFileName;
static StateFn _rgStates[]; static StateFn _rgStates[];
static int _cStates; static int _cStates;
...@@ -78,7 +83,9 @@ public: ...@@ -78,7 +83,9 @@ public:
const StateFn* rgStates (void) const final; const StateFn* rgStates (void) const final;
private: private:
void _stateRequestCompInfoComplete(void); void _stateRequestCompInfoComplete (void);
void _compInfoJsonAvailable (const QString& metadataJsonFileName, const QString& translationsJsonFileName);
bool _isCompTypeSupported (COMP_METADATA_TYPE type);
static void _stateRequestCompInfoVersion (StateMachine* stateMachine); static void _stateRequestCompInfoVersion (StateMachine* stateMachine);
static void _stateRequestCompInfoParam (StateMachine* stateMachine); static void _stateRequestCompInfoParam (StateMachine* stateMachine);
...@@ -97,5 +104,8 @@ private: ...@@ -97,5 +104,8 @@ private:
static StateFn _rgStates[]; static StateFn _rgStates[];
static int _cStates; static int _cStates;
static const char* _jsonVersionKey;
static const char* _jsonSupportedCompMetadataTypesKey;
friend class RequestMetaDataTypeStateMachine; friend class RequestMetaDataTypeStateMachine;
}; };
...@@ -50,3 +50,12 @@ void StateMachine::statesCompleted(void) const ...@@ -50,3 +50,12 @@ void StateMachine::statesCompleted(void) const
{ {
} }
StateMachine::StateFn StateMachine::currentState(void)
{
if (_active) {
return rgStates()[_stateIndex];
} else {
return nullptr;
}
}
...@@ -29,6 +29,8 @@ public: ...@@ -29,6 +29,8 @@ public:
/// Move the state machine to the specified state and call the state function /// Move the state machine to the specified state and call the state function
void move(StateFn stateFn); void move(StateFn stateFn);
StateFn currentState(void);
/// @return The number of states in the rgStates array /// @return The number of states in the rgStates array
virtual int stateCount(void) const = 0; virtual int stateCount(void) const = 0;
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
#include "QGCCorePlugin.h" #include "QGCCorePlugin.h"
#include "FirmwareUpgradeSettings.h" #include "FirmwareUpgradeSettings.h"
#include "SettingsManager.h" #include "SettingsManager.h"
#include "QGCTemporaryFile.h" #include "QGCZlib.h"
#include "JsonHelper.h"
#include <QStandardPaths> #include <QStandardPaths>
#include <QRegularExpression> #include <QRegularExpression>
...@@ -892,68 +893,19 @@ void FirmwareUpgradeController::_ardupilotManifestDownloadFinished(QString remot ...@@ -892,68 +893,19 @@ void FirmwareUpgradeController::_ardupilotManifestDownloadFinished(QString remot
qCDebug(FirmwareUpgradeLog) << "_ardupilotManifestDownloadFinished" << remoteFile << localFile; qCDebug(FirmwareUpgradeLog) << "_ardupilotManifestDownloadFinished" << remoteFile << localFile;
QFile inputFile(localFile); QString jsonFileName(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).absoluteFilePath("ArduPilot.Manifest.json"));
if (!inputFile.open(QIODevice::ReadOnly)) { if (!QGCZlib::inflateGzipFile(localFile, jsonFileName)) {
qCWarning(FirmwareUpgradeLog) << "Unable to open ArduPilot firmware manifest file for reading" << localFile << inputFile.errorString(); qCWarning(FirmwareUpgradeLog) << "Inflate of compressed manifest failed" << localFile;
QFile::remove(localFile);
return; return;
} }
int ret; QString errorString;
const int cBuffer = 1024 * 5; QJsonDocument doc;
unsigned char inputBuffer[cBuffer]; if (JsonHelper::isJsonFile(jsonFileName, doc, errorString)) {
unsigned char outputBuffer[cBuffer]; qCWarning(FirmwareUpgradeLog) << "Json file read failed" << errorString;
z_stream strm;
QByteArray jsonBytes;
strm.zalloc = nullptr;
strm.zfree = nullptr;
strm.opaque = nullptr;
strm.avail_in = 0;
strm.next_in = nullptr;
ret = inflateInit2(&strm, 16+MAX_WBITS);
if (ret != Z_OK) {
qCWarning(FirmwareUpgradeLog) << "inflateInit2 failed:" << ret;
QFile::remove(localFile);
return; return;
} }
do {
strm.avail_in = static_cast<unsigned>(inputFile.read((char*)inputBuffer, cBuffer));
if (strm.avail_in == 0) {
break;
}
strm.next_in = inputBuffer;
do {
strm.avail_out = cBuffer;
strm.next_out = outputBuffer;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
qCWarning(FirmwareUpgradeLog) << "Inflate failed" << ret;
inflateEnd(&strm);
QFile::remove(localFile);
return;
}
unsigned cBytesInflated = cBuffer - strm.avail_out;
jsonBytes.append((char*)outputBuffer, static_cast<int>(cBytesInflated));
} while (strm.avail_out == 0);
} while (ret != Z_STREAM_END);
inflateEnd(&strm);
inputFile.close();
QFile::remove(localFile);
QJsonParseError jsonParseError;
QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &jsonParseError);
if (jsonParseError.error != QJsonParseError::NoError) {
qCWarning(FirmwareUpgradeLog) << "Unable to open ArduPilot manifest json document" << localFile << jsonParseError.errorString();
}
QJsonObject json = doc.object(); QJsonObject json = doc.object();
QJsonArray rgFirmware = json[_manifestFirmwareJsonKey].toArray(); QJsonArray rgFirmware = json[_manifestFirmwareJsonKey].toArray();
......
This diff is collapsed.
...@@ -1529,7 +1529,7 @@ bool MockLink::_handleRequestMessage(const mavlink_command_long_t& request, bool ...@@ -1529,7 +1529,7 @@ bool MockLink::_handleRequestMessage(const mavlink_command_long_t& request, bool
void MockLink::_sendVersionMetaData(void) void MockLink::_sendVersionMetaData(void)
{ {
mavlink_message_t responseMsg; mavlink_message_t responseMsg;
char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://version.json"; char metaDataURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_METADATA_URI_LEN] = "mavlinkftp://version.json.gz";
char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = ""; char translationURI[MAVLINK_MSG_COMPONENT_INFORMATION_FIELD_TRANSLATION_URI_LEN] = "";
mavlink_msg_component_information_pack_chan(_vehicleSystemId, mavlink_msg_component_information_pack_chan(_vehicleSystemId,
......
...@@ -119,6 +119,10 @@ void MockLinkFTP::_openCommand(uint8_t senderSystemId, uint8_t senderComponentId ...@@ -119,6 +119,10 @@ void MockLinkFTP::_openCommand(uint8_t senderSystemId, uint8_t senderComponentId
tmpFilename = _createTestTempFile(sizeString.toInt()); tmpFilename = _createTestTempFile(sizeString.toInt());
} else if (path == "/version.json") { } else if (path == "/version.json") {
tmpFilename = ":MockLink/Version.MetaData.json"; tmpFilename = ":MockLink/Version.MetaData.json";
} else if (path == "/version.json.gz") {
tmpFilename = ":MockLink/Version.MetaData.json.gz";
} else if (path == "/parameter.json") {
tmpFilename = ":MockLink/Parameter.MetaData.json";
} }
if (!tmpFilename.isEmpty()) { if (!tmpFilename.isEmpty()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment