Newer
Older
/****************************************************************************
*
* (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 "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "QGCApplication.h"
Nate Weibley
committed
#include <QEasingCurve>
#include <QFile>
#include <QDebug>
Nate Weibley
committed
#include <QVariantAnimation>
QGC_LOGGING_CATEGORY(ParameterManagerVerbose1Log, "ParameterManagerVerbose1Log")
QGC_LOGGING_CATEGORY(ParameterManagerVerbose2Log, "ParameterManagerVerbose2Log")
QGC_LOGGING_CATEGORY(ParameterManagerDebugCacheFailureLog, "ParameterManagerDebugCacheFailureLog") // Turn on to debug parameter cache crc misses
olliw42
committed
const QHash<int, QString> _mavlinkCompIdHash {
{ MAV_COMP_ID_CAMERA, "Camera1" },
{ MAV_COMP_ID_CAMERA2, "Camera2" },
{ MAV_COMP_ID_CAMERA3, "Camera3" },
{ MAV_COMP_ID_CAMERA4, "Camera4" },
{ MAV_COMP_ID_CAMERA5, "Camera5" },
{ MAV_COMP_ID_CAMERA6, "Camera6" },
{ MAV_COMP_ID_SERVO1, "Servo1" },
{ MAV_COMP_ID_SERVO2, "Servo2" },
{ MAV_COMP_ID_SERVO3, "Servo3" },
{ MAV_COMP_ID_SERVO4, "Servo4" },
{ MAV_COMP_ID_SERVO5, "Servo5" },
{ MAV_COMP_ID_SERVO6, "Servo6" },
{ MAV_COMP_ID_SERVO7, "Servo7" },
{ MAV_COMP_ID_SERVO8, "Servo8" },
{ MAV_COMP_ID_SERVO9, "Servo9" },
{ MAV_COMP_ID_SERVO10, "Servo10" },
{ MAV_COMP_ID_SERVO11, "Servo11" },
{ MAV_COMP_ID_SERVO12, "Servo12" },
{ MAV_COMP_ID_SERVO13, "Servo13" },
{ MAV_COMP_ID_SERVO14, "Servo14" },
{ MAV_COMP_ID_GIMBAL, "Gimbal1" },
{ MAV_COMP_ID_ADSB, "ADSB" },
{ MAV_COMP_ID_OSD, "OSD" },
{ MAV_COMP_ID_FLARM, "FLARM" },
{ MAV_COMP_ID_GIMBAL2, "Gimbal2" },
{ MAV_COMP_ID_GIMBAL3, "Gimbal3" },
{ MAV_COMP_ID_GIMBAL4, "Gimbal4" },
{ MAV_COMP_ID_GIMBAL5, "Gimbal5" },
{ MAV_COMP_ID_GIMBAL6, "Gimbal6" },
olliw42
committed
{ MAV_COMP_ID_IMU, "IMU1" },
{ MAV_COMP_ID_IMU_2, "IMU2" },
{ MAV_COMP_ID_IMU_3, "IMU3" },
{ MAV_COMP_ID_GPS, "GPS1" },
{ MAV_COMP_ID_GPS2, "GPS2" }
};
const char* ParameterManager::_cachedMetaDataFilePrefix = "ParameterFactMetaData";
const char* ParameterManager::_jsonParametersKey = "parameters";
const char* ParameterManager::_jsonCompIdKey = "compId";
const char* ParameterManager::_jsonParamNameKey = "name";
const char* ParameterManager::_jsonParamValueKey = "value";
ParameterManager::ParameterManager(Vehicle* vehicle)
: QObject (vehicle)
, _vehicle (vehicle)
, _loadProgress (0.0)
, _parametersReady (false)
, _missingParameters (false)
, _initialLoadComplete (false)
, _waitingForDefaultComponent (false)
, _saveRequired (false)
, _metaDataAddedToFacts (false)
, _logReplay (vehicle->priorityLink() && vehicle->priorityLink()->isLogReplay())
, _parameterSetMajorVersion (-1)
, _prevWaitingReadParamIndexCount (0)
, _prevWaitingReadParamNameCount (0)
, _prevWaitingWriteParamNameCount (0)
, _initialRequestRetryCount (0)
, _disableAllRetries (false)
, _indexBatchQueueActive (false)
, _totalParamCount (0)
_versionParam = vehicle->firmwarePlugin()->getVersionParam();
if (_vehicle->isOfflineEditingVehicle()) {
_loadOfflineEditingParams();
return;
}
_mavlink = qgcApp()->toolbox()->mavlinkProtocol();
_initialRequestTimeoutTimer.setSingleShot(true);
_initialRequestTimeoutTimer.setInterval(5000);
connect(&_initialRequestTimeoutTimer, &QTimer::timeout, this, &ParameterManager::_initialRequestTimeout);
_waitingParamTimeoutTimer.setSingleShot(true);
_waitingParamTimeoutTimer.setInterval(3000);
connect(&_waitingParamTimeoutTimer, &QTimer::timeout, this, &ParameterManager::_waitingParamTimeout);
connect(_vehicle->uas(), &UASInterface::parameterUpdate, this, &ParameterManager::_parameterUpdate);
// Ensure the cache directory exists
QFileInfo(QSettings().fileName()).dir().mkdir("ParamCache");
if (_vehicle->highLatencyLink()) {
// High latency links don't load parameters
_parametersReady = true;
_missingParameters = true;
_initialLoadComplete = true;
_waitingForDefaultComponent = false;
emit parametersReadyChanged(_parametersReady);
emit missingParametersChanged(_missingParameters);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
void ParameterManager::_updateProgressBar(void)
{
int waitingReadParamIndexCount = 0;
int waitingReadParamNameCount = 0;
int waitingWriteParamCount = 0;
for (int compId: _waitingReadParamIndexMap.keys()) {
waitingReadParamIndexCount += _waitingReadParamIndexMap[compId].count();
}
for(int compId: _waitingReadParamNameMap.keys()) {
waitingReadParamNameCount += _waitingReadParamNameMap[compId].count();
}
for(int compId: _waitingWriteParamNameMap.keys()) {
waitingWriteParamCount += _waitingWriteParamNameMap[compId].count();
}
if (waitingReadParamIndexCount == 0) {
if (_readParamIndexProgressActive) {
_readParamIndexProgressActive = false;
_setLoadProgress(0.0);
return;
}
} else {
_readParamIndexProgressActive = true;
_setLoadProgress((double)(_totalParamCount - waitingReadParamIndexCount) / (double)_totalParamCount);
return;
}
if (waitingWriteParamCount == 0) {
if (_writeParamProgressActive) {
_writeParamProgressActive = false;
_waitingWriteParamBatchCount = 0;
_setLoadProgress(0.0);
emit pendingWritesChanged(false);
return;
}
} else {
_writeParamProgressActive = true;
_setLoadProgress((double)(qMax(_waitingWriteParamBatchCount - waitingWriteParamCount, 1)) / (double)(_waitingWriteParamBatchCount + 1));
emit pendingWritesChanged(true);
return;
}
if (waitingReadParamNameCount == 0) {
if (_readParamNameProgressActive) {
_readParamNameProgressActive = false;
_waitingReadParamNameBatchCount = 0;
_setLoadProgress(0.0);
return;
}
} else {
_readParamNameProgressActive = true;
_setLoadProgress((double)(qMax(_waitingReadParamNameBatchCount - waitingReadParamNameCount, 1)) / (double)(_waitingReadParamNameBatchCount + 1));
return;
}
}
/// Called whenever a parameter is updated or first seen.
void ParameterManager::_parameterUpdate(int vehicleId, int componentId, QString parameterName, int parameterCount, int parameterId, int mavType, QVariant value)
{
// Is this for our uas?
if (vehicleId != _vehicle->id()) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) <<
"_parameterUpdate" <<
"name:" << parameterName <<
"count:" << parameterCount <<
"index:" << parameterId <<
"mavType:" << mavType <<
"value:" << value <<
")";
// ArduPilot has this strange behavior of streaming parameters that we didn't ask for. This even happens before it responds to the
// PARAM_REQUEST_LIST. We disregard any of this until the initial request is responded to.
if (parameterId == 65535 && parameterName != "_HASH_CHECK" && _initialRequestTimeoutTimer.isActive()) {
qCDebug(ParameterManagerVerbose1Log) << "Disregarding unrequested param prior to initial list response" << parameterName;
if (!_initialLoadComplete && !_indexBatchQueueActive) {
// Handy for testing retry logic
static int counter = 0;
if (counter++ & 0x8) {
qCDebug(ParameterManagerLog) << "Artificial discard" << counter;
return;
}
#if 0
// Use this to test missing default component id
if (componentId == 50) {
return;
}
#endif
if (_vehicle->px4Firmware() && parameterName == "_HASH_CHECK") {
if (!_initialLoadComplete && !_logReplay) {
/* we received a cache hash, potentially load from cache */
_tryCacheHashLoad(vehicleId, componentId, value);
}
return;
// Used to debug cache crc misses (turn on ParameterManagerDebugCacheFailureLog)
if (!_initialLoadComplete && !_logReplay && _debugCacheCRC.contains(componentId) && _debugCacheCRC[componentId]) {
if (_debugCacheMap[componentId].contains(parameterName)) {
const ParamTypeVal& cacheParamTypeVal = _debugCacheMap[componentId][parameterName];
size_t dataSize = FactMetaData::typeToSize(static_cast<FactMetaData::ValueType_t>(cacheParamTypeVal.first));
const void *cacheData = cacheParamTypeVal.second.constData();
const void *vehicleData = value.constData();
if (memcmp(cacheData, vehicleData, dataSize)) {
qDebug() << "Cache/Vehicle values differ for name:cache:actual" << parameterName << value << cacheParamTypeVal.second;
}
_debugCacheParamSeen[componentId][parameterName] = true;
} else {
qDebug() << "Parameter missing from cache" << parameterName;
}
}
_waitingParamTimeoutTimer.stop();
// Update our total parameter counts
if (!_paramCountMap.contains(componentId)) {
_paramCountMap[componentId] = parameterCount;
_totalParamCount += parameterCount;
}
// If we've never seen this component id before, setup the wait lists.
if (!_waitingReadParamIndexMap.contains(componentId)) {
// Add all indices to the wait list, parameter index is 0-based
for (int waitingIndex=0; waitingIndex<parameterCount; waitingIndex++) {
// This will add the new component id, as well as the the new waiting index and set the retry count for that index to 0
_waitingReadParamIndexMap[componentId][waitingIndex] = 0;
// The read and write waiting lists for this component are initialized the empty
_waitingReadParamNameMap[componentId] = QMap<QString, int>();
_waitingWriteParamNameMap[componentId] = QMap<QString, int>();
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Seeing component for first time - paramcount:" << parameterCount;
bool componentParamsComplete = false;
if (_waitingReadParamIndexMap[componentId].count() == 1) {
// We need to know when we get the last param from a component in order to complete setup
componentParamsComplete = true;
}
if (!_waitingReadParamIndexMap[componentId].contains(parameterId) &&
!_waitingReadParamNameMap[componentId].contains(parameterName) &&
!_waitingWriteParamNameMap[componentId].contains(parameterName)) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "Unrequested param update" << parameterName;
// Remove this parameter from the waiting lists
if (_waitingReadParamIndexMap[componentId].contains(parameterId)) {
_waitingReadParamIndexMap[componentId].remove(parameterId);
_indexBatchQueue.removeOne(parameterId);
_fillIndexBatchQueue(false /* waitingParamTimeout */);
}
_waitingReadParamNameMap[componentId].remove(parameterName);
_waitingWriteParamNameMap[componentId].remove(parameterName);
if (_waitingReadParamIndexMap[componentId].count()) {
qCDebug(ParameterManagerVerbose2Log) << _logVehiclePrefix(componentId) << "_waitingReadParamIndexMap:" << _waitingReadParamIndexMap[componentId];
}
if (_waitingReadParamNameMap[componentId].count()) {
qCDebug(ParameterManagerVerbose2Log) << _logVehiclePrefix(componentId) << "_waitingReadParamNameMap" << _waitingReadParamNameMap[componentId];
}
if (_waitingWriteParamNameMap[componentId].count()) {
qCDebug(ParameterManagerVerbose2Log) << _logVehiclePrefix(componentId) << "_waitingWriteParamNameMap" << _waitingWriteParamNameMap[componentId];
}
// Track how many parameters we are still waiting for
int waitingReadParamIndexCount = 0;
int waitingReadParamNameCount = 0;
int waitingWriteParamNameCount = 0;
for(int waitingComponentId: _waitingReadParamIndexMap.keys()) {
waitingReadParamIndexCount += _waitingReadParamIndexMap[waitingComponentId].count();
}
if (waitingReadParamIndexCount) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "waitingReadParamIndexCount:" << waitingReadParamIndexCount;
for(int waitingComponentId: _waitingReadParamNameMap.keys()) {
waitingReadParamNameCount += _waitingReadParamNameMap[waitingComponentId].count();
}
if (waitingReadParamNameCount) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "waitingReadParamNameCount:" << waitingReadParamNameCount;
for(int waitingComponentId: _waitingWriteParamNameMap.keys()) {
waitingWriteParamNameCount += _waitingWriteParamNameMap[waitingComponentId].count();
}
if (waitingWriteParamNameCount) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "waitingWriteParamNameCount:" << waitingWriteParamNameCount;
int readWaitingParamCount = waitingReadParamIndexCount + waitingReadParamNameCount;
int totalWaitingParamCount = readWaitingParamCount + waitingWriteParamNameCount;
if (totalWaitingParamCount) {
// More params to wait for, restart timer
_waitingParamTimeoutTimer.start();
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(-1) << "Restarting _waitingParamTimeoutTimer: totalWaitingParamCount:" << totalWaitingParamCount;
if (!_mapParameterName2Variant.contains(_vehicle->defaultComponentId())) {
// Still waiting for parameters from default component
qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) << "Restarting _waitingParamTimeoutTimer (still waiting for default component params)";
_waitingParamTimeoutTimer.start();
} else {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(-1) << "Not restarting _waitingParamTimeoutTimer (all requests satisfied)";
// Get parameter set version
if (!_versionParam.isEmpty() && _versionParam == parameterName) {
_parameterSetMajorVersion = value.toInt();
}
if (!_mapParameterName2Variant.contains(componentId) || !_mapParameterName2Variant[componentId].contains(parameterName)) {
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "Adding new fact" << parameterName;
FactMetaData::ValueType_t factType;
switch (mavType) {
case MAV_PARAM_TYPE_UINT8:
factType = FactMetaData::valueTypeUint8;
break;
case MAV_PARAM_TYPE_INT8:
factType = FactMetaData::valueTypeInt8;
break;
case MAV_PARAM_TYPE_UINT16:
factType = FactMetaData::valueTypeUint16;
break;
case MAV_PARAM_TYPE_INT16:
factType = FactMetaData::valueTypeInt16;
break;
case MAV_PARAM_TYPE_UINT32:
factType = FactMetaData::valueTypeUint32;
break;
case MAV_PARAM_TYPE_INT32:
factType = FactMetaData::valueTypeInt32;
break;
case MAV_PARAM_TYPE_UINT64:
factType = FactMetaData::valueTypeUint64;
break;
case MAV_PARAM_TYPE_INT64:
factType = FactMetaData::valueTypeInt64;
break;
case MAV_PARAM_TYPE_REAL32:
factType = FactMetaData::valueTypeFloat;
break;
case MAV_PARAM_TYPE_REAL64:
factType = FactMetaData::valueTypeDouble;
break;
default:
factType = FactMetaData::valueTypeInt32;
qCritical() << "Unsupported fact type" << mavType;
break;
Fact* fact = new Fact(componentId, parameterName, factType, this);
_mapParameterName2Variant[componentId][parameterName] = QVariant::fromValue(fact);
// We need to know when the fact changes from QML so that we can send the new value to the parameter manager
connect(fact, &Fact::_containerRawValueChanged, this, &ParameterManager::_valueUpdated);
if (_mapParameterName2Variant[componentId].contains(parameterName)) {
fact = _mapParameterName2Variant[componentId][parameterName].value<Fact*>();
}
if (fact) {
fact->_containerSetRawValue(value);
} else {
qWarning() << "Internal error";
}
if (componentParamsComplete) {
if (componentId == _vehicle->defaultComponentId()) {
// Add meta data to default component. We need to do this before we setup the group map since group
// map requires meta data.
_addMetaDataToDefaultComponent();
olliw42
committed
// When we are getting the very last component param index, reset the group maps to update for the
// new params. By handling this here, we can pick up components which finish up later than the default
// component param set.
_setupComponentCategoryMap(componentId);
// Update param cache. The param cache is only used on PX4 Firmware since ArduPilot and Solo have volatile params
// which invalidate the cache. The Solo also streams param updates in flight for things like gimbal values
// which in turn causes a perf problem with all the param cache updates.
if (_prevWaitingReadParamIndexCount + _prevWaitingReadParamNameCount != 0 && readWaitingParamCount == 0) {
// All reads just finished, update the cache
_writeLocalParamCache(vehicleId, componentId);
}
}
_prevWaitingReadParamIndexCount = waitingReadParamIndexCount;
_prevWaitingReadParamNameCount = waitingReadParamNameCount;
_prevWaitingWriteParamNameCount = waitingWriteParamNameCount;
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "_parameterUpdate complete";
}
/// Connected to Fact::valueUpdated
///
/// Writes the parameter to mavlink, sets up for write wait
void ParameterManager::_valueUpdated(const QVariant& value)
{
Fact* fact = qobject_cast<Fact*>(sender());
if (!fact) {
qWarning() << "Internal error";
return;
}
int componentId = fact->componentId();
if (_waitingWriteParamNameMap[componentId].contains(name)) {
_waitingWriteParamNameMap[componentId].remove(name);
} else {
_waitingWriteParamBatchCount++;
}
_waitingWriteParamNameMap[componentId][name] = 0; // Add new entry and set retry count
_updateProgressBar();
_waitingParamTimeoutTimer.start();
_saveRequired = true;
} else {
qWarning() << "Internal error";
}
_writeParameterRaw(componentId, fact->name(), value);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Set parameter - name:" << name << value << "(_waitingParamTimeoutTimer started)";
void ParameterManager::refreshAllParameters(uint8_t componentId)
if (!_initialLoadComplete) {
_initialRequestTimeoutTimer.start();
}
for (int cid: _paramCountMap.keys()) {
// Add/Update all indices to the wait list, parameter index is 0-based
if(componentId != MAV_COMP_ID_ALL && componentId != cid)
continue;
for (int waitingIndex = 0; waitingIndex < _paramCountMap[cid]; waitingIndex++) {
// This will add a new waiting index if needed and set the retry count for that index to 0
MAVLinkProtocol* mavlink = qgcApp()->toolbox()->mavlinkProtocol();
mavlink_msg_param_request_list_pack_chan(mavlink->getSystemId(),
mavlink->getComponentId(),
_vehicle->priorityLink()->mavlinkChannel(),
&msg,
_vehicle->id(),
_vehicle->sendMessageOnLink(_vehicle->priorityLink(), msg);
QString what = (componentId == MAV_COMP_ID_ALL) ? "MAV_COMP_ID_ALL" : QString::number(componentId);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) << "Request to refresh all parameters for component ID:" << what;
}
/// Translates FactSystem::defaultComponentId to real component id if needed
int ParameterManager::_actualComponentId(int componentId)
{
if (componentId == FactSystem::defaultComponentId) {
componentId = _vehicle->defaultComponentId();
return componentId;
}
olliw42
committed
void ParameterManager::refreshParameter(int componentId, const QString& paramName)
componentId = _actualComponentId(componentId);
olliw42
committed
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "refreshParameter - name:" << paramName << ")";
_dataMutex.lock();
if (_waitingReadParamNameMap.contains(componentId)) {
olliw42
committed
QString mappedParamName = _remapParamNameToVersion(paramName);
if (_waitingReadParamNameMap[componentId].contains(mappedParamName)) {
_waitingReadParamNameMap[componentId].remove(mappedParamName);
} else {
_waitingReadParamNameBatchCount++;
}
_waitingReadParamNameMap[componentId][mappedParamName] = 0; // Add new wait entry and update retry count
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "restarting _waitingParamTimeout";
_waitingParamTimeoutTimer.start();
olliw42
committed
_readParameterRaw(componentId, paramName, -1);
void ParameterManager::refreshParametersPrefix(int componentId, const QString& namePrefix)
{
componentId = _actualComponentId(componentId);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "refreshParametersPrefix - name:" << namePrefix << ")";
olliw42
committed
for(const QString ¶mName: _mapParameterName2Variant[componentId].keys()) {
if (paramName.startsWith(namePrefix)) {
refreshParameter(componentId, paramName);
olliw42
committed
bool ParameterManager::parameterExists(int componentId, const QString& paramName)
componentId = _actualComponentId(componentId);
if (_mapParameterName2Variant.contains(componentId)) {
olliw42
committed
ret = _mapParameterName2Variant[componentId].contains(_remapParamNameToVersion(paramName));
olliw42
committed
Fact* ParameterManager::getParameter(int componentId, const QString& paramName)
{
componentId = _actualComponentId(componentId);
olliw42
committed
QString mappedParamName = _remapParamNameToVersion(paramName);
if (!_mapParameterName2Variant.contains(componentId) || !_mapParameterName2Variant[componentId].contains(mappedParamName)) {
qgcApp()->reportMissingParameter(componentId, mappedParamName);
return _mapParameterName2Variant[componentId][mappedParamName].value<Fact*>();
QStringList ParameterManager::parameterNames(int componentId)
for(const QString ¶mName: _mapParameterName2Variant[_actualComponentId(componentId)].keys()) {
olliw42
committed
void ParameterManager::_setupComponentCategoryMap(int componentId)
{
if (componentId == _vehicle->defaultComponentId()) {
_setupDefaultComponentCategoryMap();
return;
}
ComponentCategoryMapType& componentCategoryMap = _componentCategoryMaps[componentId];
QString category = getComponentCategory(componentId);
// Must be able to handle being called multiple times
componentCategoryMap.clear();
// Fill parameters into the group determined by param name
for (const QString ¶mName: _mapParameterName2Variant[componentId].keys()) {
int i = paramName.indexOf("_");
if (i > 0) {
componentCategoryMap[category][paramName.left(i)] += paramName;
} else {
componentCategoryMap[category][tr("Misc")] += paramName;
olliw42
committed
}
}
// Memorize category for component ID
if (!_componentCategoryHash.contains(category)) {
_componentCategoryHash.insert(category, componentId);
}
}
olliw42
committed
ComponentCategoryMapType& defaultComponentCategoryMap = _componentCategoryMaps[_vehicle->defaultComponentId()];
// Must be able to handle being called multiple times
olliw42
committed
defaultComponentCategoryMap.clear();
for (const QString ¶mName: _mapParameterName2Variant[_vehicle->defaultComponentId()].keys()) {
Fact* fact = _mapParameterName2Variant[_vehicle->defaultComponentId()][paramName].value<Fact*>();
defaultComponentCategoryMap[fact->category()][fact->group()] += paramName;
}
}
olliw42
committed
QString ParameterManager::getComponentCategory(int componentId)
{
if (_mavlinkCompIdHash.contains(componentId)) {
return tr("Component %1 (%2)").arg(_mavlinkCompIdHash.value(componentId)).arg(componentId);
olliw42
committed
QString componentCategoryPrefix = tr("Component ");
return QString("%1%2").arg(componentCategoryPrefix).arg(componentId);
}
const QMap<QString, QMap<QString, QStringList> >& ParameterManager::getComponentCategoryMap(int componentId)
{
return _componentCategoryMaps[componentId];
olliw42
committed
int ParameterManager::getComponentId(const QString& category)
olliw42
committed
return (_componentCategoryHash.contains(category)) ? _componentCategoryHash.value(category) : _vehicle->defaultComponentId();
/// Requests missing index based parameters from the vehicle.
/// @param waitingParamTimeout: true: being called due to timeout, false: being called to re-fill the batch queue
/// return true: Parameters were requested, false: No more requests needed
bool ParameterManager::_fillIndexBatchQueue(bool waitingParamTimeout)
if (!_indexBatchQueueActive) {
return false;
}
if (waitingParamTimeout) {
// We timed out, clear the queue and try again
qCDebug(ParameterManagerLog) << "Refilling index based batch queue due to timeout";
_indexBatchQueue.clear();
} else {
qCDebug(ParameterManagerLog) << "Refilling index based batch queue due to received parameter";
}
for(int componentId: _waitingReadParamIndexMap.keys()) {
if (_waitingReadParamIndexMap[componentId].count()) {
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "_waitingReadParamIndexMap count" << _waitingReadParamIndexMap[componentId].count();
qCDebug(ParameterManagerVerbose1Log) << _logVehiclePrefix(componentId) << "_waitingReadParamIndexMap" << _waitingReadParamIndexMap[componentId];
for(int paramIndex: _waitingReadParamIndexMap[componentId].keys()) {
if (_indexBatchQueue.contains(paramIndex)) {
// Don't add more than once
continue;
}
if (_indexBatchQueue.count() > maxBatchSize) {
break;
_waitingReadParamIndexMap[componentId][paramIndex]++; // Bump retry count
if (_disableAllRetries || _waitingReadParamIndexMap[componentId][paramIndex] > _maxInitialLoadRetrySingleParam) {
// Give up on this index
_failedReadParamIndexMap[componentId] << paramIndex;
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Giving up on (paramIndex:" << paramIndex << "retryCount:" << _waitingReadParamIndexMap[componentId][paramIndex] << ")";
_waitingReadParamIndexMap[componentId].remove(paramIndex);
} else {
// Retry again
_indexBatchQueue.append(paramIndex);
_readParameterRaw(componentId, "", paramIndex);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Read re-request for (paramIndex:" << paramIndex << "retryCount:" << _waitingReadParamIndexMap[componentId][paramIndex] << ")";
return _indexBatchQueue.count() != 0;
}
void ParameterManager::_waitingParamTimeout(void)
{
bool paramsRequested = false;
const int maxBatchSize = 10;
int batchCount = 0;
qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) << "_waitingParamTimeout";
// Now that we have timed out for possibly the first time we can activate the index batch queue
_indexBatchQueueActive = true;
// First check for any missing parameters from the initial index based load
paramsRequested = _fillIndexBatchQueue(true /* waitingParamTimeout */);
if (!paramsRequested && !_waitingForDefaultComponent && !_mapParameterName2Variant.contains(_vehicle->defaultComponentId())) {
// Initial load is complete but we still don't have any default component params. Wait one more cycle to see if the
// any show up.
qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) << "Restarting _waitingParamTimeoutTimer - still don't have default component params" << _vehicle->defaultComponentId() << _mapParameterName2Variant.keys();
_waitingParamTimeoutTimer.start();
_waitingForDefaultComponent = true;
return;
}
_waitingForDefaultComponent = false;
for(int componentId: _waitingWriteParamNameMap.keys()) {
for(const QString ¶mName: _waitingWriteParamNameMap[componentId].keys()) {
_waitingWriteParamNameMap[componentId][paramName]++; // Bump retry count
if (_waitingWriteParamNameMap[componentId][paramName] <= _maxReadWriteRetry) {
_writeParameterRaw(componentId, paramName, getParameter(componentId, paramName)->rawValue());
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Write resend for (paramName:" << paramName << "retryCount:" << _waitingWriteParamNameMap[componentId][paramName] << ")";
goto Out;
}
} else {
// Exceeded max retry count, notify user
_waitingWriteParamNameMap[componentId].remove(paramName);
QString errorMsg = tr("Parameter write failed: veh:%1 comp:%2 param:%3").arg(_vehicle->id()).arg(componentId).arg(paramName);
qCDebug(ParameterManagerLog) << errorMsg;
qgcApp()->showMessage(errorMsg);
for(int componentId: _waitingReadParamNameMap.keys()) {
for(const QString ¶mName: _waitingReadParamNameMap[componentId].keys()) {
_waitingReadParamNameMap[componentId][paramName]++; // Bump retry count
if (_waitingReadParamNameMap[componentId][paramName] <= _maxReadWriteRetry) {
_readParameterRaw(componentId, paramName, -1);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(componentId) << "Read re-request for (paramName:" << paramName << "retryCount:" << _waitingReadParamNameMap[componentId][paramName] << ")";
goto Out;
}
} else {
// Exceeded max retry count, notify user
_waitingReadParamNameMap[componentId].remove(paramName);
QString errorMsg = tr("Parameter read failed: veh:%1 comp:%2 param:%3").arg(_vehicle->id()).arg(componentId).arg(paramName);
qCDebug(ParameterManagerLog) << errorMsg;
qgcApp()->showMessage(errorMsg);
qCDebug(ParameterManagerLog) << _logVehiclePrefix(-1) << "Restarting _waitingParamTimeoutTimer - re-request";
_waitingParamTimeoutTimer.start();
}
}
void ParameterManager::_readParameterRaw(int componentId, const QString& paramName, int paramIndex)
{
mavlink_message_t msg;
char fixedParamName[MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN];
strncpy(fixedParamName, paramName.toStdString().c_str(), sizeof(fixedParamName));
mavlink_msg_param_request_read_pack_chan(_mavlink->getSystemId(), // QGC system id
_mavlink->getComponentId(), // QGC component id
_vehicle->priorityLink()->mavlinkChannel(),
&msg, // Pack into this mavlink_message_t
_vehicle->id(), // Target system id
componentId, // Target component id
fixedParamName, // Named parameter being requested
paramIndex); // Parameter index being requested, -1 for named
_vehicle->sendMessageOnLink(_vehicle->priorityLink(), msg);
void ParameterManager::_writeParameterRaw(int componentId, const QString& paramName, const QVariant& value)
{
mavlink_param_set_t p;
mavlink_param_union_t union_value;
FactMetaData::ValueType_t factType = getParameter(componentId, paramName)->type();
p.param_type = _factTypeToMavType(factType);
case FactMetaData::valueTypeUint8:
union_value.param_uint8 = (uint8_t)value.toUInt();
break;
case FactMetaData::valueTypeInt8:
union_value.param_int8 = (int8_t)value.toInt();
break;
case FactMetaData::valueTypeUint16:
union_value.param_uint16 = (uint16_t)value.toUInt();
break;
case FactMetaData::valueTypeInt16:
union_value.param_int16 = (int16_t)value.toInt();
break;
case FactMetaData::valueTypeUint32:
union_value.param_uint32 = (uint32_t)value.toUInt();
break;
case FactMetaData::valueTypeFloat:
union_value.param_float = value.toFloat();
break;
default:
qCritical() << "Unsupported fact type" << factType;
// fall through
case FactMetaData::valueTypeInt32:
union_value.param_int32 = (int32_t)value.toInt();
break;
p.param_value = union_value.param_float;
p.target_system = (uint8_t)_vehicle->id();
p.target_component = (uint8_t)componentId;
strncpy(p.param_id, paramName.toStdString().c_str(), sizeof(p.param_id));
mavlink_msg_param_set_encode_chan(_mavlink->getSystemId(),
_mavlink->getComponentId(),
_vehicle->priorityLink()->mavlinkChannel(),
&msg,
&p);
_vehicle->sendMessageOnLink(_vehicle->priorityLink(), msg);
void ParameterManager::_writeLocalParamCache(int vehicleId, int componentId)
CacheMapName2ParamTypeVal cacheMap;
olliw42
committed
for(const QString& paramName: _mapParameterName2Variant[componentId].keys()) {
const Fact *fact = _mapParameterName2Variant[componentId][paramName].value<Fact*>();
cacheMap[paramName] = ParamTypeVal(fact->type(), fact->rawValue());
}
QFile cacheFile(parameterCacheFile(vehicleId, componentId));
cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
QDataStream ds(&cacheFile);
ds << cacheMap;
}
QDir ParameterManager::parameterCacheDir()
{
const QString spath(QFileInfo(QSettings().fileName()).dir().absolutePath());
return spath + QDir::separator() + "ParamCache";
}
QString ParameterManager::parameterCacheFile(int vehicleId, int componentId)
return parameterCacheDir().filePath(QString("%1_%2.v2").arg(vehicleId).arg(componentId));
void ParameterManager::_tryCacheHashLoad(int vehicleId, int componentId, QVariant hash_value)
qCInfo(ParameterManagerLog) << "Attemping load from cache";
uint32_t crc32_value = 0;
/* The datastructure of the cache table */
CacheMapName2ParamTypeVal cacheMap;
QFile cacheFile(parameterCacheFile(vehicleId, componentId));
if (!cacheFile.exists()) {
/* no local cache, just wait for them to come in*/
return;
}
cacheFile.open(QIODevice::ReadOnly);
/* Deserialize the parameter cache table */
QDataStream ds(&cacheFile);
ds >> cacheMap;
// Load parameter meta data for the version number stored in cache.
// We need meta data so we have access to the volatile bit
if (cacheMap.contains(_versionParam)) {
_parameterSetMajorVersion = cacheMap[_versionParam].second.toInt();
}
_loadMetaData();
/* compute the crc of the local cache to check against the remote */
FirmwarePlugin* firmwarePlugin = _vehicle->firmwarePlugin();
for (const QString& name: cacheMap.keys()) {
bool volatileValue = false;
FactMetaData* metaData = firmwarePlugin->getMetaDataForFact(_parameterMetaData, name, _vehicle->vehicleType());
if (metaData) {
volatileValue = metaData->volatileValue();
}
if (volatileValue) {
// Does not take part in CRC
qCDebug(ParameterManagerLog) << "Volatile parameter" << name;
} else {
const ParamTypeVal& paramTypeVal = cacheMap[name];
const void *vdat = paramTypeVal.second.constData();
const FactMetaData::ValueType_t fact_type = static_cast<FactMetaData::ValueType_t>(paramTypeVal.first);
crc32_value = QGC::crc32((const uint8_t *)qPrintable(name), name.length(), crc32_value);
crc32_value = QGC::crc32((const uint8_t *)vdat, FactMetaData::typeToSize(fact_type), crc32_value);
}
}
/* if the two param set hashes match, just load from the disk */
if (crc32_value == hash_value.toUInt()) {
qCInfo(ParameterManagerLog) << "Parameters loaded from cache" << qPrintable(QFileInfo(cacheFile).absoluteFilePath());
int count = cacheMap.count();
int index = 0;
for (const QString& name: cacheMap.keys()) {
const ParamTypeVal& paramTypeVal = cacheMap[name];
const FactMetaData::ValueType_t fact_type = static_cast<FactMetaData::ValueType_t>(paramTypeVal.first);
const int mavType = _factTypeToMavType(fact_type);
_parameterUpdate(vehicleId, componentId, name, count, index++, mavType, paramTypeVal.second);
// Return the hash value to notify we don't want any more updates
mavlink_param_set_t p;
mavlink_param_union_t union_value;
p.param_type = MAV_PARAM_TYPE_UINT32;
strncpy(p.param_id, "_HASH_CHECK", sizeof(p.param_id));
union_value.param_uint32 = crc32_value;
p.param_value = union_value.param_float;
p.target_system = (uint8_t)_vehicle->id();
p.target_component = (uint8_t)componentId;
mavlink_message_t msg;
mavlink_msg_param_set_encode_chan(_mavlink->getSystemId(),
_mavlink->getComponentId(),
_vehicle->priorityLink()->mavlinkChannel(),
&msg,
&p);
_vehicle->sendMessageOnLink(_vehicle->priorityLink(), msg);