QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
APMParameterMetaData.cc
Go to the documentation of this file.
3
4#include <algorithm>
5#include <QtCore/QJsonObject>
6#include <QtCore/QRegularExpression>
7
8using namespace Qt::StringLiterals;
9
10QGC_LOGGING_CATEGORY(APMParameterMetaDataLog, "FirmwarePlugin.APMParameterMetaData")
11QGC_LOGGING_CATEGORY(APMParameterMetaDataVerboseLog, "FirmwarePlugin.APMParameterMetaData:verbose")
12
14 : ParameterMetaData(parent)
15{
16 qCDebug(APMParameterMetaDataLog) << this;
17}
18
20{
21 qCDebug(APMParameterMetaDataLog) << this;
22}
23
24QString APMParameterMetaData::_groupFromParameterName(const QString &name)
25{
26 static const QRegularExpression regex(QStringLiteral("[0-9]*$"));
27 QString group = name.split('_').first();
28 return group.remove(regex);
29}
30
31void APMParameterMetaData::parseParameterJson(const QJsonObject &json)
32{
33 for (auto groupIt = json.constBegin(); groupIt != json.constEnd(); ++groupIt) {
34 if (!groupIt->isObject()) {
35 continue;
36 }
37
38 const QJsonObject params = groupIt->toObject();
39
40 for (auto paramIt = params.constBegin(); paramIt != params.constEnd(); ++paramIt) {
41 if (!paramIt->isObject()) {
42 continue;
43 }
44
45 const QString name = paramIt.key();
46 const QString group = _groupFromParameterName(name);
47
48 if (_rawParams.contains(name)) {
49 qCWarning(APMParameterMetaDataLog) << "Duplicate parameter found:" << name;
50 }
51
52 _rawParams[name] = RawParamData{group, paramIt->toObject()};
53 }
54 }
55
56 _correctGroupMemberships();
57}
58
59void APMParameterMetaData::_correctGroupMemberships()
60{
61 // Demote groups with only one member to the default group.
62 QHash<QString, int> groupCount;
63 for (const auto &raw : std::as_const(_rawParams)) {
64 groupCount[raw.group]++;
65 }
66 for (auto &raw : _rawParams) {
67 if (groupCount.value(raw.group) == 1) {
68 raw.group = FactMetaData::defaultGroup();
69 }
70 }
71}
72
74{
75 auto it = _rawParams.constFind(name);
76 if (it == _rawParams.constEnd()) {
77 return nullptr;
78 }
79
80 const RawParamData &raw = *it;
81 const QJsonObject &f = raw.fields;
82
83 auto *metaData = new FactMetaData(type, this);
84 metaData->setName(name);
85 metaData->setGroup(raw.group);
86
87 const QString displayName = f.value(u"DisplayName").toString();
88 if (!displayName.isEmpty()) {
89 metaData->setShortDescription(displayName);
90 }
91
92 const QString description = f.value(u"Description").toString();
93 if (!description.isEmpty()) {
94 metaData->setLongDescription(description);
95 }
96
97 const QString units = f.value(u"Units").toString();
98 if (!units.isEmpty()) {
99 metaData->setRawUnits(units);
100 }
101
102 const QString category = f.value(u"User").toString();
103 if (!category.isEmpty()) {
104 metaData->setCategory(category);
105 }
106
107 if (f.contains(u"ReadOnly")) {
108 metaData->setReadOnly(jsonToBool(f.value(u"ReadOnly")));
109 }
110 if (f.contains(u"RebootRequired")) {
111 metaData->setVehicleRebootRequired(jsonToBool(f.value(u"RebootRequired")));
112 }
113
114 const QString increment = f.value(u"Increment").toString();
115 if (!increment.isEmpty()) {
116 bool ok = false;
117 const double val = increment.toDouble(&ok);
118 if (ok) {
119 metaData->setRawIncrement(val);
120 }
121 }
122
123 const QJsonObject range = f.value(u"Range").toObject();
124 if (!range.isEmpty()) {
125 const QString lowStr = range.value(u"low").toString();
126 const QString highStr = range.value(u"high").toString();
127 if (!lowStr.isEmpty()) {
130 }
131 if (!highStr.isEmpty()) {
134 }
135 }
136
137 const QJsonObject valuesObj = f.value(u"Values").toObject();
138 if (!valuesObj.isEmpty()) {
139 _applyEnumValues(metaData, valuesObj);
140 }
141
142 const QJsonObject bitmaskObj = f.value(u"Bitmask").toObject();
143 if (!bitmaskObj.isEmpty()) {
144 _applyBitmask(metaData, bitmaskObj);
145 }
146
147 return metaData;
148}
149
150QList<ParameterMetaData::ValueDescPair> APMParameterMetaData::_sortedNumericPairs(const QJsonObject &obj, const QString &paramName)
151{
152 // APM format: {"0":"Disabled","1":"Enabled"} — sort by numeric value
153 // but preserve original string keys to avoid float round-trip issues.
154 struct Entry { double sortKey; QString key; QString desc; };
155 QList<Entry> entries;
156 entries.reserve(obj.size());
157 for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) {
158 bool ok = false;
159 const double sortKey = it.key().toDouble(&ok);
160 if (!ok) {
161 qCWarning(APMParameterMetaDataLog) << "Non-numeric key:" << it.key() << "for" << paramName;
162 continue;
163 }
164 entries.append({sortKey, it.key(), it->toString()});
165 }
166 std::sort(entries.begin(), entries.end(), [](const auto &a, const auto &b) {
167 return a.sortKey < b.sortKey;
168 });
169
170 QList<ValueDescPair> pairs;
171 pairs.reserve(entries.size());
172 for (const auto &e : std::as_const(entries)) {
173 pairs.append({e.key, e.desc});
174 }
175 return pairs;
176}
177
178void APMParameterMetaData::_applyEnumValues(FactMetaData *metaData, const QJsonObject &valuesObj)
179{
180 setEnumFromPairs(metaData, _sortedNumericPairs(valuesObj, metaData->name()));
181}
182
183void APMParameterMetaData::_applyBitmask(FactMetaData *metaData, const QJsonObject &bitmaskObj)
184{
185 setBitmaskFromPairs(metaData, _sortedNumericPairs(bitmaskObj, metaData->name()));
186}
187
189{
190 auto *metaData = new FactMetaData(type, this);
191 metaData->setCategory(QStringLiteral("Advanced"));
192 metaData->setGroup(_groupFromParameterName(name));
193 return metaData;
194}
195
197{
198 if ((name.endsWith(u"_P") || name.endsWith(u"_I") || name.endsWith(u"_D")) &&
199 (metaData->type() == FactMetaData::valueTypeFloat || metaData->type() == FactMetaData::valueTypeDouble)) {
200 metaData->setDecimalPlaces(6);
201 }
202}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
FactMetaData * _lookupMetaData(const QString &name, FactMetaData::ValueType_t type) override
void parseParameterJson(const QJsonObject &json) override
void _postProcessMetaData(const QString &name, FactMetaData *metaData) override
FactMetaData * _createDefaultMetaData(const QString &name, FactMetaData::ValueType_t type) override
Holds the meta data associated with a Fact.
void setDecimalPlaces(int decimalPlaces)
void setRawUserMin(const QVariant &rawUserMin)
void setRawUserMax(const QVariant &rawUserMax)
void setRawMin(const QVariant &rawMin)
void setCategory(const QString &category)
static const QString defaultGroup()
void setRawMax(const QVariant &rawMax)
QString name() const
void setGroup(const QString &group)
ValueType_t type() const
The FirmwarePlugin class represents the methods and objects which are specific to a certain Firmware ...
static void setBitmaskFromPairs(FactMetaData *metaData, const QList< ValueDescPair > &pairs)
static bool setRawConvertedValue(FactMetaData *metaData, const QString &rawText, void(FactMetaData::*setter)(const QVariant &))
static void setEnumFromPairs(FactMetaData *metaData, const QList< ValueDescPair > &pairs)
static bool jsonToBool(const QJsonValue &value)