7#include <QtCore/QTextStream>
26#include <QtCore/QEasingCurve>
27#include <QtCore/QFile>
28#include <QtCore/QStandardPaths>
29#include <QtCore/QVariantAnimation>
39 , _logReplay(!vehicle->vehicleLinkManager()->primaryLink().expired() && vehicle->vehicleLinkManager()->primaryLink().lock()->isLogReplay())
40 , _disableAllRetries(_logReplay)
41 , _waitForParamValueAckMs(
QGC::runningUnitTests() ? 50 : kWaitForParamValueAckMs)
42 , _tryftp(vehicle->apmFirmware())
44 qCDebug(ParameterManagerLog) <<
this;
46 if (_vehicle->isOfflineEditingVehicle()) {
47 _loadOfflineEditingParams();
52 qCDebug(ParameterManagerLog) <<
this <<
"In log replay mode";
55 _hashCheckTimer.setSingleShot(
true);
57 (void) connect(&_hashCheckTimer, &QTimer::timeout,
this, &ParameterManager::_hashCheckTimeout);
59 _paramRequestListTimer.setSingleShot(
true);
60 _paramRequestListTimer.setInterval(
QGC::runningUnitTests() ? kTestInitialRequestIntervalMs : kParamRequestListTimeoutMs);
61 (void) connect(&_paramRequestListTimer, &QTimer::timeout,
this, &ParameterManager::_paramRequestListTimeout);
63 _waitingParamTimeoutTimer.setSingleShot(
true);
66 (void) connect(&_waitingParamTimeoutTimer, &QTimer::timeout,
this, &ParameterManager::_waitingParamTimeout);
70 (void) QDir().mkpath(parameterCacheDir().absolutePath());
75 qCDebug(ParameterManagerLog) <<
this;
78void ParameterManager::_updateProgressBar()
80 int waitingReadParamIndexCount = 0;
82 for (
const int compId: _waitingReadParamIndexMap.keys()) {
83 waitingReadParamIndexCount += _waitingReadParamIndexMap[compId].count();
86 if (waitingReadParamIndexCount == 0) {
87 if (_readParamIndexProgressActive) {
88 _readParamIndexProgressActive =
false;
89 _setLoadProgress(0.0);
93 _readParamIndexProgressActive =
true;
94 _setLoadProgress(
static_cast<double>(_totalParamCount - waitingReadParamIndexCount) /
static_cast<double>(_totalParamCount));
101 if (_tryftp && (message.compid == MAV_COMP_ID_AUTOPILOT1) && !_initialLoadComplete)
104 if (message.msgid == MAVLINK_MSG_ID_PARAM_VALUE) {
105 mavlink_param_value_t param_value{};
106 mavlink_msg_param_value_decode(&message, ¶m_value);
109 char parameterNameWithNull[MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1] = {};
110 (void) strncpy(parameterNameWithNull, param_value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
111 const QString parameterName(parameterNameWithNull);
114 paramUnion.param_float = param_value.param_value;
115 paramUnion.type = param_value.param_type;
117 QVariant parameterValue;
118 if (!_mavlinkParamUnionToVariant(paramUnion, parameterValue)) {
122 _handleParamValue(message.compid, parameterName, param_value.param_count, param_value.param_index,
static_cast<MAV_PARAM_TYPE
>(param_value.param_type), parameterValue);
126void ParameterManager::_handleParamValue(
int componentId,
const QString ¶meterName,
int parameterCount,
int parameterIndex, MAV_PARAM_TYPE mavParamType,
const QVariant ¶meterValue)
129 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
130 "_parameterUpdate" <<
131 "name:" << parameterName <<
132 "count:" << parameterCount <<
133 "index:" << parameterIndex <<
134 "mavType:" << mavParamType <<
135 "value:" << parameterValue <<
140 if ((parameterIndex == 65535) && (parameterName != QStringLiteral(
"_HASH_CHECK")) && _paramRequestListTimer.isActive()) {
141 qCDebug(ParameterManagerLog) <<
"Disregarding unrequested param prior to initial list response" << parameterName;
145 if (_vehicle->
px4Firmware() && (parameterName ==
"_HASH_CHECK")) {
146 _hashCheckTimer.stop();
147 if (!_initialLoadComplete && !_logReplay) {
149 _tryCacheHashLoad(_vehicle->
id(), componentId, parameterValue);
154 _paramRequestListTimer.stop();
157 if (!_initialLoadComplete && !_logReplay && _debugCacheCRC.contains(componentId) && _debugCacheCRC[componentId]) {
158 if (_debugCacheMap[componentId].contains(parameterName)) {
159 const ParamTypeVal &cacheParamTypeVal = _debugCacheMap[componentId][parameterName];
161 const void *
const cacheData = cacheParamTypeVal.second.constData();
162 const void *
const vehicleData = parameterValue.constData();
164 if (memcmp(cacheData, vehicleData, dataSize) != 0) {
165 qCDebug(ParameterManagerVerbose1Log) <<
"Cache/Vehicle values differ for name:cache:actual" << parameterName << parameterValue << cacheParamTypeVal.second;
167 _debugCacheParamSeen[componentId][parameterName] =
true;
169 qCDebug(ParameterManagerVerbose1Log) <<
"Parameter missing from cache" << parameterName;
173 _waitingParamTimeoutTimer.stop();
176 if (!_paramCountMap.contains(componentId)) {
177 _paramCountMap[componentId] = parameterCount;
178 _totalParamCount += parameterCount;
182 if (!_waitingReadParamIndexMap.contains(componentId)) {
184 for (
int waitingIndex = 0; waitingIndex < parameterCount; waitingIndex++) {
186 _waitingReadParamIndexMap[componentId][waitingIndex] = 0;
189 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"Seeing component for first time - paramcount:" << parameterCount;
192 if (!_waitingReadParamIndexMap[componentId].contains(parameterIndex)) {
193 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"Unrequested param update" << parameterName;
197 if (_waitingReadParamIndexMap[componentId].contains(parameterIndex)) {
198 _waitingReadParamIndexMap[componentId].remove(parameterIndex);
199 (void) _indexBatchQueue.removeOne(parameterIndex);
200 _fillIndexBatchQueue(
false );
204 int waitingReadParamIndexCount = 0;
206 for (
const int waitingComponentId: _waitingReadParamIndexMap.keys()) {
207 waitingReadParamIndexCount += _waitingReadParamIndexMap[waitingComponentId].count();
209 if (waitingReadParamIndexCount) {
210 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"waitingReadParamIndexCount:" << waitingReadParamIndexCount;
213 const int readWaitingParamCount = waitingReadParamIndexCount;
214 const int totalWaitingParamCount = readWaitingParamCount;
215 if (totalWaitingParamCount) {
217 _waitingParamTimeoutTimer.start();
218 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(-1) <<
"Restarting _waitingParamTimeoutTimer: totalWaitingParamCount:" << totalWaitingParamCount;
221 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Restarting _waitingParamTimeoutTimer (still waiting for default component params)";
222 _waitingParamTimeoutTimer.start();
224 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(-1) <<
"Not restarting _waitingParamTimeoutTimer (all requests satisfied)";
227 _updateProgressBar();
229 Fact *fact =
nullptr;
230 if (_mapCompId2FactMap.contains(componentId) && _mapCompId2FactMap[componentId].contains(parameterName)) {
231 fact = _mapCompId2FactMap[componentId][parameterName];
233 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"Adding new fact" << parameterName;
239 _mapCompId2FactMap[componentId][parameterName] = fact;
253 if (_prevWaitingReadParamIndexCount != 0 && readWaitingParamCount == 0) {
255 _writeLocalParamCache(_vehicle->
id(), componentId);
259 _prevWaitingReadParamIndexCount = waitingReadParamIndexCount;
261 _checkInitialLoadComplete();
263 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"_parameterUpdate complete";
266QString ParameterManager::_vehicleAndComponentString(
int componentId)
const
269 QString vehicleIdStr;
271 vehicleIdStr = QStringLiteral(
"veh: %1").arg(_vehicle->
id());
275 QString componentIdStr;
276 if (_mapCompId2FactMap.keys().count() > 1) {
277 componentIdStr = QStringLiteral(
"comp: %1").arg(componentId);
280 if (!vehicleIdStr.isEmpty() && !componentIdStr.isEmpty()) {
281 return vehicleIdStr + QStringLiteral(
" ") + componentIdStr;
282 }
else if (!vehicleIdStr.isEmpty()) {
284 }
else if (!componentIdStr.isEmpty()) {
285 return componentIdStr;
291void ParameterManager::_mavlinkParamSet(
int componentId,
const QString ¶mName,
FactMetaData::ValueType_t valueType,
const QVariant &rawValue)
293 auto paramSetEncoder = [
this, componentId, paramName, valueType, rawValue](uint8_t , uint8_t channel,
mavlink_message_t *message) ->
void {
297 if (!_fillMavlinkParamUnion(valueType, rawValue, union_value)) {
301 char paramId[MAVLINK_MSG_PARAM_SET_FIELD_PARAM_ID_LEN + 1] = {};
302 (void) strncpy(paramId, paramName.toLocal8Bit().constData(), MAVLINK_MSG_PARAM_SET_FIELD_PARAM_ID_LEN);
304 (void) mavlink_msg_param_set_pack_chan(
309 static_cast<uint8_t
>(_vehicle->
id()),
310 static_cast<uint8_t
>(componentId),
312 union_value.param_float,
313 static_cast<uint8_t
>(paramType));
316 auto checkForCorrectParamValue = [
this, componentId, paramName, rawValue](
const mavlink_message_t &message) ->
bool {
317 if (message.compid != componentId) {
321 mavlink_param_value_t param_value{};
322 mavlink_msg_param_value_decode(&message, ¶m_value);
325 char parameterNameWithNull[MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1] = {};
326 (void) strncpy(parameterNameWithNull, param_value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
327 const QString parameterName(parameterNameWithNull);
329 if (parameterName != paramName) {
334 QVariant receivedValue;
336 param_union.param_float = param_value.param_value;
337 param_union.type = param_value.param_type;
338 if (!_mavlinkParamUnionToVariant(param_union, receivedValue)) {
341 if (rawValue.typeId() != receivedValue.typeId()) {
342 qCWarning(ParameterManagerLog) <<
"QVariant type mismatch on PARAM_VALUE ack for" << paramName <<
": expected type" << rawValue.typeId() <<
"got type" << receivedValue.typeId();
345 if (param_value.param_type == MAV_PARAM_TYPE_REAL32) {
349 return receivedValue == rawValue;
353 auto checkForParamError = [componentId, paramName](
const mavlink_message_t &message) ->
bool {
354 if (message.compid != componentId) {
358 mavlink_param_error_t paramError{};
359 mavlink_msg_param_error_decode(&message, ¶mError);
361 char paramId[MAVLINK_MSG_PARAM_ERROR_FIELD_PARAM_ID_LEN + 1] = {};
362 (void) strncpy(paramId, paramError.param_id, MAVLINK_MSG_PARAM_ERROR_FIELD_PARAM_ID_LEN);
364 return QString(paramId) == paramName;
384 auto incPendingWriteCountState =
new FunctionState(QStringLiteral(
"ParameterManager increment pending write count"), stateMachine, [
this]() {
385 _incrementPendingWriteCount();
387 auto decPendingWriteCountState =
new FunctionState(QStringLiteral(
"ParameterManager decrement pending write count"), stateMachine, [
this]() {
388 _decrementPendingWriteCount();
390 auto retryDecPendingWriteCountState =
new FunctionState(QStringLiteral(
"ParameterManager retry decrement pending write count"), stateMachine, [
this]() {
391 _decrementPendingWriteCount();
393 auto errorDecPendingWriteCountState =
new FunctionState(QStringLiteral(
"ParameterManager error decrement pending write count"), stateMachine, [
this]() {
394 _decrementPendingWriteCount();
396 auto waitAckState =
new WaitForParamResponseState(stateMachine, _waitForParamValueAckMs, checkForCorrectParamValue, checkForParamError);
397 auto paramRefreshState =
new FunctionState(QStringLiteral(
"ParameterManager param refresh"), stateMachine, [
this, componentId, paramName]() {
400 auto userNotifyState =
new FunctionState(QStringLiteral(
"ParameterManager user notify"), stateMachine, [waitAckState, paramName,
this, componentId]() {
401 const QString errorDetail = waitAckState->lastParamErrorString();
402 const QString msg = errorDetail.isEmpty()
403 ? QStringLiteral(
"Parameter write failed: param: %1 %2").arg(paramName, _vehicleAndComponentString(componentId))
404 : QStringLiteral(
"Parameter write failed: param: %1 %2 - %3").arg(paramName, _vehicleAndComponentString(componentId), errorDetail);
407 auto logSuccessState =
new FunctionState(QStringLiteral(
"ParameterManager log success"), stateMachine, [
this, componentId, paramName]() {
408 qCDebug(ParameterManagerLog) <<
"Parameter write succeeded: param:" << paramName << _vehicleAndComponentString(componentId);
411 auto logFailureState =
new FunctionState(QStringLiteral(
"ParameterManager log failure"), stateMachine, [
this, componentId, paramName]() {
412 qCDebug(ParameterManagerLog) <<
"Parameter write failed: param:" << paramName << _vehicleAndComponentString(componentId);
418 stateMachine->setInitialState(sendParamSetState);
419 sendParamSetState->addThisTransition (&
QGCState::advance, incPendingWriteCountState);
434 sendParamSetState->addThisTransition(&
QGCState::error, logFailureState);
441 qCDebug(ParameterManagerLog) <<
"Starting state machine for PARAM_SET on: " << paramName << _vehicleAndComponentString(componentId);
442 stateMachine->start();
451 paramUnion.param_uint8 =
static_cast<uint8_t
>(rawValue.toUInt(&ok));
454 paramUnion.param_int8 =
static_cast<int8_t
>(rawValue.toInt(&ok));
457 paramUnion.param_uint16 =
static_cast<uint16_t
>(rawValue.toUInt(&ok));
460 paramUnion.param_int16 =
static_cast<int16_t
>(rawValue.toInt(&ok));
463 paramUnion.param_uint32 =
static_cast<uint32_t
>(rawValue.toUInt(&ok));
466 paramUnion.param_float = rawValue.toFloat(&ok);
469 paramUnion.param_int32 =
static_cast<int32_t
>(rawValue.toInt(&ok));
472 qCCritical(ParameterManagerLog) <<
"Internal Error: Unsupported fact value type" << valueType;
473 paramUnion.param_int32 =
static_cast<int32_t
>(rawValue.toInt(&ok));
478 qCCritical(ParameterManagerLog) <<
"Fact Failed to Convert to Param Type:" << valueType;
485bool ParameterManager::_mavlinkParamUnionToVariant(
const mavlink_param_union_t ¶mUnion, QVariant &outValue)
const
487 switch (paramUnion.type) {
488 case MAV_PARAM_TYPE_REAL32:
489 outValue = QVariant(paramUnion.param_float);
491 case MAV_PARAM_TYPE_UINT8:
492 outValue = QVariant(paramUnion.param_uint8);
494 case MAV_PARAM_TYPE_INT8:
495 outValue = QVariant(paramUnion.param_int8);
497 case MAV_PARAM_TYPE_UINT16:
498 outValue = QVariant(paramUnion.param_uint16);
500 case MAV_PARAM_TYPE_INT16:
501 outValue = QVariant(paramUnion.param_int16);
503 case MAV_PARAM_TYPE_UINT32:
504 outValue = QVariant(paramUnion.param_uint32);
506 case MAV_PARAM_TYPE_INT32:
507 outValue = QVariant(paramUnion.param_int32);
510 qCCritical(ParameterManagerLog) <<
"ParameterManager::_mavlinkParamUnionToVariant - unsupported MAV_PARAM_TYPE" << paramUnion.type;
515void ParameterManager::_factRawValueUpdated(
const QVariant &rawValue)
517 Fact *
const fact = qobject_cast<Fact*>(sender());
519 qCWarning(ParameterManagerLog) <<
"Internal error";
526void ParameterManager::_ftpDownloadComplete(
const QString &fileName,
const QString &errorMsg)
528 bool continueWithDefaultParameterdownload =
true;
529 bool immediateRetry =
false;
534 if (errorMsg.isEmpty()) {
535 qCDebug(ParameterManagerLog) <<
"ParameterManager::_ftpDownloadComplete : Parameter file received:" << fileName;
536 if (_parseParamFile(fileName)) {
537 qCDebug(ParameterManagerLog) <<
"ParameterManager::_ftpDownloadComplete : Parsed!";
540 qCDebug(ParameterManagerLog) <<
"ParameterManager::_ftpDownloadComplete : Error in parameter file";
543 }
else if (errorMsg.contains(
"File Not Found")) {
544 qCDebug(ParameterManagerLog) <<
"ParameterManager-ftp: No Parameterfile on vehicle - Start Conventional Parameter Download";
545 if (_initialRequestRetryCount == 0) {
546 immediateRetry =
true;
548 }
else if ((_loadProgress > 0.0001) && (_loadProgress < 0.01)) {
549 qCDebug(ParameterManagerLog) <<
"ParameterManager-ftp progress too slow - Start Conventional Parameter Download";
550 }
else if (_initialRequestRetryCount == 1) {
551 qCDebug(ParameterManagerLog) <<
"ParameterManager-ftp: Too many retries - Start Conventional Parameter Download";
553 qCDebug(ParameterManagerLog) <<
"ParameterManager-ftp Retry:" << _initialRequestRetryCount;
554 continueWithDefaultParameterdownload =
false;
557 if (continueWithDefaultParameterdownload) {
559 _initialRequestRetryCount = 0;
564 if (immediateRetry) {
565 _paramRequestListTimeout();
567 _paramRequestListTimer.start();
570 _paramRequestListTimer.start();
574void ParameterManager::_ftpDownloadProgress(
float progress)
576 qCDebug(ParameterManagerVerbose1Log) <<
"ParameterManager::_ftpDownloadProgress:" << progress;
577 _setLoadProgress(
static_cast<double>(progress));
578 if (progress > 0.001) {
579 _paramRequestListTimer.stop();
583void ParameterManager::_resetHashCheck()
585 _hashCheckTimer.stop();
586 _hashCheckDone =
false;
593 _startParameterDownload(componentId);
599 _cacheOnlyHashCheck =
true;
607 if (sharedLink->linkConfiguration()->isHighLatency() || _logReplay) {
608 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Cache-only hash check: high latency or log replay link, signalling failure";
613 if (_vehicle->
px4Firmware() && !_initialLoadComplete) {
614 _hashCheckTimer.start();
615 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Cache-only hash check: requesting _HASH_CHECK";
616 _requestHashCheck(MAV_COMP_ID_AUTOPILOT1);
618 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Cache-only hash check: not available, signalling failure";
623void ParameterManager::_startParameterDownload(uint8_t componentId)
630 if (sharedLink->linkConfiguration()->isHighLatency() || _logReplay) {
632 _parametersReady =
true;
633 _missingParameters =
true;
634 _initialLoadComplete =
true;
635 _waitingForDefaultComponent =
false;
641 if (_tryftp && ((componentId == MAV_COMP_ID_ALL) || (componentId == MAV_COMP_ID_AUTOPILOT1))) {
642 if (!_initialLoadComplete) {
643 _paramRequestListTimer.start();
647 _waitingParamTimeoutTimer.stop();
648 if (ftpManager->
download(MAV_COMP_ID_AUTOPILOT1,
649 QStringLiteral(
"@PARAM/param.pck?withdefaults=1"),
650 QStandardPaths::writableLocation(QStandardPaths::TempLocation),
651 QStringLiteral(
"param.pck"),
655 qCWarning(ParameterManagerLog) <<
"ParameterManager::_startParameterDownload FTPManager::download returned failure";
658 }
else if (_vehicle->
px4Firmware() && !_initialLoadComplete && !_hashCheckDone) {
660 _cacheOnlyHashCheck =
false;
661 _hashCheckTimer.start();
662 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Requesting _HASH_CHECK before full parameter list";
663 const uint8_t hashCheckCompId = (componentId == MAV_COMP_ID_ALL)
664 ?
static_cast<uint8_t
>(MAV_COMP_ID_AUTOPILOT1)
666 _requestHashCheck(hashCheckCompId);
668 if (!_initialLoadComplete) {
669 _paramRequestListTimer.start();
673 for (
int cid: _paramCountMap.keys()) {
675 if ((componentId != MAV_COMP_ID_ALL) && (componentId != cid)) {
678 for (
int waitingIndex = 0; waitingIndex < _paramCountMap[cid]; waitingIndex++) {
680 _waitingReadParamIndexMap[cid][waitingIndex] = 0;
687 sharedLink->mavlinkChannel(),
694 const QString what = (componentId == MAV_COMP_ID_ALL) ?
"MAV_COMP_ID_ALL" : QString::number(componentId);
695 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Request to refresh all parameters for component ID:" << what;
698int ParameterManager::_actualComponentId(
int componentId)
const
703 qCWarning(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Default component id not set";
712 componentId = _actualComponentId(componentId);
714 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"refreshParameter - name:" << paramName <<
")";
716 _mavlinkParamRequestRead(componentId, paramName, -1,
true );
721 componentId = _actualComponentId(componentId);
722 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"refreshParametersPrefix - name:" << namePrefix <<
")";
724 if (!_mapCompId2FactMap.contains(componentId)) {
727 for (
const QString ¶mName: _mapCompId2FactMap[componentId].keys()) {
728 if (paramName.startsWith(namePrefix)) {
736 componentId = _actualComponentId(componentId);
738 if (!_mapCompId2FactMap.contains(componentId)) {
741 const QMap<QString, Fact *> &factMap = _mapCompId2FactMap[componentId];
742 QStringList resolved;
744 for (
const QString &entry : names) {
745 if (entry.endsWith(QLatin1Char(
'*'))) {
746 const QString prefix = entry.chopped(1);
747 if (prefix.isEmpty()) {
748 qCWarning(ParameterManagerLog) <<
"bulkRefresh: ignoring bare '*' entry";
751 for (
auto it = factMap.cbegin(); it != factMap.cend(); ++it) {
752 if (it.key().startsWith(prefix) && !seen.contains(it.key())) {
753 seen.insert(it.key());
754 resolved.append(it.key());
757 }
else if (factMap.contains(entry)) {
758 if (!seen.contains(entry)) {
760 resolved.append(entry);
763 qCWarning(ParameterManagerLog) <<
"bulkRefresh: unknown param name (skipped):" << entry;
767 if (resolved.isEmpty()) {
771 qCDebug(ParameterManagerLog) <<
"bulkRefresh: resolved" << resolved.count() <<
"params";
773 this, componentId, resolved, notifyFailure,
774 [
this, componentId](
const QString &name) {
775 _mavlinkParamRequestRead(componentId, name, -1,
false );
784 componentId = _actualComponentId(componentId);
785 if (_mapCompId2FactMap.contains(componentId)) {
786 ret = _mapCompId2FactMap[componentId].contains(_remapParamNameToVersion(paramName));
794 componentId = _actualComponentId(componentId);
796 const QString mappedParamName = _remapParamNameToVersion(paramName);
797 if (!_mapCompId2FactMap.contains(componentId) || !_mapCompId2FactMap[componentId].contains(mappedParamName)) {
798 qgcApp()->reportMissingParameter(componentId, mappedParamName);
799 return &_defaultFact;
802 return _mapCompId2FactMap[componentId][mappedParamName];
809 const int compId = _actualComponentId(componentId);
810 const QMap<QString, Fact*> &factMap = _mapCompId2FactMap[compId];
811 for (
const QString ¶mName: factMap.keys()) {
818bool ParameterManager::_fillIndexBatchQueue(
bool waitingParamTimeout)
820 if (!_indexBatchQueueActive) {
824 constexpr int maxBatchSize = 10;
826 if (waitingParamTimeout) {
828 qCDebug(ParameterManagerLog) <<
"Refilling index based batch queue due to timeout";
829 _indexBatchQueue.clear();
831 qCDebug(ParameterManagerLog) <<
"Refilling index based batch queue due to received parameter";
834 for (
const int componentId: _waitingReadParamIndexMap.keys()) {
835 if (_waitingReadParamIndexMap[componentId].count()) {
836 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"_waitingReadParamIndexMap count" << _waitingReadParamIndexMap[componentId].count();
837 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"_waitingReadParamIndexMap" << _waitingReadParamIndexMap[componentId];
840 for (
const int paramIndex: _waitingReadParamIndexMap[componentId].keys()) {
841 if (_indexBatchQueue.contains(paramIndex)) {
846 if (_indexBatchQueue.count() > maxBatchSize) {
850 _waitingReadParamIndexMap[componentId][paramIndex]++;
851 if (_disableAllRetries || (_waitingReadParamIndexMap[componentId][paramIndex] > _maxInitialLoadRetrySingleParam)) {
853 _failedReadParamIndexMap[componentId] << paramIndex;
854 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"Giving up on (paramIndex:" << paramIndex <<
"retryCount:" << _waitingReadParamIndexMap[componentId][paramIndex] <<
")";
855 (void) _waitingReadParamIndexMap[componentId].remove(paramIndex);
858 _indexBatchQueue.append(paramIndex);
859 _mavlinkParamRequestRead(componentId, QString(), paramIndex,
false );
860 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"Read re-request for (paramIndex:" << paramIndex <<
"retryCount:" << _waitingReadParamIndexMap[componentId][paramIndex] <<
")";
865 return (!_indexBatchQueue.isEmpty());
868void ParameterManager::_waitingParamTimeout()
874 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"_waitingParamTimeout";
877 _indexBatchQueueActive =
true;
880 bool paramsRequested = _fillIndexBatchQueue(
true );
881 if (!paramsRequested && !_waitingForDefaultComponent && !_mapCompId2FactMap.contains(_vehicle->
defaultComponentId())) {
884 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Restarting _waitingParamTimeoutTimer - still don't have default component params" << _vehicle->
defaultComponentId();
885 _waitingParamTimeoutTimer.start();
886 _waitingForDefaultComponent =
true;
889 _waitingForDefaultComponent =
false;
891 _checkInitialLoadComplete();
893 if (paramsRequested) {
894 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Restarting _waitingParamTimeoutTimer - re-request";
895 _waitingParamTimeoutTimer.start();
899void ParameterManager::_requestHashCheck(uint8_t componentId)
906 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"Sending PARAM_REQUEST_READ for _HASH_CHECK";
908 char paramId[MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN + 1] = {};
909 (void) strncpy(paramId,
"_HASH_CHECK", MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN);
912 (void) mavlink_msg_param_request_read_pack_chan(
915 sharedLink->mavlinkChannel(),
917 static_cast<uint8_t
>(_vehicle->
id()),
925void ParameterManager::_mavlinkParamRequestRead(
int componentId,
const QString ¶mName,
int paramIndex,
bool notifyFailure)
927 auto paramRequestReadEncoder = [
this, componentId, paramName, paramIndex](uint8_t , uint8_t channel,
mavlink_message_t *message) ->
void {
928 char paramId[MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN + 1] = {};
929 (void) strncpy(paramId, paramName.toLocal8Bit().constData(), MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN);
935 static_cast<uint8_t
>(_vehicle->
id()),
936 static_cast<uint8_t
>(componentId),
938 static_cast<int16_t
>(paramIndex));
941 auto checkForCorrectParamValue = [componentId, paramName, paramIndex](
const mavlink_message_t &message) ->
bool {
942 if (message.compid != componentId) {
946 mavlink_param_value_t param_value{};
947 mavlink_msg_param_value_decode(&message, ¶m_value);
950 char parameterNameWithNull[MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN + 1] = {};
951 (void) strncpy(parameterNameWithNull, param_value.param_id, MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN);
952 const QString parameterName(parameterNameWithNull);
955 if (paramIndex != -1) {
957 if (param_value.param_index != paramIndex) {
962 if (parameterName != paramName) {
970 auto checkForParamError = [componentId, paramName, paramIndex](
const mavlink_message_t &message) ->
bool {
971 if (message.compid != componentId) {
975 mavlink_param_error_t paramError{};
976 mavlink_msg_param_error_decode(&message, ¶mError);
978 char paramId[MAVLINK_MSG_PARAM_ERROR_FIELD_PARAM_ID_LEN + 1] = {};
979 (void) strncpy(paramId, paramError.param_id, MAVLINK_MSG_PARAM_ERROR_FIELD_PARAM_ID_LEN);
981 if (paramIndex != -1) {
982 return paramError.param_index == paramIndex;
984 return QString(paramId) == paramName;
1001 auto waitAckState =
new WaitForParamResponseState(stateMachine, _waitForParamValueAckMs, checkForCorrectParamValue, checkForParamError);
1002 auto userNotifyState =
new FunctionState(QStringLiteral(
"User notify"), stateMachine, [waitAckState, paramName,
this, componentId]() {
1003 const QString errorDetail = waitAckState->lastParamErrorString();
1004 const QString msg = errorDetail.isEmpty()
1005 ? QStringLiteral(
"Parameter read failed: param: %1 %2").arg(paramName, _vehicleAndComponentString(componentId))
1006 : QStringLiteral(
"Parameter read failed: param: %1 %2 - %3").arg(paramName, _vehicleAndComponentString(componentId), errorDetail);
1009 auto logSuccessState =
new FunctionState(QStringLiteral(
"Log success"), stateMachine, [
this, componentId, paramName, paramIndex]() {
1010 qCDebug(ParameterManagerLog) <<
"PARAM_REQUEST_READ succeeded: name:" << paramName <<
"index" << paramIndex << _vehicleAndComponentString(componentId);
1013 auto logFailureState =
new FunctionState(QStringLiteral(
"Log failure"), stateMachine, [
this, componentId, paramName, paramIndex]() {
1014 qCDebug(ParameterManagerLog) <<
"PARAM_REQUEST_READ failed: param:" << paramName <<
"index" << paramIndex << _vehicleAndComponentString(componentId);
1020 stateMachine->setInitialState(sendParamRequestReadState);
1032 sendParamRequestReadState->addThisTransition(&
QGCState::error, logFailureState);
1035 if (notifyFailure) {
1042 qCDebug(ParameterManagerLog) <<
"Starting state machine for PARAM_REQUEST_READ on: " << paramName << _vehicleAndComponentString(componentId);
1043 stateMachine->start();
1046void ParameterManager::_writeLocalParamCache(
int vehicleId,
int componentId)
1048 CacheMapName2ParamTypeVal cacheMap;
1050 for (
const QString ¶mName: _mapCompId2FactMap[componentId].keys()) {
1051 const Fact *
const fact = _mapCompId2FactMap[componentId][paramName];
1052 cacheMap[paramName] = ParamTypeVal(fact->
type(), fact->
rawValue());
1056 if (cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1057 QDataStream ds(&cacheFile);
1060 qCWarning(ParameterManagerLog) <<
"Failed to open cache file for writing" << cacheFile.fileName();
1067 const QFileInfo settingsFile(QSettings().fileName());
1068 const QString basePath = settingsFile.dir().absolutePath();
1069 const QString appName = settingsFile.completeBaseName();
1070 return QDir(basePath + QDir::separator() + appName + QDir::separator() + QStringLiteral(
"ParamCache"));
1075 return parameterCacheDir().filePath(QStringLiteral(
"%1_%2.v2").arg(vehicleId).arg(componentId));
1078void ParameterManager::_tryCacheHashLoad(
int vehicleId,
int componentId,
const QVariant &hashValue)
1080 qCDebug(ParameterManagerLog) <<
"Attemping load from cache";
1083 CacheMapName2ParamTypeVal cacheMap;
1085 if (!cacheFile.exists()) {
1086 qCDebug(ParameterManagerLog) <<
"No parameter cache file";
1087 if (!_hashCheckDone) {
1088 _hashCheckDone =
true;
1089 if (_cacheOnlyHashCheck) {
1090 qCDebug(ParameterManagerLog) <<
"Cache-only hash check: no cache file, signalling failure";
1095 _startParameterDownload(MAV_COMP_ID_ALL);
1100 (void) cacheFile.open(QIODevice::ReadOnly);
1103 QDataStream ds(&cacheFile);
1107 uint32_t crc32_value = 0;
1108 for (
const QString &name: cacheMap.keys()) {
1109 const ParamTypeVal ¶mTypeVal = cacheMap[name];
1114 qCDebug(ParameterManagerLog) <<
"Volatile parameter" << name;
1116 const void *
const vdat = paramTypeVal.second.constData();
1118 crc32_value =
QGC::crc32(
reinterpret_cast<const uint8_t *
>(qPrintable(name)), name.length(), crc32_value);
1124 if (crc32_value == hashValue.toUInt()) {
1125 _hashCheckDone =
true;
1126 _paramRequestListTimer.stop();
1127 qCDebug(ParameterManagerLog) <<
"Parameters loaded from cache" << qPrintable(QFileInfo(cacheFile).absoluteFilePath());
1129 const int count = cacheMap.count();
1131 for (
const QString &name: cacheMap.keys()) {
1132 const ParamTypeVal ¶mTypeVal = cacheMap[name];
1135 _handleParamValue(componentId, name, count, index++, mavParamType, paramTypeVal.second);
1140 mavlink_param_set_t p{};
1144 p.param_type = MAV_PARAM_TYPE_UINT32;
1145 (void) strncpy(p.param_id,
"_HASH_CHECK",
sizeof(p.param_id));
1146 union_value.param_uint32 = crc32_value;
1147 p.param_value = union_value.param_float;
1148 p.target_system =
static_cast<uint8_t
>(_vehicle->
id());
1149 p.target_component =
static_cast<uint8_t
>(componentId);
1154 sharedLink->mavlinkChannel(),
1161 QVariantAnimation *
const ani =
new QVariantAnimation(
this);
1162 ani->setEasingCurve(QEasingCurve::OutCubic);
1163 ani->setStartValue(0.0);
1164 ani->setEndValue(1.0);
1165 ani->setDuration(750);
1167 (void) connect(ani, &QVariantAnimation::valueChanged,
this, [
this](
const QVariant &value) {
1168 _setLoadProgress(value.toDouble());
1172 connect(ani, &QVariantAnimation::finished,
this, [
this] {
1173 QTimer::singleShot(500,
this, [
this] {
1174 _setLoadProgress(0);
1178 ani->start(QAbstractAnimation::DeleteWhenStopped);
1180 qCDebug(ParameterManagerLog) <<
"Parameters cache match failed" << qPrintable(QFileInfo(cacheFile).absoluteFilePath());
1181 if (ParameterManagerDebugCacheFailureLog().isDebugEnabled()) {
1182 _debugCacheCRC[componentId] =
true;
1183 _debugCacheMap[componentId] = cacheMap;
1184 for (
const QString &name: cacheMap.keys()) {
1185 _debugCacheParamSeen[componentId][name] =
false;
1189 if (!_hashCheckDone) {
1190 _hashCheckDone =
true;
1191 if (_cacheOnlyHashCheck) {
1192 qCDebug(ParameterManagerLog) <<
"Cache-only hash check: CRC mismatch, signalling failure";
1197 _startParameterDownload(MAV_COMP_ID_ALL);
1205 stream <<
"# Onboard parameters for Vehicle " << _vehicle->
id() <<
"\n";
1210 stream <<
"# Version: "
1215 stream <<
"# Git Revision: " << _vehicle->
gitHash() <<
"\n";
1218 stream <<
"# Vehicle-Id Component-Id Name Value Type\n";
1220 for (
const int componentId: _mapCompId2FactMap.keys()) {
1221 for (
const QString ¶mName: _mapCompId2FactMap[componentId].keys()) {
1222 const Fact *
const fact = _mapCompId2FactMap[componentId][paramName];
1226 qCWarning(ParameterManagerLog) <<
"Internal error: missing fact";
1238 return MAV_PARAM_TYPE_UINT8;
1240 return MAV_PARAM_TYPE_INT8;
1242 return MAV_PARAM_TYPE_UINT16;
1244 return MAV_PARAM_TYPE_INT16;
1246 return MAV_PARAM_TYPE_UINT32;
1248 return MAV_PARAM_TYPE_UINT64;
1250 return MAV_PARAM_TYPE_INT64;
1252 return MAV_PARAM_TYPE_REAL32;
1254 return MAV_PARAM_TYPE_REAL64;
1256 qCWarning(ParameterManagerLog) <<
"Unsupported fact type" << factType;
1259 return MAV_PARAM_TYPE_INT32;
1266 case MAV_PARAM_TYPE_UINT8:
1268 case MAV_PARAM_TYPE_INT8:
1270 case MAV_PARAM_TYPE_UINT16:
1272 case MAV_PARAM_TYPE_INT16:
1274 case MAV_PARAM_TYPE_UINT32:
1276 case MAV_PARAM_TYPE_UINT64:
1278 case MAV_PARAM_TYPE_INT64:
1280 case MAV_PARAM_TYPE_REAL32:
1282 case MAV_PARAM_TYPE_REAL64:
1285 qCWarning(ParameterManagerLog) <<
"Unsupported mav param type" << mavType;
1287 case MAV_PARAM_TYPE_INT32:
1292void ParameterManager::_checkInitialLoadComplete()
1294 if (_initialLoadComplete) {
1298 for (
const int componentId: _waitingReadParamIndexMap.keys()) {
1299 if (!_waitingReadParamIndexMap[componentId].isEmpty()) {
1311 _initialLoadComplete =
true;
1314 for (
const int componentId: _debugCacheParamSeen.keys()) {
1315 if (!_logReplay && _debugCacheCRC.contains(componentId) && _debugCacheCRC[componentId]) {
1316 for (
const QString ¶mName: _debugCacheParamSeen[componentId].keys()) {
1317 if (!_debugCacheParamSeen[componentId][paramName]) {
1318 qCDebug(ParameterManagerLog) <<
"Parameter in cache but not on vehicle componentId:Name" << componentId << paramName;
1323 _debugCacheCRC.clear();
1325 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Initial load complete";
1329 bool initialLoadFailures =
false;
1330 for (
const int componentId: _failedReadParamIndexMap.keys()) {
1331 for (
const int paramIndex: _failedReadParamIndexMap[componentId]) {
1332 if (initialLoadFailures) {
1335 indexList += QStringLiteral(
"%1:%2").arg(componentId).arg(paramIndex);
1336 initialLoadFailures =
true;
1337 qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) <<
"Gave up on initial load after max retries (paramIndex:" << paramIndex <<
")";
1341 _missingParameters =
false;
1342 if (initialLoadFailures) {
1343 _missingParameters =
true;
1344 const QString errorMsg = tr(
"%1 was unable to retrieve the full set of parameters from vehicle %2. "
1345 "This will cause %1 to be unable to display its full user interface. "
1346 "If you are using modified firmware, you may need to resolve any vehicle startup errors to resolve the issue. "
1347 "If you are using standard firmware, you may need to upgrade to a newer version to resolve the issue.").arg(QCoreApplication::applicationName()).arg(_vehicle->
id());
1348 qCDebug(ParameterManagerLog) << errorMsg;
1351 qCWarning(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"The following parameter indices could not be loaded after the maximum number of retries:" << indexList;
1356 _parametersReady =
true;
1362void ParameterManager::_hashCheckTimeout()
1364 _hashCheckDone =
true;
1365 if (_cacheOnlyHashCheck) {
1366 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"_HASH_CHECK timed out in cache-only mode, signalling failure";
1370 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"_HASH_CHECK timed out, falling back to PARAM_REQUEST_LIST";
1371 _startParameterDownload(MAV_COMP_ID_ALL);
1374void ParameterManager::_paramRequestListTimeout()
1378 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"_paramRequestListTimeout (log replay): Signalling load complete";
1379 _initialLoadComplete =
true;
1380 _missingParameters =
false;
1381 _parametersReady =
true;
1388 if (!_disableAllRetries && (++_initialRequestRetryCount <= _maxInitialRequestListRetry)) {
1389 qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) <<
"Retrying initial parameter request list";
1390 _startParameterDownload(MAV_COMP_ID_ALL);
1392 const QString errorMsg = tr(
"Vehicle %1 did not respond to request for parameters. "
1393 "This will cause %2 to be unable to display its full user interface.").arg(_vehicle->
id()).arg(QCoreApplication::applicationName());
1394 qCDebug(ParameterManagerLog) << errorMsg;
1399QString ParameterManager::_remapParamNameToVersion(
const QString ¶mName)
const
1401 static const QString noRemapPrefix = QStringLiteral(
"noremap.");
1402 if (paramName.startsWith(noRemapPrefix)) {
1403 return paramName.mid(noRemapPrefix.length());
1415 if (!majorVersionRemap.contains(majorVersion)) {
1417 qCDebug(ParameterManagerLog) <<
"_remapParamNameToVersion: no major version mapping";
1423 QString mappedParamName = paramName;
1425 if (remapMinorVersion.contains(currentMinorVersion)) {
1427 if (remap.contains(mappedParamName)) {
1428 const QString toParamName = remap[mappedParamName];
1429 qCDebug(ParameterManagerLog) <<
"_remapParamNameToVersion: remapped currentMinor:from:to" << currentMinorVersion << mappedParamName << toParamName;
1430 mappedParamName = toParamName;
1435 return mappedParamName;
1438void ParameterManager::_loadOfflineEditingParams()
1441 if (paramFilename.isEmpty()) {
1445 QFile paramFile(paramFilename);
1446 if (!paramFile.open(QFile::ReadOnly)) {
1447 qCWarning(ParameterManagerLog) <<
"Unable to open offline editing params file" << paramFilename;
1450 QTextStream paramStream(¶mFile);
1451 while (!paramStream.atEnd()) {
1452 const QString line = paramStream.readLine();
1453 if (line.startsWith(
"#")) {
1457 const QStringList paramData = line.split(
"\t");
1458 Q_ASSERT(paramData.count() == 5);
1460 const int offlineDefaultComponentId = paramData.at(1).toInt();
1462 const QString paramName = paramData.at(2);
1463 const QString valStr = paramData.at(3);
1464 const MAV_PARAM_TYPE paramType =
static_cast<MAV_PARAM_TYPE
>(paramData.at(4).toUInt());
1466 QVariant paramValue;
1467 switch (paramType) {
1468 case MAV_PARAM_TYPE_REAL32:
1469 paramValue = QVariant(valStr.toFloat());
1471 case MAV_PARAM_TYPE_UINT32:
1472 paramValue = QVariant(valStr.toUInt());
1474 case MAV_PARAM_TYPE_UINT16:
1475 paramValue = QVariant((quint16)valStr.toUInt());
1477 case MAV_PARAM_TYPE_INT16:
1478 paramValue = QVariant((qint16)valStr.toInt());
1480 case MAV_PARAM_TYPE_UINT8:
1481 paramValue = QVariant((quint8)valStr.toUInt());
1483 case MAV_PARAM_TYPE_INT8:
1484 paramValue = QVariant((qint8)valStr.toUInt());
1487 qCCritical(ParameterManagerLog) <<
"Unknown type" << paramType;
1489 case MAV_PARAM_TYPE_INT32:
1490 paramValue = QVariant(valStr.toInt());
1502 _parametersReady =
true;
1503 _initialLoadComplete =
true;
1504 _debugCacheCRC.clear();
1510 MAV_CMD_PREFLIGHT_STORAGE,
1520 if (sysAutoConfigFact) {
1525QString ParameterManager::_logVehiclePrefix(
int componentId)
const
1527 if (componentId == -1) {
1528 return QStringLiteral(
"V:%1").arg(_vehicle->
id());
1530 return QStringLiteral(
"V:%1 C:%2").arg(_vehicle->
id()).arg(componentId);
1534void ParameterManager::_setLoadProgress(
double loadProgress)
1544 if (_parameterDownloadSkipped != skipped) {
1545 _parameterDownloadSkipped = skipped;
1552 return _paramCountMap.keys();
1557 return _pendingWritesCount > 0;
1560#ifdef QGC_UNITTEST_BUILD
1561void ParameterManager::setPendingWritesForTest(
bool pending)
1563 const bool wasPending = (_pendingWritesCount > 0);
1564 _pendingWritesCount = pending ? 1 : 0;
1565 if (wasPending != pending) {
1577bool ParameterManager::_parseParamFile(
const QString& filename)
1579 constexpr quint16 magic_standard = 0x671B;
1580 constexpr quint16 magic_withdefaults = 0x671C;
1581 quint32 no_of_parameters_found = 0;
1582 constexpr int componentId = MAV_COMP_ID_AUTOPILOT1;
1593 qCDebug(ParameterManagerLog) <<
"_parseParamFile:" << filename;
1594 QFile file(filename);
1595 if (!file.open(QIODevice::ReadOnly)) {
1596 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: Could not open downloaded parameter file.";
1600 QDataStream in(&file);
1601 in.setByteOrder(QDataStream::LittleEndian);
1603 quint16 magic, num_params, total_params;
1608 if (in.status() != QDataStream::Ok) {
1609 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: Could not read Header";
1613 qCDebug(ParameterManagerVerbose2Log) <<
"_parseParamFile: magic: 0x" << Qt::hex << magic;
1614 qCDebug(ParameterManagerVerbose2Log) <<
"_parseParamFile: num_params:" << num_params
1615 <<
"total_params:" << total_params;
1617 if ((magic != magic_standard) && (magic != magic_withdefaults)) {
1618 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: File does not start with Magic";
1621 if (num_params > total_params) {
1622 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: total_params > num_params";
1625 if (num_params != total_params) {
1627 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: total_params != num_params";
1631 while (in.status() == QDataStream::Ok) {
1635 quint8 name_len = 0;
1636 quint8 common_len = 0;
1637 bool withdefault =
false;
1639 char name_buffer[17];
1641 while (
byte == 0x0) {
1643 if (in.status() != QDataStream::Ok) {
1644 if (no_of_parameters_found == num_params) {
1647 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: unexpected EOF"
1648 <<
"number of parameters expected:" << num_params
1649 <<
"actual:" << no_of_parameters_found;
1654 ptype =
byte & 0x0F;
1655 flags = (
byte >> 4) & 0x0F;
1656 withdefault = (flags & 0x01) == 0x01;
1658 if (in.status() != QDataStream::Ok) {
1659 qCritical(ParameterManagerLog) <<
"_parseParamFile: Error: Unexpected EOF while reading flags";
1662 name_len = ((
byte >> 4) & 0x0F) + 1;
1663 common_len =
byte & 0x0F;
1664 if ((name_len + common_len) > 16) {
1665 qCritical(ParameterManagerLog) <<
"_parseParamFile: Error: common_len + name_len > 16"
1666 <<
"name_len" << name_len
1667 <<
"common_len" << common_len;
1670 no_read = in.readRawData(&name_buffer[common_len],
static_cast<int>(name_len));
1671 if (no_read != name_len) {
1672 qCritical(ParameterManagerLog) <<
"_parseParamFile: Error: Unexpected EOF while reading parameterName"
1673 <<
"Expected:" << name_len
1674 <<
"Actual:" << no_read;
1677 name_buffer[common_len + name_len] =
'\0';
1678 const QString parameterName(name_buffer);
1679 qCDebug(ParameterManagerVerbose2Log) <<
"_parseParamFile: parameter" << parameterName
1680 <<
"name_len" << name_len
1681 <<
"common_len" << common_len
1683 <<
"flags" << flags;
1685 QVariant parameterValue = 0;
1686 QVariant defaultValue;
1687 switch (
static_cast<ap_var_type
>(ptype)) {
1694 parameterValue = data8;
1697 defaultValue = data8;
1700 case AP_PARAM_INT16:
1702 parameterValue = data16;
1705 defaultValue = data16;
1708 case AP_PARAM_INT32:
1710 parameterValue = data32;
1713 defaultValue = data32;
1716 case AP_PARAM_FLOAT:
1718 (void) memcpy(&dfloat, &data32, 4);
1719 parameterValue = dfloat;
1723 (void) memcpy(&ddefault, &data32, 4);
1724 defaultValue = ddefault;
1728 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: type is out of range" << ptype;
1732 qCDebug(ParameterManagerVerbose2Log) <<
"paramValue" << parameterValue;
1734 if (++no_of_parameters_found > num_params) {
1735 qCDebug(ParameterManagerLog) <<
"_parseParamFile: Error: more parameters in file than expected."
1736 <<
"Expected:" << num_params
1737 <<
"Actual:" << no_of_parameters_found;
1742 (ptype == AP_PARAM_INT16) ?
FactMetaData::valueTypeInt16 :
1743 (ptype == AP_PARAM_INT32) ?
FactMetaData::valueTypeInt32 :
1746 Fact *fact =
nullptr;
1747 if (_mapCompId2FactMap.contains(componentId) && _mapCompId2FactMap[componentId].contains(parameterName)) {
1748 fact = _mapCompId2FactMap[componentId][parameterName];
1749 if (withdefault && defaultValue.isValid()) {
1756 qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"Adding new fact" << parameterName;
1758 fact =
new Fact(componentId, parameterName, factType,
this);
1762 _mapCompId2FactMap[componentId][parameterName] = fact;
1768 if (withdefault && defaultValue.isValid()) {
1780 _paramCountMap[componentId] = num_params;
1781 _totalParamCount += num_params;
1782 _waitingReadParamIndexMap[componentId] = QMap<int, int>();
1783 _checkInitialLoadComplete();
1784 _setLoadProgress(0.0);
1792void ParameterManager::_incrementPendingWriteCount()
1794 _pendingWritesCount++;
1795 if (_pendingWritesCount == 1) {
1800void ParameterManager::_decrementPendingWriteCount()
1802 if (_pendingWritesCount == 0) {
1803 qCWarning(ParameterManagerLog) <<
"Internal Error: _pendingWriteCount == 0";
1807 _pendingWritesCount--;
1808 if (_pendingWritesCount == 0) {
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
struct param_union mavlink_param_union_t
virtual void parametersReadyPreChecks()
FactMetaData * factMetaDataForName(const QString &name, FactMetaData::ValueType_t valueType)
void commandProgress(float value)
void downloadComplete(const QString &file, const QString &errorMsg)
bool download(uint8_t fromCompId, const QString &fromURI, const QString &toDir, const QString &fileName="", bool checksize=true)
A Fact is used to hold a single value within the system.
void setMetaData(FactMetaData *metaData, bool setDefaultFromMetaData=false)
void containerSetRawValue(const QVariant &value)
Value coming from Vehicle. This does NOT send a _containerRawValueChanged signal.
FactMetaData * metaData()
FactMetaData::ValueType_t type() const
void setRawValue(const QVariant &value)
void containerRawValueChanged(const QVariant &value)
This signal is meant for use by Fact container implementations. Used to send changed values to vehicl...
QString rawValueStringFullPrecision() const
Returns the values as a string with full 18 digit precision if float/double.
QVariant rawValue() const
Value after translation.
QMap< int, remapParamNameMap_t > remapParamNameMinorVersionRemapMap_t
virtual int remapParamNameHigestMinorVersionNumber(int) const
QMap< QString, QString > remapParamNameMap_t
virtual QString offlineEditingParamFile(Vehicle *) const
Return the resource file which contains the set of params loaded for offline editing.
QMap< int, remapParamNameMinorVersionRemapMap_t > remapParamNameMajorVersionMap_t
virtual const remapParamNameMajorVersionMap_t & paramNameRemapMajorVersionMap() const
static int getComponentId()
static MAVLinkProtocol * instance()
static MultiVehicleManager * instance()
bool parameterExists(int componentId, const QString ¶mName) const
void parameterDownloadSkippedChanged()
void mavlinkMessageReceived(const mavlink_message_t &message)
Fact * getParameter(int componentId, const QString ¶mName)
void factAdded(int componentId, Fact *fact)
static FactMetaData::ValueType_t mavTypeToFactType(MAV_PARAM_TYPE mavType)
void setParameterDownloadSkipped(bool skipped)
QList< int > componentIds() const
void refreshParametersPrefix(int componentId, const QString &namePrefix)
Request a refresh on all parameters that begin with the specified prefix.
void parametersReadyChanged(bool parametersReady)
double loadProgress() const
void bulkRefresh(int componentId, const QStringList &names, bool notifyFailure=true)
void tryHashCheckCacheLoad()
bool pendingWrites() const
static QDir parameterCacheDir()
void missingParametersChanged(bool missingParameters)
static constexpr int defaultComponentId
void resetAllParametersToDefaults()
QStringList parameterNames(int componentId) const
Returns all parameter names.
void _paramRequestReadFailure(int componentId, const QString ¶mName, int paramIndex)
void _paramRequestReadSuccess(int componentId, const QString ¶mName, int paramIndex)
static constexpr int kParamSetRetryCount
Number of retries for PARAM_SET.
void _paramSetSuccess(int componentId, const QString ¶mName)
void loadProgressChanged(float value)
void cacheCheckOnlyFailed()
void refreshParameter(int componentId, const QString ¶mName)
Request a refresh on the specific parameter.
void pendingWritesChanged(bool pendingWrites)
static MAV_PARAM_TYPE factTypeToMavType(FactMetaData::ValueType_t factType)
static constexpr int kParamRequestReadRetryCount
Number of retries for PARAM_REQUEST_READ.
void resetAllToVehicleConfiguration()
Q_INVOKABLE void refreshAllParameters()
static QString parameterCacheFile(int vehicleId, int componentId)
void writeParametersToStream(QTextStream &stream) const
void _paramSetFailure(int componentId, const QString ¶mName)
Final state for a QGCStateMachine with logging support.
static VehicleClass_t vehicleClass(MAV_TYPE mavType)
static const char * vehicleClassToCanonicalString(VehicleClass_t vehicleClass)
static FirmwareClass_t firmwareClass(MAV_AUTOPILOT autopilot)
static const char * firmwareClassToCanonicalString(FirmwareClass_t firmwareClass)
QGroundControl specific state machine with enhanced error handling.
QSignalTransition * addThisTransition(PointerToMemberFunction signal, QAbstractState *target)
Simpler version of QState::addTransition which assumes the sender is this.
Sends the specified MAVLink message to the vehicle.
WeakLinkInterfacePtr primaryLink() const
void sendMavCommand(int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
QString firmwareVersionTypeString() const
MAV_TYPE vehicleType() const
VehicleLinkManager * vehicleLinkManager()
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
ComponentInformationManager * compInfoManager()
int firmwareMinorVersion() const
MAV_AUTOPILOT firmwareType() const
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
int defaultComponentId() const
bool genericFirmware() const
AutoPilotPlugin * autopilotPlugin()
Provides access to AutoPilotPlugin for this vehicle.
void setOfflineEditingDefaultComponentId(int defaultComponentId)
Sets the default component id for an offline editing vehicle.
int firmwarePatchVersion() const
FTPManager * ftpManager()
int firmwareMajorVersion() const
Waits for either PARAM_VALUE (success) or PARAM_ERROR (rejection) from the vehicle.
Error
Error codes for decompression operations.
quint32 crc32(const quint8 *src, unsigned len, unsigned state)
bool fuzzyCompare(double value1, double value2)
Returns true if the two values are equal or close. Correctly handles 0 and NaN values.
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
static const int versionNotSetValue