| /* | |
| * Copyright (c) 2011-2015, Intel Corporation | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation and/or | |
| * other materials provided with the distribution. | |
| * | |
| * 3. Neither the name of the copyright holder nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software without | |
| * specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "ConfigurableElement.h" | |
| #include "MappingData.h" | |
| #include "SyncerSet.h" | |
| #include "ConfigurableDomain.h" | |
| #include "ConfigurationAccessContext.h" | |
| #include "ConfigurableElementAggregator.h" | |
| #include "AreaConfiguration.h" | |
| #include "Iterator.hpp" | |
| #include "Utility.h" | |
| #include "XmlParameterSerializingContext.h" | |
| #include <assert.h> | |
| #define base CElement | |
| CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName) | |
| { | |
| } | |
| bool CConfigurableElement::fromXml(const CXmlElement &xmlElement, | |
| CXmlSerializingContext &serializingContext) | |
| { | |
| auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); | |
| auto &accessContext = context.getAccessContext(); | |
| if (accessContext.serializeSettings()) { | |
| // As serialization and deserialisation are handled through the *same* function | |
| // the (de)serialize object can not be const in `serializeXmlSettings` signature. | |
| // As a result a const_cast is unavoidable :(. | |
| // Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast` | |
| return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement), | |
| static_cast<CConfigurationAccessContext &>(accessContext)); | |
| } | |
| return structureFromXml(xmlElement, serializingContext); | |
| } | |
| void CConfigurableElement::toXml(CXmlElement &xmlElement, | |
| CXmlSerializingContext &serializingContext) const | |
| { | |
| auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); | |
| auto &accessContext = context.getAccessContext(); | |
| if (accessContext.serializeSettings()) { | |
| serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext)); | |
| } else { | |
| structureToXml(xmlElement, serializingContext); | |
| } | |
| } | |
| // XML configuration settings parsing | |
| bool CConfigurableElement::serializeXmlSettings( | |
| CXmlElement &xmlConfigurationSettingsElementContent, | |
| CConfigurationAccessContext &configurationAccessContext) const | |
| { | |
| size_t uiNbChildren = getNbChildren(); | |
| if (!configurationAccessContext.serializeOut()) { | |
| // Just do basic checks and propagate to children | |
| CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent); | |
| CXmlElement xmlChildConfigurableElementSettingsElement; | |
| // Propagate to children | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| // Get child | |
| const CConfigurableElement *pChildConfigurableElement = | |
| static_cast<const CConfigurableElement *>(getChild(index)); | |
| if (!it.next(xmlChildConfigurableElementSettingsElement)) { | |
| // Structure error | |
| configurationAccessContext.setError( | |
| "Configuration settings parsing: missing child node " + | |
| pChildConfigurableElement->getXmlElementName() + " (name:" + | |
| pChildConfigurableElement->getName() + ") in " + getName()); | |
| return false; | |
| } | |
| // Check element type matches in type | |
| if (xmlChildConfigurableElementSettingsElement.getType() != | |
| pChildConfigurableElement->getXmlElementName()) { | |
| // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility | |
| // shall be ensured. | |
| // | |
| // So checking if this case occurs, i.e. element name is "ParameterBlock" | |
| // but xml setting name is "Component". | |
| bool compatibilityCase = | |
| (pChildConfigurableElement->getXmlElementName() == "ParameterBlock") && | |
| (xmlChildConfigurableElementSettingsElement.getType() == "Component"); | |
| // Error if the compatibility case does not occur. | |
| if (!compatibilityCase) { | |
| // Type error | |
| configurationAccessContext.setError( | |
| "Configuration settings parsing: Settings " | |
| "for configurable element " + | |
| pChildConfigurableElement->getQualifiedPath() + | |
| " does not match expected type: " + | |
| xmlChildConfigurableElementSettingsElement.getType() + " instead of " + | |
| pChildConfigurableElement->getKind()); | |
| return false; | |
| } | |
| } | |
| // Check element type matches in name | |
| if (xmlChildConfigurableElementSettingsElement.getNameAttribute() != | |
| pChildConfigurableElement->getName()) { | |
| // Name error | |
| configurationAccessContext.setError( | |
| "Configuration settings parsing: Under configurable element " + | |
| getQualifiedPath() + ", expected element name " + | |
| pChildConfigurableElement->getName() + " but found " + | |
| xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead"); | |
| return false; | |
| } | |
| // Parse child configurable element's settings | |
| if (!pChildConfigurableElement->serializeXmlSettings( | |
| xmlChildConfigurableElementSettingsElement, configurationAccessContext)) { | |
| return false; | |
| } | |
| } | |
| // There should remain no configurable element to parse | |
| if (it.next(xmlChildConfigurableElementSettingsElement)) { | |
| // Structure error | |
| configurationAccessContext.setError( | |
| "Configuration settings parsing: Unexpected xml element node " + | |
| xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath()); | |
| return false; | |
| } | |
| } else { | |
| // Handle element name attribute | |
| xmlConfigurationSettingsElementContent.setNameAttribute(getName()); | |
| // Propagate to children | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| const CConfigurableElement *pChildConfigurableElement = | |
| static_cast<const CConfigurableElement *>(getChild(index)); | |
| // Create corresponding child element | |
| CXmlElement xmlChildConfigurableElementSettingsElement; | |
| xmlConfigurationSettingsElementContent.createChild( | |
| xmlChildConfigurableElementSettingsElement, | |
| pChildConfigurableElement->getXmlElementName()); | |
| // Propagate | |
| pChildConfigurableElement->serializeXmlSettings( | |
| xmlChildConfigurableElementSettingsElement, configurationAccessContext); | |
| } | |
| } | |
| // Done | |
| return true; | |
| } | |
| // AreaConfiguration creation | |
| CAreaConfiguration *CConfigurableElement::createAreaConfiguration( | |
| const CSyncerSet *pSyncerSet) const | |
| { | |
| return new CAreaConfiguration(this, pSyncerSet); | |
| } | |
| // Parameter access | |
| bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue, | |
| bool bSet, | |
| CParameterAccessContext ¶meterAccessContext) const | |
| { | |
| std::string *pStrChildName = pathNavigator.next(); | |
| if (!pStrChildName) { | |
| parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") + | |
| pathNavigator.getCurrentPath() + | |
| " because it is not a parameter"); | |
| return false; | |
| } | |
| const CConfigurableElement *pChild = | |
| static_cast<const CConfigurableElement *>(findChild(*pStrChildName)); | |
| if (!pChild) { | |
| parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath()); | |
| return false; | |
| } | |
| return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext); | |
| } | |
| // Whole element access | |
| void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes, | |
| CParameterAccessContext ¶meterAccessContext) const | |
| { | |
| bytes.resize(getFootPrint()); | |
| parameterAccessContext.getParameterBlackboard()->readBytes( | |
| bytes, getOffset() - parameterAccessContext.getBaseOffset()); | |
| } | |
| bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes, | |
| CParameterAccessContext ¶meterAccessContext) const | |
| { | |
| CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard(); | |
| // Size | |
| size_t size = getFootPrint(); | |
| // Check sizes match | |
| if (size != bytes.size()) { | |
| parameterAccessContext.setError(std::string("Wrong size: Expected: ") + | |
| std::to_string(size) + " Provided: " + | |
| std::to_string(bytes.size())); | |
| return false; | |
| } | |
| // Write bytes | |
| pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset()); | |
| if (not parameterAccessContext.getAutoSync()) { | |
| // Auto sync is not activated, sync will be defered until an explicit request | |
| return true; | |
| } | |
| CSyncerSet syncerSet; | |
| fillSyncerSet(syncerSet); | |
| core::Results res; | |
| if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) { | |
| parameterAccessContext.setError(utility::asString(res)); | |
| return false; | |
| } | |
| return true; | |
| } | |
| std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const | |
| { | |
| std::list<const CConfigurableElement *> configurableElementPath; | |
| const CElement *element = this; | |
| while (element != nullptr and isOfConfigurableElementType(element)) { | |
| auto configurableElement = static_cast<const CConfigurableElement *>(element); | |
| configurableElementPath.push_back(configurableElement); | |
| element = element->getParent(); | |
| } | |
| return configurableElementPath; | |
| } | |
| // Used for simulation and virtual subsystems | |
| void CConfigurableElement::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const | |
| { | |
| // Propagate to children | |
| size_t uiNbChildren = getNbChildren(); | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| const CConfigurableElement *pConfigurableElement = | |
| static_cast<const CConfigurableElement *>(getChild(index)); | |
| pConfigurableElement->setDefaultValues(parameterAccessContext); | |
| } | |
| } | |
| // Element properties | |
| void CConfigurableElement::showProperties(std::string &strResult) const | |
| { | |
| base::showProperties(strResult); | |
| strResult += "Total size: " + getFootprintAsString() + "\n"; | |
| } | |
| std::string CConfigurableElement::logValue(utility::ErrorContext &context) const | |
| { | |
| return logValue(static_cast<CParameterAccessContext &>(context)); | |
| } | |
| std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const | |
| { | |
| // By default, an element does not have a value. Only leaf elements have | |
| // one. This method could be pure virtual but then, several derived classes | |
| // would need to implement it in order to simply return an empty string. | |
| return ""; | |
| } | |
| // Offset | |
| void CConfigurableElement::setOffset(size_t offset) | |
| { | |
| // Assign offset locally | |
| _offset = offset; | |
| // Propagate to children | |
| size_t uiNbChildren = getNbChildren(); | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| CConfigurableElement *pConfigurableElement = | |
| static_cast<CConfigurableElement *>(getChild(index)); | |
| pConfigurableElement->setOffset(offset); | |
| offset += pConfigurableElement->getFootPrint(); | |
| } | |
| } | |
| size_t CConfigurableElement::getOffset() const | |
| { | |
| return _offset; | |
| } | |
| // Memory | |
| size_t CConfigurableElement::getFootPrint() const | |
| { | |
| size_t uiSize = 0; | |
| size_t uiNbChildren = getNbChildren(); | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| const CConfigurableElement *pConfigurableElement = | |
| static_cast<const CConfigurableElement *>(getChild(index)); | |
| uiSize += pConfigurableElement->getFootPrint(); | |
| } | |
| return uiSize; | |
| } | |
| // Browse parent path to find syncer | |
| ISyncer *CConfigurableElement::getSyncer() const | |
| { | |
| // Check parent | |
| const CElement *pParent = getParent(); | |
| if (isOfConfigurableElementType(pParent)) { | |
| return static_cast<const CConfigurableElement *>(pParent)->getSyncer(); | |
| } | |
| return nullptr; | |
| } | |
| // Syncer set (me, ascendant or descendant ones) | |
| void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const | |
| { | |
| // Try me or ascendants | |
| ISyncer *pMineOrAscendantSyncer = getSyncer(); | |
| if (pMineOrAscendantSyncer) { | |
| // Provide found syncer object | |
| syncerSet += pMineOrAscendantSyncer; | |
| // Done | |
| return; | |
| } | |
| // Fetch descendant ones | |
| fillSyncerSetFromDescendant(syncerSet); | |
| } | |
| // Syncer set (descendant) | |
| void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const | |
| { | |
| // Dig | |
| size_t uiNbChildren = getNbChildren(); | |
| for (size_t index = 0; index < uiNbChildren; index++) { | |
| const CConfigurableElement *pConfigurableElement = | |
| static_cast<const CConfigurableElement *>(getChild(index)); | |
| pConfigurableElement->fillSyncerSetFromDescendant(syncerSet); | |
| } | |
| } | |
| // Configurable domain association | |
| void CConfigurableElement::addAttachedConfigurableDomain( | |
| const CConfigurableDomain *pConfigurableDomain) | |
| { | |
| _configurableDomainList.push_back(pConfigurableDomain); | |
| } | |
| void CConfigurableElement::removeAttachedConfigurableDomain( | |
| const CConfigurableDomain *pConfigurableDomain) | |
| { | |
| _configurableDomainList.remove(pConfigurableDomain); | |
| } | |
| // Belonging domain | |
| bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const | |
| { | |
| if (containsConfigurableDomain(pConfigurableDomain)) { | |
| return true; | |
| } | |
| return belongsToDomainAscending(pConfigurableDomain); | |
| } | |
| // Belonging domains | |
| void CConfigurableElement::getBelongingDomains( | |
| std::list<const CConfigurableDomain *> &configurableDomainList) const | |
| { | |
| configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(), | |
| _configurableDomainList.end()); | |
| // Check parent | |
| const CElement *pParent = getParent(); | |
| if (isOfConfigurableElementType(pParent)) { | |
| static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains( | |
| configurableDomainList); | |
| } | |
| } | |
| void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const | |
| { | |
| // Get belonging domain list | |
| std::list<const CConfigurableDomain *> configurableDomainList; | |
| getBelongingDomains(configurableDomainList); | |
| // Fill list | |
| listDomains(configurableDomainList, strResult, bVertical); | |
| } | |
| // Elements with no domains | |
| void CConfigurableElement::listRogueElements(std::string &strResult) const | |
| { | |
| // Get rogue element aggregate list (no associated domain) | |
| std::list<const CConfigurableElement *> rogueElementList; | |
| CConfigurableElementAggregator configurableElementAggregator( | |
| rogueElementList, &CConfigurableElement::hasNoDomainAssociated); | |
| configurableElementAggregator.aggegate(this); | |
| // Build list as std::string | |
| std::list<const CConfigurableElement *>::const_iterator it; | |
| for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) { | |
| const CConfigurableElement *pConfigurableElement = *it; | |
| strResult += pConfigurableElement->getPath() + "\n"; | |
| } | |
| } | |
| bool CConfigurableElement::isRogue() const | |
| { | |
| // Check not belonging to any domin from current level and towards ascendents | |
| if (getBelongingDomainCount() != 0) { | |
| return false; | |
| } | |
| // Get a list of elements (current + descendants) with no domains associated | |
| std::list<const CConfigurableElement *> rogueElementList; | |
| CConfigurableElementAggregator agregator(rogueElementList, | |
| &CConfigurableElement::hasNoDomainAssociated); | |
| agregator.aggegate(this); | |
| // Check only one element found which ought to be current one | |
| return (rogueElementList.size() == 1) && (rogueElementList.front() == this); | |
| } | |
| // Footprint as string | |
| std::string CConfigurableElement::getFootprintAsString() const | |
| { | |
| // Get size as string | |
| return std::to_string(getFootPrint()) + " byte(s)"; | |
| } | |
| // Matching check for no domain association | |
| bool CConfigurableElement::hasNoDomainAssociated() const | |
| { | |
| return _configurableDomainList.empty(); | |
| } | |
| // Matching check for no valid associated domains | |
| bool CConfigurableElement::hasNoValidDomainAssociated() const | |
| { | |
| if (_configurableDomainList.empty()) { | |
| // No domains associated | |
| return true; | |
| } | |
| ConfigurableDomainListConstIterator it; | |
| // Browse all configurable domains for validity checking | |
| for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { | |
| const CConfigurableDomain *pConfigurableDomain = *it; | |
| if (pConfigurableDomain->isApplicableConfigurationValid(this)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| // Owning domains | |
| void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const | |
| { | |
| // Fill list | |
| listDomains(_configurableDomainList, strResult, bVertical); | |
| } | |
| size_t CConfigurableElement::getBelongingDomainCount() const | |
| { | |
| // Get belonging domain list | |
| std::list<const CConfigurableDomain *> configurableDomainList; | |
| getBelongingDomains(configurableDomainList); | |
| return configurableDomainList.size(); | |
| } | |
| void CConfigurableElement::listDomains( | |
| const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult, | |
| bool bVertical) const | |
| { | |
| // Fill list | |
| ConfigurableDomainListConstIterator it; | |
| bool bFirst = true; | |
| // Browse all configurable domains for comparison | |
| for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) { | |
| const CConfigurableDomain *pConfigurableDomain = *it; | |
| if (!bVertical && !bFirst) { | |
| strResult += ", "; | |
| } | |
| strResult += pConfigurableDomain->getName(); | |
| if (bVertical) { | |
| strResult += "\n"; | |
| } else { | |
| bFirst = false; | |
| } | |
| } | |
| } | |
| bool CConfigurableElement::containsConfigurableDomain( | |
| const CConfigurableDomain *pConfigurableDomain) const | |
| { | |
| ConfigurableDomainListConstIterator it; | |
| // Browse all configurable domains for comparison | |
| for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { | |
| if (pConfigurableDomain == *it) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // Belonging domain ascending search | |
| bool CConfigurableElement::belongsToDomainAscending( | |
| const CConfigurableDomain *pConfigurableDomain) const | |
| { | |
| // Check parent | |
| const CElement *pParent = getParent(); | |
| if (isOfConfigurableElementType(pParent)) { | |
| return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain); | |
| } | |
| return false; | |
| } | |
| // Belonging subsystem | |
| const CSubsystem *CConfigurableElement::getBelongingSubsystem() const | |
| { | |
| const CElement *pParent = getParent(); | |
| // Stop at system class | |
| if (!pParent->getParent()) { | |
| return nullptr; | |
| } | |
| return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem(); | |
| } | |
| // Check element is a parameter | |
| bool CConfigurableElement::isParameter() const | |
| { | |
| return false; | |
| } | |
| // Check parent is still of current type (by structure knowledge) | |
| bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const | |
| { | |
| assert(pParent); | |
| // Up to system class | |
| return !!pParent->getParent(); | |
| } |