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
CConfigurableElement(const std::string & strName)44 CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName)
45 {
46 }
47
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)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
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const65 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
serializeXmlSettings(CXmlElement & xmlConfigurationSettingsElementContent,CConfigurationAccessContext & configurationAccessContext) const80 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
createAreaConfiguration(const CSyncerSet * pSyncerSet) const196 CAreaConfiguration *CConfigurableElement::createAreaConfiguration(
197 const CSyncerSet *pSyncerSet) const
198 {
199 return new CAreaConfiguration(this, pSyncerSet);
200 }
201
202 // Parameter access
accessValue(CPathNavigator & pathNavigator,std::string & strValue,bool bSet,CParameterAccessContext & parameterAccessContext) const203 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
getSettingsAsBytes(std::vector<uint8_t> & bytes,CParameterAccessContext & parameterAccessContext) const232 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
setSettingsAsBytes(const std::vector<uint8_t> & bytes,CParameterAccessContext & parameterAccessContext) const241 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
getConfigurableElementContext() const278 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
setDefaultValues(CParameterAccessContext & parameterAccessContext) const294 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
showProperties(std::string & strResult) const309 void CConfigurableElement::showProperties(std::string &strResult) const
310 {
311 base::showProperties(strResult);
312
313 strResult += "Total size: " + getFootprintAsString() + "\n";
314 }
315
logValue(utility::ErrorContext & context) const316 std::string CConfigurableElement::logValue(utility::ErrorContext &context) const
317 {
318 return logValue(static_cast<CParameterAccessContext &>(context));
319 }
320
logValue(CParameterAccessContext &) const321 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
setOffset(size_t 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
getOffset() const349 size_t CConfigurableElement::getOffset() const
350 {
351 return _offset;
352 }
353
354 // Memory
getFootPrint() const355 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
getSyncer() const372 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 nullptr;
382 }
383
384 // Syncer set (me, ascendant or descendant ones)
fillSyncerSet(CSyncerSet & syncerSet) const385 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)
fillSyncerSetFromDescendant(CSyncerSet & syncerSet) const403 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
addAttachedConfigurableDomain(const CConfigurableDomain * pConfigurableDomain)418 void CConfigurableElement::addAttachedConfigurableDomain(
419 const CConfigurableDomain *pConfigurableDomain)
420 {
421 _configurableDomainList.push_back(pConfigurableDomain);
422 }
423
removeAttachedConfigurableDomain(const CConfigurableDomain * pConfigurableDomain)424 void CConfigurableElement::removeAttachedConfigurableDomain(
425 const CConfigurableDomain *pConfigurableDomain)
426 {
427 _configurableDomainList.remove(pConfigurableDomain);
428 }
429
430 // Belonging domain
belongsTo(const CConfigurableDomain * pConfigurableDomain) const431 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
getBelongingDomains(std::list<const CConfigurableDomain * > & configurableDomainList) const441 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
listBelongingDomains(std::string & strResult,bool bVertical) const457 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
listRogueElements(std::string & strResult) const469 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
isRogue() const490 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
getFootprintAsString() const511 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
hasNoDomainAssociated() const518 bool CConfigurableElement::hasNoDomainAssociated() const
519 {
520 return _configurableDomainList.empty();
521 }
522
523 // Matching check for no valid associated domains
hasNoValidDomainAssociated() const524 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
listAssociatedDomains(std::string & strResult,bool bVertical) const549 void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const
550 {
551 // Fill list
552 listDomains(_configurableDomainList, strResult, bVertical);
553 }
554
getBelongingDomainCount() const555 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
listDomains(const std::list<const CConfigurableDomain * > & configurableDomainList,std::string & strResult,bool bVertical) const565 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
containsConfigurableDomain(const CConfigurableDomain * pConfigurableDomain) const595 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
belongsToDomainAscending(const CConfigurableDomain * pConfigurableDomain) const612 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
getBelongingSubsystem() const626 const CSubsystem *CConfigurableElement::getBelongingSubsystem() const
627 {
628 const CElement *pParent = getParent();
629
630 // Stop at system class
631 if (!pParent->getParent()) {
632
633 return nullptr;
634 }
635
636 return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem();
637 }
638
639 // Check element is a parameter
isParameter() const640 bool CConfigurableElement::isParameter() const
641 {
642 return false;
643 }
644
645 // Check parent is still of current type (by structure knowledge)
isOfConfigurableElementType(const CElement * pParent) const646 bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const
647 {
648 assert(pParent);
649
650 // Up to system class
651 return !!pParent->getParent();
652 }
653