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 "ConfigurableElement.h" 31 #include "MappingData.h" 32 #include "SyncerSet.h" 33 #include "ConfigurableDomain.h" 34 #include "ConfigurationAccessContext.h" 35 #include "ConfigurableElementAggregator.h" 36 #include "AreaConfiguration.h" 37 #include "Iterator.hpp" 38 #include "Utility.h" 39 #include "XmlParameterSerializingContext.h" 40 #include <assert.h> 41 42 #define base CElement 43 44 CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName) 45 { 46 } 47 48 bool CConfigurableElement::fromXml(const CXmlElement &xmlElement, 49 CXmlSerializingContext &serializingContext) 50 { 51 auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); 52 auto &accessContext = context.getAccessContext(); 53 54 if (accessContext.serializeSettings()) { 55 // As serialization and deserialisation are handled through the *same* function 56 // the (de)serialize object can not be const in `serializeXmlSettings` signature. 57 // As a result a const_cast is unavoidable :(. 58 // Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast` 59 return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement), 60 static_cast<CConfigurationAccessContext &>(accessContext)); 61 } 62 return structureFromXml(xmlElement, serializingContext); 63 } 64 65 void CConfigurableElement::toXml(CXmlElement &xmlElement, 66 CXmlSerializingContext &serializingContext) const 67 { 68 auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext); 69 auto &accessContext = context.getAccessContext(); 70 if (accessContext.serializeSettings()) { 71 72 serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext)); 73 } else { 74 75 structureToXml(xmlElement, serializingContext); 76 } 77 } 78 79 // XML configuration settings parsing 80 bool CConfigurableElement::serializeXmlSettings( 81 CXmlElement &xmlConfigurationSettingsElementContent, 82 CConfigurationAccessContext &configurationAccessContext) const 83 { 84 size_t uiNbChildren = getNbChildren(); 85 86 if (!configurationAccessContext.serializeOut()) { 87 // Just do basic checks and propagate to children 88 CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent); 89 90 CXmlElement xmlChildConfigurableElementSettingsElement; 91 92 // Propagate to children 93 for (size_t index = 0; index < uiNbChildren; index++) { 94 95 // Get child 96 const CConfigurableElement *pChildConfigurableElement = 97 static_cast<const CConfigurableElement *>(getChild(index)); 98 99 if (!it.next(xmlChildConfigurableElementSettingsElement)) { 100 101 // Structure error 102 configurationAccessContext.setError( 103 "Configuration settings parsing: missing child node " + 104 pChildConfigurableElement->getXmlElementName() + " (name:" + 105 pChildConfigurableElement->getName() + ") in " + getName()); 106 107 return false; 108 } 109 110 // Check element type matches in type 111 if (xmlChildConfigurableElementSettingsElement.getType() != 112 pChildConfigurableElement->getXmlElementName()) { 113 114 // "Component" tag has been renamed to "ParameterBlock", but retro-compatibility 115 // shall be ensured. 116 // 117 // So checking if this case occurs, i.e. element name is "ParameterBlock" 118 // but xml setting name is "Component". 119 bool compatibilityCase = 120 (pChildConfigurableElement->getXmlElementName() == "ParameterBlock") && 121 (xmlChildConfigurableElementSettingsElement.getType() == "Component"); 122 123 // Error if the compatibility case does not occur. 124 if (!compatibilityCase) { 125 126 // Type error 127 configurationAccessContext.setError( 128 "Configuration settings parsing: Settings " 129 "for configurable element " + 130 pChildConfigurableElement->getQualifiedPath() + 131 " does not match expected type: " + 132 xmlChildConfigurableElementSettingsElement.getType() + " instead of " + 133 pChildConfigurableElement->getKind()); 134 return false; 135 } 136 } 137 138 // Check element type matches in name 139 if (xmlChildConfigurableElementSettingsElement.getNameAttribute() != 140 pChildConfigurableElement->getName()) { 141 142 // Name error 143 configurationAccessContext.setError( 144 "Configuration settings parsing: Under configurable element " + 145 getQualifiedPath() + ", expected element name " + 146 pChildConfigurableElement->getName() + " but found " + 147 xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead"); 148 149 return false; 150 } 151 152 // Parse child configurable element's settings 153 if (!pChildConfigurableElement->serializeXmlSettings( 154 xmlChildConfigurableElementSettingsElement, configurationAccessContext)) { 155 156 return false; 157 } 158 } 159 // There should remain no configurable element to parse 160 if (it.next(xmlChildConfigurableElementSettingsElement)) { 161 162 // Structure error 163 configurationAccessContext.setError( 164 "Configuration settings parsing: Unexpected xml element node " + 165 xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath()); 166 167 return false; 168 } 169 } else { 170 // Handle element name attribute 171 xmlConfigurationSettingsElementContent.setNameAttribute(getName()); 172 173 // Propagate to children 174 for (size_t index = 0; index < uiNbChildren; index++) { 175 176 const CConfigurableElement *pChildConfigurableElement = 177 static_cast<const CConfigurableElement *>(getChild(index)); 178 179 // Create corresponding child element 180 CXmlElement xmlChildConfigurableElementSettingsElement; 181 182 xmlConfigurationSettingsElementContent.createChild( 183 xmlChildConfigurableElementSettingsElement, 184 pChildConfigurableElement->getXmlElementName()); 185 186 // Propagate 187 pChildConfigurableElement->serializeXmlSettings( 188 xmlChildConfigurableElementSettingsElement, configurationAccessContext); 189 } 190 } 191 // Done 192 return true; 193 } 194 195 // AreaConfiguration creation 196 CAreaConfiguration *CConfigurableElement::createAreaConfiguration( 197 const CSyncerSet *pSyncerSet) const 198 { 199 return new CAreaConfiguration(this, pSyncerSet); 200 } 201 202 // Parameter access 203 bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue, 204 bool bSet, 205 CParameterAccessContext ¶meterAccessContext) const 206 { 207 std::string *pStrChildName = pathNavigator.next(); 208 209 if (!pStrChildName) { 210 211 parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") + 212 pathNavigator.getCurrentPath() + 213 " because it is not a parameter"); 214 215 return false; 216 } 217 218 const CConfigurableElement *pChild = 219 static_cast<const CConfigurableElement *>(findChild(*pStrChildName)); 220 221 if (!pChild) { 222 223 parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath()); 224 225 return false; 226 } 227 228 return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext); 229 } 230 231 // Whole element access 232 void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes, 233 CParameterAccessContext ¶meterAccessContext) const 234 { 235 bytes.resize(getFootPrint()); 236 237 parameterAccessContext.getParameterBlackboard()->readBytes( 238 bytes, getOffset() - parameterAccessContext.getBaseOffset()); 239 } 240 241 bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes, 242 CParameterAccessContext ¶meterAccessContext) const 243 { 244 CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard(); 245 246 // Size 247 size_t size = getFootPrint(); 248 249 // Check sizes match 250 if (size != bytes.size()) { 251 252 parameterAccessContext.setError(std::string("Wrong size: Expected: ") + 253 std::to_string(size) + " Provided: " + 254 std::to_string(bytes.size())); 255 256 return false; 257 } 258 259 // Write bytes 260 pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset()); 261 262 if (not parameterAccessContext.getAutoSync()) { 263 // Auto sync is not activated, sync will be defered until an explicit request 264 return true; 265 } 266 267 CSyncerSet syncerSet; 268 fillSyncerSet(syncerSet); 269 core::Results res; 270 if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) { 271 272 parameterAccessContext.setError(utility::asString(res)); 273 return false; 274 } 275 return true; 276 } 277 278 std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const 279 { 280 std::list<const CConfigurableElement *> configurableElementPath; 281 282 const CElement *element = this; 283 while (element != nullptr and isOfConfigurableElementType(element)) { 284 auto configurableElement = static_cast<const CConfigurableElement *>(element); 285 286 configurableElementPath.push_back(configurableElement); 287 element = element->getParent(); 288 } 289 290 return configurableElementPath; 291 } 292 293 // Used for simulation and virtual subsystems 294 void CConfigurableElement::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const 295 { 296 // Propagate to children 297 size_t uiNbChildren = getNbChildren(); 298 299 for (size_t index = 0; index < uiNbChildren; index++) { 300 301 const CConfigurableElement *pConfigurableElement = 302 static_cast<const CConfigurableElement *>(getChild(index)); 303 304 pConfigurableElement->setDefaultValues(parameterAccessContext); 305 } 306 } 307 308 // Element properties 309 void CConfigurableElement::showProperties(std::string &strResult) const 310 { 311 base::showProperties(strResult); 312 313 strResult += "Total size: " + getFootprintAsString() + "\n"; 314 } 315 316 std::string CConfigurableElement::logValue(utility::ErrorContext &context) const 317 { 318 return logValue(static_cast<CParameterAccessContext &>(context)); 319 } 320 321 std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const 322 { 323 // By default, an element does not have a value. Only leaf elements have 324 // one. This method could be pure virtual but then, several derived classes 325 // would need to implement it in order to simply return an empty string. 326 return ""; 327 } 328 329 // Offset 330 void CConfigurableElement::setOffset(size_t offset) 331 { 332 // Assign offset locally 333 _offset = offset; 334 335 // Propagate to children 336 size_t uiNbChildren = getNbChildren(); 337 338 for (size_t index = 0; index < uiNbChildren; index++) { 339 340 CConfigurableElement *pConfigurableElement = 341 static_cast<CConfigurableElement *>(getChild(index)); 342 343 pConfigurableElement->setOffset(offset); 344 345 offset += pConfigurableElement->getFootPrint(); 346 } 347 } 348 349 size_t CConfigurableElement::getOffset() const 350 { 351 return _offset; 352 } 353 354 // Memory 355 size_t CConfigurableElement::getFootPrint() const 356 { 357 size_t uiSize = 0; 358 size_t uiNbChildren = getNbChildren(); 359 360 for (size_t index = 0; index < uiNbChildren; index++) { 361 362 const CConfigurableElement *pConfigurableElement = 363 static_cast<const CConfigurableElement *>(getChild(index)); 364 365 uiSize += pConfigurableElement->getFootPrint(); 366 } 367 368 return uiSize; 369 } 370 371 // Browse parent path to find syncer 372 ISyncer *CConfigurableElement::getSyncer() const 373 { 374 // Check parent 375 const CElement *pParent = getParent(); 376 377 if (isOfConfigurableElementType(pParent)) { 378 379 return static_cast<const CConfigurableElement *>(pParent)->getSyncer(); 380 } 381 return NULL; 382 } 383 384 // Syncer set (me, ascendant or descendant ones) 385 void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const 386 { 387 // Try me or ascendants 388 ISyncer *pMineOrAscendantSyncer = getSyncer(); 389 390 if (pMineOrAscendantSyncer) { 391 392 // Provide found syncer object 393 syncerSet += pMineOrAscendantSyncer; 394 395 // Done 396 return; 397 } 398 // Fetch descendant ones 399 fillSyncerSetFromDescendant(syncerSet); 400 } 401 402 // Syncer set (descendant) 403 void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const 404 { 405 // Dig 406 size_t uiNbChildren = getNbChildren(); 407 408 for (size_t index = 0; index < uiNbChildren; index++) { 409 410 const CConfigurableElement *pConfigurableElement = 411 static_cast<const CConfigurableElement *>(getChild(index)); 412 413 pConfigurableElement->fillSyncerSetFromDescendant(syncerSet); 414 } 415 } 416 417 // Configurable domain association 418 void CConfigurableElement::addAttachedConfigurableDomain( 419 const CConfigurableDomain *pConfigurableDomain) 420 { 421 _configurableDomainList.push_back(pConfigurableDomain); 422 } 423 424 void CConfigurableElement::removeAttachedConfigurableDomain( 425 const CConfigurableDomain *pConfigurableDomain) 426 { 427 _configurableDomainList.remove(pConfigurableDomain); 428 } 429 430 // Belonging domain 431 bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const 432 { 433 if (containsConfigurableDomain(pConfigurableDomain)) { 434 435 return true; 436 } 437 return belongsToDomainAscending(pConfigurableDomain); 438 } 439 440 // Belonging domains 441 void CConfigurableElement::getBelongingDomains( 442 std::list<const CConfigurableDomain *> &configurableDomainList) const 443 { 444 configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(), 445 _configurableDomainList.end()); 446 447 // Check parent 448 const CElement *pParent = getParent(); 449 450 if (isOfConfigurableElementType(pParent)) { 451 452 static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains( 453 configurableDomainList); 454 } 455 } 456 457 void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const 458 { 459 // Get belonging domain list 460 std::list<const CConfigurableDomain *> configurableDomainList; 461 462 getBelongingDomains(configurableDomainList); 463 464 // Fill list 465 listDomains(configurableDomainList, strResult, bVertical); 466 } 467 468 // Elements with no domains 469 void CConfigurableElement::listRogueElements(std::string &strResult) const 470 { 471 // Get rogue element aggregate list (no associated domain) 472 std::list<const CConfigurableElement *> rogueElementList; 473 474 CConfigurableElementAggregator configurableElementAggregator( 475 rogueElementList, &CConfigurableElement::hasNoDomainAssociated); 476 477 configurableElementAggregator.aggegate(this); 478 479 // Build list as std::string 480 std::list<const CConfigurableElement *>::const_iterator it; 481 482 for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) { 483 484 const CConfigurableElement *pConfigurableElement = *it; 485 486 strResult += pConfigurableElement->getPath() + "\n"; 487 } 488 } 489 490 bool CConfigurableElement::isRogue() const 491 { 492 // Check not belonging to any domin from current level and towards ascendents 493 if (getBelongingDomainCount() != 0) { 494 495 return false; 496 } 497 498 // Get a list of elements (current + descendants) with no domains associated 499 std::list<const CConfigurableElement *> rogueElementList; 500 501 CConfigurableElementAggregator agregator(rogueElementList, 502 &CConfigurableElement::hasNoDomainAssociated); 503 504 agregator.aggegate(this); 505 506 // Check only one element found which ought to be current one 507 return (rogueElementList.size() == 1) && (rogueElementList.front() == this); 508 } 509 510 // Footprint as string 511 std::string CConfigurableElement::getFootprintAsString() const 512 { 513 // Get size as string 514 return std::to_string(getFootPrint()) + " byte(s)"; 515 } 516 517 // Matching check for no domain association 518 bool CConfigurableElement::hasNoDomainAssociated() const 519 { 520 return _configurableDomainList.empty(); 521 } 522 523 // Matching check for no valid associated domains 524 bool CConfigurableElement::hasNoValidDomainAssociated() const 525 { 526 if (_configurableDomainList.empty()) { 527 528 // No domains associated 529 return true; 530 } 531 532 ConfigurableDomainListConstIterator it; 533 534 // Browse all configurable domains for validity checking 535 for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { 536 537 const CConfigurableDomain *pConfigurableDomain = *it; 538 539 if (pConfigurableDomain->isApplicableConfigurationValid(this)) { 540 541 return false; 542 } 543 } 544 545 return true; 546 } 547 548 // Owning domains 549 void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const 550 { 551 // Fill list 552 listDomains(_configurableDomainList, strResult, bVertical); 553 } 554 555 size_t CConfigurableElement::getBelongingDomainCount() const 556 { 557 // Get belonging domain list 558 std::list<const CConfigurableDomain *> configurableDomainList; 559 560 getBelongingDomains(configurableDomainList); 561 562 return configurableDomainList.size(); 563 } 564 565 void CConfigurableElement::listDomains( 566 const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult, 567 bool bVertical) const 568 { 569 // Fill list 570 ConfigurableDomainListConstIterator it; 571 bool bFirst = true; 572 573 // Browse all configurable domains for comparison 574 for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) { 575 576 const CConfigurableDomain *pConfigurableDomain = *it; 577 578 if (!bVertical && !bFirst) { 579 580 strResult += ", "; 581 } 582 583 strResult += pConfigurableDomain->getName(); 584 585 if (bVertical) { 586 587 strResult += "\n"; 588 } else { 589 590 bFirst = false; 591 } 592 } 593 } 594 595 bool CConfigurableElement::containsConfigurableDomain( 596 const CConfigurableDomain *pConfigurableDomain) const 597 { 598 ConfigurableDomainListConstIterator it; 599 600 // Browse all configurable domains for comparison 601 for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) { 602 603 if (pConfigurableDomain == *it) { 604 605 return true; 606 } 607 } 608 return false; 609 } 610 611 // Belonging domain ascending search 612 bool CConfigurableElement::belongsToDomainAscending( 613 const CConfigurableDomain *pConfigurableDomain) const 614 { 615 // Check parent 616 const CElement *pParent = getParent(); 617 618 if (isOfConfigurableElementType(pParent)) { 619 620 return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain); 621 } 622 return false; 623 } 624 625 // Belonging subsystem 626 const CSubsystem *CConfigurableElement::getBelongingSubsystem() const 627 { 628 const CElement *pParent = getParent(); 629 630 // Stop at system class 631 if (!pParent->getParent()) { 632 633 return NULL; 634 } 635 636 return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem(); 637 } 638 639 // Check element is a parameter 640 bool CConfigurableElement::isParameter() const 641 { 642 return false; 643 } 644 645 // Check parent is still of current type (by structure knowledge) 646 bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const 647 { 648 assert(pParent); 649 650 // Up to system class 651 return !!pParent->getParent(); 652 } 653