diff --git a/src/Vehicle/Actuators/Actuators.cc b/src/Vehicle/Actuators/Actuators.cc index 292781f..b477e56 100644 --- a/src/Vehicle/Actuators/Actuators.cc +++ b/src/Vehicle/Actuators/Actuators.cc @@ -239,7 +239,7 @@ void Actuators::parametersChanged() _actuatorTest.updateFunctions(actuators); // check if there are required functions, but not set on any output - QSet requiredFunctions = _mixer.requiredFunctions(); + QSet requiredFunctions = _mixer.getFunctions(true); _hasUnsetRequiredFunctions = false; for (int requiredFunction : requiredFunctions) { if (uniqueConfiguredFunctions.find(requiredFunction) == uniqueConfiguredFunctions.end()) { @@ -248,11 +248,92 @@ void Actuators::parametersChanged() } emit hasUnsetRequiredFunctionsChanged(); + updateFunctionMetadata(); + updateActuatorActions(); updateGeometryImage(); } +void Actuators::updateFunctionMetadata() +{ + // Update the function parameter metadata: + // - remove the mixer functions that are unused with the current configration (e.g. if 4 motors -> remove motors 5-N) + // - use the specific labels + QSet usedMixerFunctions = _mixer.getFunctions(false); + + QMap usedMixerLabels; + for (int usedMixerFunction : usedMixerFunctions) { + usedMixerLabels[usedMixerFunction] = _mixer.getSpecificLabelForFunction(usedMixerFunction); + } + + if (_usedMixerLabels == usedMixerLabels) { + // no update required + return; + } + _usedMixerLabels = usedMixerLabels; + + // Get the unused mixer functions + QSet removedMixerFunctions; + for(Mixer::ActuatorTypes::const_iterator iter = _mixer.actuatorTypes().constBegin(); + iter != _mixer.actuatorTypes().constEnd(); ++iter) { + if (iter.key() == "DEFAULT") + continue; + + for (int i = iter.value().functionMin; i <= iter.value().functionMax; ++i) { + if (!usedMixerFunctions.contains(i)) { + removedMixerFunctions.insert(i); + } + } + } + + // Now update all function facts (we need to treat them individually, as some might have extra functions) + for (int groupIdx = 0; groupIdx < _actuatorOutputs->count(); groupIdx++) { + ActuatorOutput* group = qobject_cast(_actuatorOutputs->get(groupIdx)); + + group->forEachOutputFunction([&](ActuatorOutputSubgroup* subgroup, ChannelConfigInstance*, Fact* fact) { + QStringList enumStrings = fact->enumStrings(); + if (!enumStrings.empty()) { + QVariantList enumValues = fact->enumValues(); + + // Replace or add + for (int usedMixerFunction : usedMixerFunctions) { + QString label = usedMixerLabels[usedMixerFunction]; + int index = enumValues.indexOf(usedMixerFunction); + if (index == -1) { + // Insert at the right place + bool inserted = false; + for (index = 0; index < enumValues.count() && !inserted; ++index) { + if (enumValues[index].toInt() > usedMixerFunction) { + enumValues.insert(index, usedMixerFunction); + enumStrings.insert(index, label); + inserted = true; + } + } + if (!inserted) { + enumValues.append(usedMixerFunction); + enumStrings.append(label); + } + } else { + enumStrings[index] = label; + } + } + + // Remove + for (int removedMixerFunction : removedMixerFunctions) { + int index = enumValues.indexOf(removedMixerFunction); + if (index != -1) { + enumValues.removeAt(index); + enumStrings.removeAt(index); + } + } + + fact->setEnumInfo(enumStrings, enumValues); + } + }); + } +} + void Actuators::updateActuatorActions() { _actuatorActions->clearAndDeleteContents(); diff --git a/src/Vehicle/Actuators/Actuators.h b/src/Vehicle/Actuators/Actuators.h index 350e50f..4e1e54b 100644 --- a/src/Vehicle/Actuators/Actuators.h +++ b/src/Vehicle/Actuators/Actuators.h @@ -106,6 +106,8 @@ private: void highlightActuators(bool highlight); + void updateFunctionMetadata(); + QSet _subscribedFacts{}; QJsonDocument _jsonMetadata; bool _init{false}; @@ -120,5 +122,6 @@ private: bool _imageRefreshFlag{false}; ///< indicator to QML to reload the image int _selectedActuatorOutput{0}; Vehicle* _vehicle{nullptr}; + QMap _usedMixerLabels; }; diff --git a/src/Vehicle/Actuators/Mixer.cc b/src/Vehicle/Actuators/Mixer.cc index 952fcc9..5092626 100644 --- a/src/Vehicle/Actuators/Mixer.cc +++ b/src/Vehicle/Actuators/Mixer.cc @@ -317,7 +317,7 @@ void Mixers::update() } if (itemLabelPrefix != "") { label = itemLabelPrefix + " (" + label + ")"; - _functionsSpecificLabel[actuatorFunction] = label; + _functionsSpecificLabel[actuatorFunction] = itemLabelPrefix; } } auto factAdded = [this](Function function, Fact* fact) { @@ -348,20 +348,37 @@ void Mixers::update() QString Mixers::getSpecificLabelForFunction(int function) const { // Try to get it from the actuator type param - for (int mixerGroupIdx = 0; mixerGroupIdx < _groups->count(); ++mixerGroupIdx) { + Fact* typeFact = nullptr; + for (int mixerGroupIdx = 0; !typeFact && mixerGroupIdx < _groups->count(); ++mixerGroupIdx) { Mixer::MixerConfigGroup* mixerGroup = _groups->value(mixerGroupIdx); - for (int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) { + for (int mixerChannelIdx = 0; !typeFact && mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) { Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value(mixerChannelIdx); if (mixerChannel->actuatorFunction() != function) { continue; } - Fact* typeFact = mixerChannel->getFact(Function::Type); - if (typeFact) { - return typeFact->enumOrValueString() + " (" + _functions.value(function).label +")"; + typeFact = mixerChannel->getFact(Function::Type); + } + } + if (typeFact) { + // Now check if we have multiple functions configured with the same type. + // If so, add the function label to disambiguate + for (int mixerGroupIdx = 0; mixerGroupIdx < _groups->count(); ++mixerGroupIdx) { + Mixer::MixerConfigGroup* mixerGroup = _groups->value(mixerGroupIdx); + for (int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) { + Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value(mixerChannelIdx); + + if (mixerChannel->actuatorFunction() == function) { + continue; + } + Fact* typeFactOther = mixerChannel->getFact(Function::Type); + if (typeFactOther && typeFactOther->rawValue() == typeFact->rawValue()) { + return typeFact->enumOrValueString() + " (" + _functions.value(function).label +")"; + } } } + return typeFact->enumOrValueString(); } const auto iter = _functionsSpecificLabel.find(function); @@ -371,12 +388,12 @@ QString Mixers::getSpecificLabelForFunction(int function) const return *iter; } -QSet Mixers::requiredFunctions() const +QSet Mixers::getFunctions(bool requiredOnly) const { QSet ret; for (int mixerGroupIdx = 0; mixerGroupIdx < _groups->count(); ++mixerGroupIdx) { Mixer::MixerConfigGroup* mixerGroup = _groups->value(mixerGroupIdx); - if (mixerGroup->group().required) { + if (!requiredOnly || mixerGroup->group().required) { for (int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) { const Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value(mixerChannelIdx); if (mixerChannel->actuatorFunction() != 0) { diff --git a/src/Vehicle/Actuators/Mixer.h b/src/Vehicle/Actuators/Mixer.h index 08bb6e6..210826f 100644 --- a/src/Vehicle/Actuators/Mixer.h +++ b/src/Vehicle/Actuators/Mixer.h @@ -321,9 +321,9 @@ public: QString getSpecificLabelForFunction(int function) const; /** - * Get the set of all required actuator functions + * Get the set of all (required) actuator functions */ - QSet requiredFunctions() const; + QSet getFunctions(bool requiredOnly) const; QString configuredType() const;