1/* 2 * Copyright (c) 2011-2015, 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 <assert.h> 39#include <sstream> 40 41#define base CConfigurableElement 42 43using std::string; 44using std::list; 45 46CSubsystem::CSubsystem(const string &strName, core::log::Logger &logger) 47 : base(strName), _pComponentLibrary(new CComponentLibrary), 48 _pInstanceDefinition(new CInstanceDefinition), _logger(logger) 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 55CSubsystem::~CSubsystem() 56{ 57 // FIXME use unique_ptr, would make this method empty 58 59 for (auto *subsystemObject : _subsystemObjectList) { 60 61 delete subsystemObject; 62 } 63 64 // Remove susbsystem creators 65 for (auto *subsystemObjectCreator : _subsystemObjectCreatorArray) { 66 67 delete subsystemObjectCreator; 68 } 69 70 // Order matters! 71 delete _pInstanceDefinition; 72 delete _pComponentLibrary; 73 74 delete _pMappingData; 75} 76 77string CSubsystem::getKind() const 78{ 79 return "Subsystem"; 80} 81 82// Susbsystem sanity 83bool CSubsystem::isAlive() const 84{ 85 return true; 86} 87 88// Resynchronization after subsystem restart needed 89bool CSubsystem::needResync(bool /*bClear*/) 90{ 91 return false; 92} 93 94bool CSubsystem::structureFromXml(const CXmlElement &xmlElement, 95 CXmlSerializingContext &serializingContext) 96{ 97 // Subsystem class does not rely on generic fromXml algorithm of Element class. 98 // So, setting here the description if found as XML attribute. 99 string description; 100 xmlElement.getAttribute(gDescriptionPropertyName, description); 101 setDescription(description); 102 103 // Context 104 CXmlParameterSerializingContext ¶meterBuildContext = 105 static_cast<CXmlParameterSerializingContext &>(serializingContext); 106 107 // Install temporary component library for further component creation 108 parameterBuildContext.setComponentLibrary(_pComponentLibrary); 109 110 CXmlElement childElement; 111 112 // Manage mapping attribute 113 string rawMapping; 114 xmlElement.getAttribute("Mapping", rawMapping); 115 if (!rawMapping.empty()) { 116 117 std::string error; 118 _pMappingData = new CMappingData; 119 if (!_pMappingData->init(rawMapping, error)) { 120 121 serializingContext.setError("Invalid Mapping data from XML element '" + 122 xmlElement.getPath() + "': " + error); 123 return false; 124 } 125 } 126 127 // XML populate ComponentLibrary 128 xmlElement.getChildElement("ComponentLibrary", childElement); 129 130 if (!_pComponentLibrary->fromXml(childElement, serializingContext)) { 131 132 return false; 133 } 134 135 // XML populate InstanceDefintion 136 xmlElement.getChildElement("InstanceDefintion", childElement); 137 if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) { 138 139 return false; 140 } 141 142 // Create components 143 _pInstanceDefinition->createInstances(this); 144 145 // Execute mapping to create subsystem mapping entities 146 string strError; 147 if (!mapSubsystemElements(strError)) { 148 149 serializingContext.setError(strError); 150 151 return false; 152 } 153 154 return true; 155} 156 157bool CSubsystem::mapSubsystemElements(string &strError) 158{ 159 // Default mapping context 160 CMappingContext context(_contextMappingKeyArray.size()); 161 // Add Subsystem-level mapping data, which will be propagated to all children 162 handleMappingContext(this, context, strError); 163 164 _contextStack.push(context); 165 166 // Map all instantiated subelements in subsystem 167 size_t nbChildren = getNbChildren(); 168 169 for (size_t child = 0; child < nbChildren; child++) { 170 171 CInstanceConfigurableElement *pInstanceConfigurableChildElement = 172 static_cast<CInstanceConfigurableElement *>(getChild(child)); 173 174 if (!pInstanceConfigurableChildElement->map(*this, strError)) { 175 176 return false; 177 } 178 } 179 return true; 180} 181 182// Formats the mapping of the ConfigurableElements 183string CSubsystem::formatMappingDataList( 184 const list<const CConfigurableElement *> &configurableElementPath) const 185{ 186 // The list is parsed in reverse order because it has been filled from the leaf to the trunk 187 // of the tree. When formatting the mapping, we want to start from the subsystem level 188 std::list<string> mappings; 189 list<const CConfigurableElement *>::const_reverse_iterator it; 190 for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) { 191 192 auto maybeMapping = (*it)->getFormattedMapping(); 193 if (not maybeMapping.empty()) { 194 mappings.push_back(maybeMapping); 195 } 196 } 197 198 return utility::asString(mappings, ", "); 199} 200 201// Find the CSubystemObject containing a specific CInstanceConfigurableElement 202const CSubsystemObject *CSubsystem::findSubsystemObjectFromConfigurableElement( 203 const CInstanceConfigurableElement *pInstanceConfigurableElement) const 204{ 205 206 list<CSubsystemObject *>::const_iterator it; 207 for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) { 208 209 // Check if one of the SubsystemObjects is associated with a ConfigurableElement 210 // corresponding to the expected one 211 const CSubsystemObject *pSubsystemObject = *it; 212 213 if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) { 214 215 return pSubsystemObject; 216 } 217 } 218 219 return nullptr; 220} 221 222void CSubsystem::findSubsystemLevelMappingKeyValue( 223 const CInstanceConfigurableElement *pInstanceConfigurableElement, string &strMappingKey, 224 string &strMappingValue) const 225{ 226 // Find creator to get key name 227 std::vector<CSubsystemObjectCreator *>::const_iterator it; 228 for (it = _subsystemObjectCreatorArray.begin(); it != _subsystemObjectCreatorArray.end(); 229 ++it) { 230 231 const CSubsystemObjectCreator *pSubsystemObjectCreator = *it; 232 233 strMappingKey = pSubsystemObjectCreator->getMappingKey(); 234 235 // Check if the ObjectCreator MappingKey corresponds to the element mapping data 236 const string *pStrValue; 237 if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) { 238 239 strMappingValue = *pStrValue; 240 return; 241 } 242 } 243 assert(0); 244} 245 246// Formats the mapping data as a comma separated list of key value pairs 247string CSubsystem::getFormattedSubsystemMappingData( 248 const CInstanceConfigurableElement *pInstanceConfigurableElement) const 249{ 250 // Find the SubsystemObject related to pInstanceConfigurableElement 251 const CSubsystemObject *pSubsystemObject = 252 findSubsystemObjectFromConfigurableElement(pInstanceConfigurableElement); 253 254 // Exit if node does not correspond to a SubsystemObject 255 if (pSubsystemObject == NULL) { 256 257 return ""; 258 } 259 260 // Find SubsystemCreator mapping key 261 string strMappingKey; 262 string strMappingValue; // mapping value where amends are not replaced by their value 263 findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue); 264 265 // Find SubSystemObject mapping value (with amends replaced by their value) 266 return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue(); 267} 268 269string CSubsystem::getMapping(list<const CConfigurableElement *> &configurableElementPath) const 270{ 271 if (configurableElementPath.empty()) { 272 273 return ""; 274 } 275 276 // Get the first element, which is the element containing the amended mapping 277 const CInstanceConfigurableElement *pInstanceConfigurableElement = 278 static_cast<const CInstanceConfigurableElement *>(configurableElementPath.front()); 279 280 // Format context mapping data 281 string strValue = formatMappingDataList(configurableElementPath); 282 283 // Print the mapping of the first node, which corresponds to a SubsystemObject 284 auto subsystemObjectAmendedMapping = 285 getFormattedSubsystemMappingData(pInstanceConfigurableElement); 286 if (not subsystemObjectAmendedMapping.empty()) { 287 strValue += ", " + subsystemObjectAmendedMapping; 288 } 289 290 return strValue; 291} 292 293// Used for simulation and virtual subsystems 294void CSubsystem::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const 295{ 296 base::setDefaultValues(parameterAccessContext); 297} 298 299// Belonging subsystem 300const CSubsystem *CSubsystem::getBelongingSubsystem() const 301{ 302 return this; 303} 304 305// Subsystem context mapping keys publication 306void CSubsystem::addContextMappingKey(const string &strMappingKey) 307{ 308 _contextMappingKeyArray.push_back(strMappingKey); 309} 310 311// Subsystem object creator publication (strong reference) 312void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator *pSubsystemObjectCreator) 313{ 314 _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator); 315} 316 317// Generic error handling from derived subsystem classes 318string CSubsystem::getMappingError(const string &strKey, const string &strMessage, 319 const CConfigurableElement *pConfigurableElement) const 320{ 321 return getName() + " " + getKind() + " " + "mapping:\n" + strKey + " " + "error: \"" + 322 strMessage + "\" " + "for element " + pConfigurableElement->getPath(); 323} 324 325bool CSubsystem::getMappingData(const std::string &strKey, const std::string *&pStrValue) const 326{ 327 if (_pMappingData) { 328 329 return _pMappingData->getValue(strKey, pStrValue); 330 } 331 return false; 332} 333 334// Returns the formatted mapping 335std::string CSubsystem::getFormattedMapping() const 336{ 337 if (!_pMappingData) { 338 return ""; 339 } 340 return _pMappingData->asString(); 341} 342 343// Mapping generic context handling 344bool CSubsystem::handleMappingContext(const CConfigurableElement *pConfigurableElement, 345 CMappingContext &context, string &strError) const 346{ 347 // Feed context with found mapping data 348 for (size_t item = 0; item < _contextMappingKeyArray.size(); item++) { 349 350 const string &strKey = _contextMappingKeyArray[item]; 351 const string *pStrValue; 352 353 if (pConfigurableElement->getMappingData(strKey, pStrValue)) { 354 // Assign item to context 355 if (!context.setItem(item, &strKey, pStrValue)) { 356 357 strError = getMappingError(strKey, "Already set", pConfigurableElement); 358 359 return false; 360 } 361 } 362 } 363 return true; 364} 365 366// Subsystem object creation handling 367bool CSubsystem::handleSubsystemObjectCreation( 368 CInstanceConfigurableElement *pInstanceConfigurableElement, CMappingContext &context, 369 bool &bHasCreatedSubsystemObject, string &strError) 370{ 371 bHasCreatedSubsystemObject = false; 372 373 for (const auto *pSubsystemObjectCreator : _subsystemObjectCreatorArray) { 374 375 // Mapping key 376 string strKey = pSubsystemObjectCreator->getMappingKey(); 377 // Object id 378 const string *pStrValue; 379 380 if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) { 381 382 // First check context consistency 383 // (required ancestors must have been set prior to object creation) 384 uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask(); 385 386 for (size_t uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size(); 387 uiAncestorKey++) { 388 389 if (!((1 << uiAncestorKey) & uiAncestorMask)) { 390 // Ancestor not required 391 continue; 392 } 393 // Check ancestor was provided 394 if (!context.iSet(uiAncestorKey)) { 395 396 strError = 397 getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] + " not set", 398 pInstanceConfigurableElement); 399 400 return false; 401 } 402 } 403 404 // Then check configurable element size is correct 405 if (pInstanceConfigurableElement->getFootPrint() > 406 pSubsystemObjectCreator->getMaxConfigurableElementSize()) { 407 408 string strSizeError = 409 "Size should not exceed " + 410 std::to_string(pSubsystemObjectCreator->getMaxConfigurableElementSize()); 411 412 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement); 413 414 return false; 415 } 416 417 // Do create object and keep its track 418 _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate( 419 *pStrValue, pInstanceConfigurableElement, context, _logger)); 420 421 // Indicate subsytem creation to caller 422 bHasCreatedSubsystemObject = true; 423 424 // The subsystem Object has been instantiated, no need to continue looking for an 425 // instantiation mapping 426 break; 427 } 428 } 429 430 return true; 431} 432 433// From IMapper 434// Handle a configurable element mapping 435bool CSubsystem::mapBegin(CInstanceConfigurableElement *pInstanceConfigurableElement, 436 bool &bKeepDiving, string &strError) 437{ 438 // Get current context 439 CMappingContext context = _contextStack.top(); 440 441 // Add mapping in context 442 if (!handleMappingContext(pInstanceConfigurableElement, context, strError)) { 443 444 return false; 445 } 446 447 // Push context 448 _contextStack.push(context); 449 450 // Assume diving by default 451 bKeepDiving = true; 452 453 // Deal with ambiguous usage of parameter blocks 454 bool bShouldCreateSubsystemObject = true; 455 456 switch (pInstanceConfigurableElement->getType()) { 457 458 case CInstanceConfigurableElement::EComponent: 459 case CInstanceConfigurableElement::EParameterBlock: 460 // Subsystem object creation is optional in parameter blocks 461 bShouldCreateSubsystemObject = false; 462 // No break 463 case CInstanceConfigurableElement::EBitParameterBlock: 464 case CInstanceConfigurableElement::EParameter: 465 case CInstanceConfigurableElement::EStringParameter: 466 467 bool bHasCreatedSubsystemObject; 468 469 if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context, 470 bHasCreatedSubsystemObject, strError)) { 471 472 return false; 473 } 474 // Check for creation error 475 if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) { 476 477 strError = getMappingError("Not found", "Subsystem object mapping key is missing", 478 pInstanceConfigurableElement); 479 return false; 480 } 481 // Not created and no error, keep diving 482 bKeepDiving = !bHasCreatedSubsystemObject; 483 484 return true; 485 486 default: 487 assert(0); 488 return false; 489 } 490} 491 492void CSubsystem::mapEnd() 493{ 494 // Unstack context 495 _contextStack.pop(); 496} 497