Home | History | Annotate | Download | only in parameter
      1 /*
      2  * Copyright (c) 2011-2014, Intel Corporation
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright notice, this
      9  * list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright notice,
     12  * this list of conditions and the following disclaimer in the documentation and/or
     13  * other materials provided with the distribution.
     14  *
     15  * 3. Neither the name of the copyright holder nor the names of its contributors
     16  * may be used to endorse or promote products derived from this software without
     17  * specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 #include "Subsystem.h"
     31 #include "ComponentLibrary.h"
     32 #include "InstanceDefinition.h"
     33 #include "XmlParameterSerializingContext.h"
     34 #include "ParameterAccessContext.h"
     35 #include "ConfigurationAccessContext.h"
     36 #include "SubsystemObjectCreator.h"
     37 #include "MappingData.h"
     38 #include "Utility.h"
     39 #include <assert.h>
     40 #include <sstream>
     41 
     42 #define base CConfigurableElementWithMapping
     43 
     44 using std::string;
     45 using std::list;
     46 using std::ostringstream;
     47 
     48 CSubsystem::CSubsystem(const string& strName) : base(strName), _pComponentLibrary(new CComponentLibrary), _pInstanceDefinition(new CInstanceDefinition), _bBigEndian(false), _pMappingData(NULL)
     49 {
     50     // Note: A subsystem contains instance components
     51     // InstanceDefintion and ComponentLibrary objects are then not chosen to be children
     52     // They'll be delt with locally
     53 }
     54 
     55 CSubsystem::~CSubsystem()
     56 {
     57     // Remove subsystem objects
     58     SubsystemObjectListIterator subsystemObjectIt;
     59 
     60     for (subsystemObjectIt = _subsystemObjectList.begin(); subsystemObjectIt != _subsystemObjectList.end(); ++subsystemObjectIt) {
     61 
     62         delete *subsystemObjectIt;
     63     }
     64 
     65     // Remove susbsystem creators
     66     uint32_t uiIndex;
     67 
     68     for (uiIndex = 0; uiIndex < _subsystemObjectCreatorArray.size(); uiIndex++) {
     69 
     70         delete _subsystemObjectCreatorArray[uiIndex];
     71     }
     72 
     73     // Order matters!
     74     delete _pInstanceDefinition;
     75     delete _pComponentLibrary;
     76 
     77     delete _pMappingData;
     78 }
     79 
     80 string CSubsystem::getKind() const
     81 {
     82     return "Subsystem";
     83 }
     84 
     85 // Susbsystem Endianness
     86 bool CSubsystem::isBigEndian() const
     87 {
     88     return _bBigEndian;
     89 }
     90 
     91 // Susbsystem sanity
     92 bool CSubsystem::isAlive() const
     93 {
     94     return true;
     95 }
     96 
     97 // Resynchronization after subsystem restart needed
     98 bool CSubsystem::needResync(bool bClear)
     99 {
    100     (void)bClear;
    101 
    102     return false;
    103 }
    104 
    105 // From IXmlSink
    106 bool CSubsystem::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
    107 {
    108     // Subsystem class does not rely on generic fromXml algorithm of Element class.
    109     // So, setting here the description if found as XML attribute.
    110     setDescription(getXmlDescriptionAttribute(xmlElement));
    111 
    112     // Context
    113     CXmlParameterSerializingContext& parameterBuildContext = static_cast<CXmlParameterSerializingContext&>(serializingContext);
    114 
    115     // Install temporary component library for further component creation
    116     parameterBuildContext.setComponentLibrary(_pComponentLibrary);
    117 
    118     CXmlElement childElement;
    119 
    120     // Manage mapping attribute
    121     if (xmlElement.hasAttribute("Mapping")) {
    122 
    123         _pMappingData = new CMappingData;
    124         if (!_pMappingData->fromXml(xmlElement, serializingContext)) {
    125 
    126             return false;
    127         }
    128     }
    129 
    130     // XML populate ComponentLibrary
    131     xmlElement.getChildElement("ComponentLibrary", childElement);
    132 
    133     if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
    134 
    135         return false;
    136     }
    137 
    138     // XML populate InstanceDefintion
    139     xmlElement.getChildElement("InstanceDefintion", childElement);
    140     if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
    141 
    142         return false;
    143     }
    144 
    145     // Create components
    146     _pInstanceDefinition->createInstances(this);
    147 
    148     // Execute mapping to create subsystem mapping entities
    149     string strError;
    150     if (!mapSubsystemElements(strError)) {
    151 
    152         serializingContext.setError(strError);
    153 
    154         return false;
    155     }
    156 
    157     // Endianness
    158     _bBigEndian = xmlElement.getAttributeBoolean("Endianness", "Big");
    159 
    160     return true;
    161 }
    162 
    163 // XML configuration settings parsing
    164 bool CSubsystem::serializeXmlSettings(CXmlElement& xmlConfigurationSettingsElementContent, CConfigurationAccessContext& configurationAccessContext) const
    165 {
    166     // Fix Endianness
    167     configurationAccessContext.setBigEndianSubsystem(_bBigEndian);
    168 
    169     return base::serializeXmlSettings(xmlConfigurationSettingsElementContent, configurationAccessContext);
    170 }
    171 
    172 
    173 bool CSubsystem::mapSubsystemElements(string& strError)
    174 {
    175     // Default mapping context
    176     CMappingContext context(_contextMappingKeyArray.size());
    177     // Add Subsystem-level mapping data, which will be propagated to all children
    178     handleMappingContext(this, context, strError);
    179 
    180     _contextStack.push(context);
    181 
    182     // Map all instantiated subelements in subsystem
    183     size_t uiNbChildren = getNbChildren();
    184     size_t uiChild;
    185 
    186     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
    187 
    188         CInstanceConfigurableElement* pInstanceConfigurableChildElement = static_cast<CInstanceConfigurableElement*>(getChild(uiChild));
    189 
    190         if (!pInstanceConfigurableChildElement->map(*this, strError)) {
    191 
    192             return false;
    193         }
    194     }
    195     return true;
    196 }
    197 
    198 // Parameter access
    199 bool CSubsystem::accessValue(CPathNavigator& pathNavigator, string& strValue, bool bSet, CParameterAccessContext& parameterAccessContext) const
    200 {
    201     // Deal with Endianness
    202     parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
    203 
    204     return base::accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
    205 }
    206 
    207 // Formats the mapping of the ConfigurableElements
    208 string CSubsystem::formatMappingDataList(
    209         const list<const CConfigurableElement*>& configurableElementPath) const
    210 {
    211     // The list is parsed in reverse order because it has been filled from the leaf to the trunk
    212     // of the tree. When formatting the mapping, we want to start from the subsystem level
    213     ostringstream ossStream;
    214     list<const CConfigurableElement*>::const_reverse_iterator it;
    215     for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
    216 
    217         const CInstanceConfigurableElement* pInstanceConfigurableElement =
    218                 static_cast<const CInstanceConfigurableElement*>(*it);
    219 
    220         ossStream << pInstanceConfigurableElement->getFormattedMapping() << ", ";
    221     }
    222     return ossStream.str();
    223 }
    224 
    225 // Find the CSubystemObject containing a specific CInstanceConfigurableElement
    226 const CSubsystemObject* CSubsystem::findSubsystemObjectFromConfigurableElement(
    227         const CInstanceConfigurableElement* pInstanceConfigurableElement) const {
    228 
    229     const CSubsystemObject* pSubsystemObject = NULL;
    230 
    231     list<CSubsystemObject*>::const_iterator it;
    232     for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
    233 
    234         // Check if one of the SubsystemObjects is associated with a ConfigurableElement
    235         // corresponding to the expected one
    236         pSubsystemObject = *it;
    237         if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
    238 
    239             break;
    240         }
    241     }
    242 
    243     return pSubsystemObject;
    244 }
    245 
    246 void CSubsystem::findSubsystemLevelMappingKeyValue(
    247         const CInstanceConfigurableElement* pInstanceConfigurableElement,
    248         string& strMappingKey,
    249         string& strMappingValue) const
    250 {
    251     // Find creator to get key name
    252     std::vector<CSubsystemObjectCreator*>::const_iterator it;
    253     for (it = _subsystemObjectCreatorArray.begin();
    254          it != _subsystemObjectCreatorArray.end(); ++it) {
    255 
    256         const CSubsystemObjectCreator* pSubsystemObjectCreator = *it;
    257 
    258         strMappingKey = pSubsystemObjectCreator->getMappingKey();
    259 
    260         // Check if the ObjectCreator MappingKey corresponds to the element mapping data
    261         const string* pStrValue;
    262         if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
    263 
    264             strMappingValue = *pStrValue;
    265             return;
    266         }
    267     }
    268     assert(0);
    269 }
    270 
    271 // Formats the mapping data as a comma separated list of key value pairs
    272 string CSubsystem::getFormattedSubsystemMappingData(
    273         const CInstanceConfigurableElement* pInstanceConfigurableElement) const
    274 {
    275     // Find the SubsystemObject related to pInstanceConfigurableElement
    276     const CSubsystemObject* pSubsystemObject = findSubsystemObjectFromConfigurableElement(
    277                 pInstanceConfigurableElement);
    278 
    279     // Exit if node does not correspond to a SubsystemObject
    280     if (pSubsystemObject == NULL) {
    281 
    282         return "";
    283     }
    284 
    285     // Find SubsystemCreator mapping key
    286     string strMappingKey;
    287     string strMappingValue; // mapping value where amends are not replaced by their value
    288     findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
    289 
    290     // Find SubSystemObject mapping value (with amends replaced by their value)
    291     return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
    292 }
    293 
    294 string CSubsystem::getMapping(list<const CConfigurableElement*>& configurableElementPath) const
    295 {
    296     if (configurableElementPath.empty()) {
    297 
    298         return "";
    299     }
    300 
    301     // Get the first element, which is the element containing the amended mapping
    302     const CInstanceConfigurableElement* pInstanceConfigurableElement =
    303             static_cast<const CInstanceConfigurableElement*>(configurableElementPath.front());
    304     configurableElementPath.pop_front();
    305     // Now the list only contains elements whose mapping are related to the context
    306 
    307     // Format context mapping data
    308     string strValue = formatMappingDataList(configurableElementPath);
    309 
    310     // Print the mapping of the first node, which corresponds to a SubsystemObject
    311     strValue += getFormattedSubsystemMappingData(pInstanceConfigurableElement);
    312 
    313     return strValue;
    314 }
    315 
    316 void CSubsystem::logValue(string& strValue, CErrorContext& errorContext) const
    317 {
    318     CParameterAccessContext& parameterAccessContext = static_cast<CParameterAccessContext&>(errorContext);
    319 
    320     // Deal with Endianness
    321     parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
    322 
    323     return base::logValue(strValue, errorContext);
    324 }
    325 
    326 // Used for simulation and virtual subsystems
    327 void CSubsystem::setDefaultValues(CParameterAccessContext& parameterAccessContext) const
    328 {
    329     // Deal with Endianness
    330     parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
    331 
    332     base::setDefaultValues(parameterAccessContext);
    333 }
    334 
    335 // Belonging subsystem
    336 const CSubsystem* CSubsystem::getBelongingSubsystem() const
    337 {
    338     return this;
    339 }
    340 
    341 // Subsystem context mapping keys publication
    342 void CSubsystem::addContextMappingKey(const string& strMappingKey)
    343 {
    344     _contextMappingKeyArray.push_back(strMappingKey);
    345 }
    346 
    347 // Subsystem object creator publication (strong reference)
    348 void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator* pSubsystemObjectCreator)
    349 {
    350     _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
    351 }
    352 
    353 // Generic error handling from derived subsystem classes
    354 string CSubsystem::getMappingError(
    355         const string& strKey,
    356         const string& strMessage,
    357         const CConfigurableElementWithMapping* pConfigurableElementWithMapping) const
    358 {
    359     return getName() + " " + getKind() + " " +
    360             "mapping:\n" + strKey + " " +
    361             "error: \"" + strMessage + "\" " +
    362             "for element " + pConfigurableElementWithMapping->getPath();
    363 }
    364 
    365 
    366 bool CSubsystem::getMappingData(const std::string& strKey, const std::string*& pStrValue) const
    367 {
    368     if (_pMappingData) {
    369 
    370         return _pMappingData->getValue(strKey, pStrValue);
    371     }
    372     return false;
    373 }
    374 
    375 // Mapping generic context handling
    376 bool CSubsystem::handleMappingContext(
    377         const CConfigurableElementWithMapping* pConfigurableElementWithMapping,
    378         CMappingContext& context,
    379         string& strError) const
    380 {
    381     // Feed context with found mapping data
    382     uint32_t uiItem;
    383 
    384     for (uiItem = 0; uiItem < _contextMappingKeyArray.size(); uiItem++) {
    385 
    386         const string& strKey = _contextMappingKeyArray[uiItem];
    387         const string* pStrValue;
    388 
    389         if (pConfigurableElementWithMapping->getMappingData(strKey, pStrValue)) {
    390             // Assign item to context
    391             if (!context.setItem(uiItem, &strKey, pStrValue)) {
    392 
    393                 strError = getMappingError(strKey, "Already set", pConfigurableElementWithMapping);
    394 
    395                 return false;
    396             }
    397         }
    398     }
    399     return true;
    400 }
    401 
    402 // Subsystem object creation handling
    403 bool CSubsystem::handleSubsystemObjectCreation(
    404         CInstanceConfigurableElement* pInstanceConfigurableElement,
    405         CMappingContext& context, bool& bHasCreatedSubsystemObject, string& strError)
    406 {
    407     uint32_t uiItem;
    408     bHasCreatedSubsystemObject = false;
    409 
    410     for (uiItem = 0; uiItem < _subsystemObjectCreatorArray.size(); uiItem++) {
    411 
    412         const CSubsystemObjectCreator* pSubsystemObjectCreator =
    413                 _subsystemObjectCreatorArray[uiItem];
    414 
    415         // Mapping key
    416         string strKey = pSubsystemObjectCreator->getMappingKey();
    417         // Object id
    418         const string* pStrValue;
    419 
    420         if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
    421 
    422             // First check context consistency
    423             // (required ancestors must have been set prior to object creation)
    424             uint32_t uiAncestorKey;
    425             uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
    426 
    427             for (uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size(); uiAncestorKey++) {
    428 
    429                 if (!((1 << uiAncestorKey) & uiAncestorMask)) {
    430                     // Ancestor not required
    431                     continue;
    432                 }
    433                 // Check ancestor was provided
    434                 if (!context.iSet(uiAncestorKey)) {
    435 
    436                     strError = getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] +
    437                                                " not set", pInstanceConfigurableElement);
    438 
    439                     return false;
    440                 }
    441             }
    442 
    443             // Then check configurable element size is correct
    444             if (pInstanceConfigurableElement->getFootPrint() >
    445                 pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
    446 
    447                 string strSizeError = "Size should not exceed " +
    448                                       CUtility::toString(
    449                                         pSubsystemObjectCreator->getMaxConfigurableElementSize());
    450 
    451                 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
    452 
    453                 return false;
    454             }
    455 
    456             // Do create object and keep its track
    457             _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
    458                     *pStrValue, pInstanceConfigurableElement, context));
    459 
    460             // Indicate subsytem creation to caller
    461             bHasCreatedSubsystemObject = true;
    462 
    463             // The subsystem Object has been instantiated, no need to continue looking for an
    464             // instantiation mapping
    465             break;
    466         }
    467     }
    468 
    469     return true;
    470 }
    471 
    472 // From IMapper
    473 // Handle a configurable element mapping
    474 bool CSubsystem::mapBegin(CInstanceConfigurableElement* pInstanceConfigurableElement,
    475                           bool& bKeepDiving, string& strError)
    476 {
    477     // Get current context
    478     CMappingContext context = _contextStack.top();
    479 
    480     // Add mapping in context
    481     if (!handleMappingContext(pInstanceConfigurableElement, context,
    482                               strError)) {
    483 
    484         return false;
    485     }
    486 
    487     // Push context
    488     _contextStack.push(context);
    489 
    490     // Assume diving by default
    491     bKeepDiving = true;
    492 
    493     // Deal with ambiguous usage of parameter blocks
    494     bool bShouldCreateSubsystemObject = true;
    495 
    496     switch(pInstanceConfigurableElement->getType()) {
    497 
    498         case CInstanceConfigurableElement::EComponent:
    499         case CInstanceConfigurableElement::EParameterBlock:
    500             // Subsystem object creation is optional in parameter blocks
    501             bShouldCreateSubsystemObject = false;
    502             // No break
    503         case CInstanceConfigurableElement::EBitParameterBlock:
    504         case CInstanceConfigurableElement::EParameter:
    505         case CInstanceConfigurableElement::EStringParameter:
    506 
    507             bool bHasCreatedSubsystemObject;
    508 
    509             if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
    510                                                bHasCreatedSubsystemObject, strError)) {
    511 
    512                 return false;
    513             }
    514             // Check for creation error
    515             if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
    516 
    517                 strError = getMappingError("Not found",
    518                                            "Subsystem object mapping key is missing",
    519                                            pInstanceConfigurableElement);
    520                 return false;
    521             }
    522             // Not created and no error, keep diving
    523             bKeepDiving = !bHasCreatedSubsystemObject;
    524 
    525             return true;
    526 
    527         default:
    528             assert(0);
    529             return false;
    530     }
    531 }
    532 
    533 void CSubsystem::mapEnd()
    534 {
    535     // Unstack context
    536     _contextStack.pop();
    537 }
    538