You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
16 KiB
497 lines
16 KiB
/*
|
|
* 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 "Subsystem.h"
|
|
#include "ComponentLibrary.h"
|
|
#include "InstanceDefinition.h"
|
|
#include "XmlParameterSerializingContext.h"
|
|
#include "ParameterAccessContext.h"
|
|
#include "ConfigurationAccessContext.h"
|
|
#include "SubsystemObjectCreator.h"
|
|
#include "MappingData.h"
|
|
#include <assert.h>
|
|
#include <sstream>
|
|
|
|
#define base CConfigurableElement
|
|
|
|
using std::string;
|
|
using std::list;
|
|
|
|
CSubsystem::CSubsystem(const string &strName, core::log::Logger &logger)
|
|
: base(strName), _pComponentLibrary(new CComponentLibrary),
|
|
_pInstanceDefinition(new CInstanceDefinition), _logger(logger)
|
|
{
|
|
// Note: A subsystem contains instance components
|
|
// InstanceDefintion and ComponentLibrary objects are then not chosen to be children
|
|
// They'll be delt with locally
|
|
}
|
|
|
|
CSubsystem::~CSubsystem()
|
|
{
|
|
// FIXME use unique_ptr, would make this method empty
|
|
|
|
for (auto *subsystemObject : _subsystemObjectList) {
|
|
|
|
delete subsystemObject;
|
|
}
|
|
|
|
// Remove susbsystem creators
|
|
for (auto *subsystemObjectCreator : _subsystemObjectCreatorArray) {
|
|
|
|
delete subsystemObjectCreator;
|
|
}
|
|
|
|
// Order matters!
|
|
delete _pInstanceDefinition;
|
|
delete _pComponentLibrary;
|
|
|
|
delete _pMappingData;
|
|
}
|
|
|
|
string CSubsystem::getKind() const
|
|
{
|
|
return "Subsystem";
|
|
}
|
|
|
|
// Susbsystem sanity
|
|
bool CSubsystem::isAlive() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Resynchronization after subsystem restart needed
|
|
bool CSubsystem::needResync(bool /*bClear*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool CSubsystem::structureFromXml(const CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext)
|
|
{
|
|
// Subsystem class does not rely on generic fromXml algorithm of Element class.
|
|
// So, setting here the description if found as XML attribute.
|
|
string description;
|
|
xmlElement.getAttribute(gDescriptionPropertyName, description);
|
|
setDescription(description);
|
|
|
|
// Context
|
|
CXmlParameterSerializingContext ¶meterBuildContext =
|
|
static_cast<CXmlParameterSerializingContext &>(serializingContext);
|
|
|
|
// Install temporary component library for further component creation
|
|
parameterBuildContext.setComponentLibrary(_pComponentLibrary);
|
|
|
|
CXmlElement childElement;
|
|
|
|
// Manage mapping attribute
|
|
string rawMapping;
|
|
xmlElement.getAttribute("Mapping", rawMapping);
|
|
if (!rawMapping.empty()) {
|
|
|
|
std::string error;
|
|
_pMappingData = new CMappingData;
|
|
if (!_pMappingData->init(rawMapping, error)) {
|
|
|
|
serializingContext.setError("Invalid Mapping data from XML element '" +
|
|
xmlElement.getPath() + "': " + error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// XML populate ComponentLibrary
|
|
xmlElement.getChildElement("ComponentLibrary", childElement);
|
|
|
|
if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// XML populate InstanceDefintion
|
|
xmlElement.getChildElement("InstanceDefintion", childElement);
|
|
if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Create components
|
|
_pInstanceDefinition->createInstances(this);
|
|
|
|
// Execute mapping to create subsystem mapping entities
|
|
string strError;
|
|
if (!mapSubsystemElements(strError)) {
|
|
|
|
serializingContext.setError(strError);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CSubsystem::mapSubsystemElements(string &strError)
|
|
{
|
|
// Default mapping context
|
|
CMappingContext context(_contextMappingKeyArray.size());
|
|
// Add Subsystem-level mapping data, which will be propagated to all children
|
|
handleMappingContext(this, context, strError);
|
|
|
|
_contextStack.push(context);
|
|
|
|
// Map all instantiated subelements in subsystem
|
|
size_t nbChildren = getNbChildren();
|
|
|
|
for (size_t child = 0; child < nbChildren; child++) {
|
|
|
|
CInstanceConfigurableElement *pInstanceConfigurableChildElement =
|
|
static_cast<CInstanceConfigurableElement *>(getChild(child));
|
|
|
|
if (!pInstanceConfigurableChildElement->map(*this, strError)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Formats the mapping of the ConfigurableElements
|
|
string CSubsystem::formatMappingDataList(
|
|
const list<const CConfigurableElement *> &configurableElementPath) const
|
|
{
|
|
// The list is parsed in reverse order because it has been filled from the leaf to the trunk
|
|
// of the tree. When formatting the mapping, we want to start from the subsystem level
|
|
std::list<string> mappings;
|
|
list<const CConfigurableElement *>::const_reverse_iterator it;
|
|
for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
|
|
|
|
auto maybeMapping = (*it)->getFormattedMapping();
|
|
if (not maybeMapping.empty()) {
|
|
mappings.push_back(maybeMapping);
|
|
}
|
|
}
|
|
|
|
return utility::asString(mappings, ", ");
|
|
}
|
|
|
|
// Find the CSubystemObject containing a specific CInstanceConfigurableElement
|
|
const CSubsystemObject *CSubsystem::findSubsystemObjectFromConfigurableElement(
|
|
const CInstanceConfigurableElement *pInstanceConfigurableElement) const
|
|
{
|
|
|
|
list<CSubsystemObject *>::const_iterator it;
|
|
for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
|
|
|
|
// Check if one of the SubsystemObjects is associated with a ConfigurableElement
|
|
// corresponding to the expected one
|
|
const CSubsystemObject *pSubsystemObject = *it;
|
|
|
|
if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
|
|
|
|
return pSubsystemObject;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void CSubsystem::findSubsystemLevelMappingKeyValue(
|
|
const CInstanceConfigurableElement *pInstanceConfigurableElement, string &strMappingKey,
|
|
string &strMappingValue) const
|
|
{
|
|
// Find creator to get key name
|
|
std::vector<CSubsystemObjectCreator *>::const_iterator it;
|
|
for (it = _subsystemObjectCreatorArray.begin(); it != _subsystemObjectCreatorArray.end();
|
|
++it) {
|
|
|
|
const CSubsystemObjectCreator *pSubsystemObjectCreator = *it;
|
|
|
|
strMappingKey = pSubsystemObjectCreator->getMappingKey();
|
|
|
|
// Check if the ObjectCreator MappingKey corresponds to the element mapping data
|
|
const string *pStrValue;
|
|
if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
|
|
|
|
strMappingValue = *pStrValue;
|
|
return;
|
|
}
|
|
}
|
|
assert(0);
|
|
}
|
|
|
|
// Formats the mapping data as a comma separated list of key value pairs
|
|
string CSubsystem::getFormattedSubsystemMappingData(
|
|
const CInstanceConfigurableElement *pInstanceConfigurableElement) const
|
|
{
|
|
// Find the SubsystemObject related to pInstanceConfigurableElement
|
|
const CSubsystemObject *pSubsystemObject =
|
|
findSubsystemObjectFromConfigurableElement(pInstanceConfigurableElement);
|
|
|
|
// Exit if node does not correspond to a SubsystemObject
|
|
if (pSubsystemObject == nullptr) {
|
|
|
|
return "";
|
|
}
|
|
|
|
// Find SubsystemCreator mapping key
|
|
string strMappingKey;
|
|
string strMappingValue; // mapping value where amends are not replaced by their value
|
|
findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
|
|
|
|
// Find SubSystemObject mapping value (with amends replaced by their value)
|
|
return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
|
|
}
|
|
|
|
string CSubsystem::getMapping(list<const CConfigurableElement *> &configurableElementPath) const
|
|
{
|
|
if (configurableElementPath.empty()) {
|
|
|
|
return "";
|
|
}
|
|
|
|
// Get the first element, which is the element containing the amended mapping
|
|
const CInstanceConfigurableElement *pInstanceConfigurableElement =
|
|
static_cast<const CInstanceConfigurableElement *>(configurableElementPath.front());
|
|
|
|
// Format context mapping data
|
|
string strValue = formatMappingDataList(configurableElementPath);
|
|
|
|
// Print the mapping of the first node, which corresponds to a SubsystemObject
|
|
auto subsystemObjectAmendedMapping =
|
|
getFormattedSubsystemMappingData(pInstanceConfigurableElement);
|
|
if (not subsystemObjectAmendedMapping.empty()) {
|
|
strValue += ", " + subsystemObjectAmendedMapping;
|
|
}
|
|
|
|
return strValue;
|
|
}
|
|
|
|
// Used for simulation and virtual subsystems
|
|
void CSubsystem::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const
|
|
{
|
|
base::setDefaultValues(parameterAccessContext);
|
|
}
|
|
|
|
// Belonging subsystem
|
|
const CSubsystem *CSubsystem::getBelongingSubsystem() const
|
|
{
|
|
return this;
|
|
}
|
|
|
|
// Subsystem context mapping keys publication
|
|
void CSubsystem::addContextMappingKey(const string &strMappingKey)
|
|
{
|
|
_contextMappingKeyArray.push_back(strMappingKey);
|
|
}
|
|
|
|
// Subsystem object creator publication (strong reference)
|
|
void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator *pSubsystemObjectCreator)
|
|
{
|
|
_subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
|
|
}
|
|
|
|
// Generic error handling from derived subsystem classes
|
|
string CSubsystem::getMappingError(const string &strKey, const string &strMessage,
|
|
const CConfigurableElement *pConfigurableElement) const
|
|
{
|
|
return getName() + " " + getKind() + " " + "mapping:\n" + strKey + " " + "error: \"" +
|
|
strMessage + "\" " + "for element " + pConfigurableElement->getPath();
|
|
}
|
|
|
|
bool CSubsystem::getMappingData(const std::string &strKey, const std::string *&pStrValue) const
|
|
{
|
|
if (_pMappingData) {
|
|
|
|
return _pMappingData->getValue(strKey, pStrValue);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns the formatted mapping
|
|
std::string CSubsystem::getFormattedMapping() const
|
|
{
|
|
if (!_pMappingData) {
|
|
return "";
|
|
}
|
|
return _pMappingData->asString();
|
|
}
|
|
|
|
// Mapping generic context handling
|
|
bool CSubsystem::handleMappingContext(const CConfigurableElement *pConfigurableElement,
|
|
CMappingContext &context, string &strError) const
|
|
{
|
|
// Feed context with found mapping data
|
|
for (size_t item = 0; item < _contextMappingKeyArray.size(); item++) {
|
|
|
|
const string &strKey = _contextMappingKeyArray[item];
|
|
const string *pStrValue;
|
|
|
|
if (pConfigurableElement->getMappingData(strKey, pStrValue)) {
|
|
// Assign item to context
|
|
if (!context.setItem(item, &strKey, pStrValue)) {
|
|
|
|
strError = getMappingError(strKey, "Already set", pConfigurableElement);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Subsystem object creation handling
|
|
bool CSubsystem::handleSubsystemObjectCreation(
|
|
CInstanceConfigurableElement *pInstanceConfigurableElement, CMappingContext &context,
|
|
bool &bHasCreatedSubsystemObject, string &strError)
|
|
{
|
|
bHasCreatedSubsystemObject = false;
|
|
|
|
for (const auto *pSubsystemObjectCreator : _subsystemObjectCreatorArray) {
|
|
|
|
// Mapping key
|
|
string strKey = pSubsystemObjectCreator->getMappingKey();
|
|
// Object id
|
|
const string *pStrValue;
|
|
|
|
if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
|
|
|
|
// First check context consistency
|
|
// (required ancestors must have been set prior to object creation)
|
|
uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
|
|
|
|
for (size_t uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size();
|
|
uiAncestorKey++) {
|
|
|
|
if (!((1 << uiAncestorKey) & uiAncestorMask)) {
|
|
// Ancestor not required
|
|
continue;
|
|
}
|
|
// Check ancestor was provided
|
|
if (!context.iSet(uiAncestorKey)) {
|
|
|
|
strError =
|
|
getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] + " not set",
|
|
pInstanceConfigurableElement);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Then check configurable element size is correct
|
|
if (pInstanceConfigurableElement->getFootPrint() >
|
|
pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
|
|
|
|
string strSizeError =
|
|
"Size should not exceed " +
|
|
std::to_string(pSubsystemObjectCreator->getMaxConfigurableElementSize());
|
|
|
|
strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Do create object and keep its track
|
|
_subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
|
|
*pStrValue, pInstanceConfigurableElement, context, _logger));
|
|
|
|
// Indicate subsytem creation to caller
|
|
bHasCreatedSubsystemObject = true;
|
|
|
|
// The subsystem Object has been instantiated, no need to continue looking for an
|
|
// instantiation mapping
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// From IMapper
|
|
// Handle a configurable element mapping
|
|
bool CSubsystem::mapBegin(CInstanceConfigurableElement *pInstanceConfigurableElement,
|
|
bool &bKeepDiving, string &strError)
|
|
{
|
|
// Get current context
|
|
CMappingContext context = _contextStack.top();
|
|
|
|
// Add mapping in context
|
|
if (!handleMappingContext(pInstanceConfigurableElement, context, strError)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Push context
|
|
_contextStack.push(context);
|
|
|
|
// Assume diving by default
|
|
bKeepDiving = true;
|
|
|
|
// Deal with ambiguous usage of parameter blocks
|
|
bool bShouldCreateSubsystemObject = true;
|
|
|
|
switch (pInstanceConfigurableElement->getType()) {
|
|
|
|
case CInstanceConfigurableElement::EComponent:
|
|
case CInstanceConfigurableElement::EParameterBlock:
|
|
// Subsystem object creation is optional in parameter blocks
|
|
bShouldCreateSubsystemObject = false;
|
|
// No break
|
|
case CInstanceConfigurableElement::EBitParameterBlock:
|
|
case CInstanceConfigurableElement::EParameter:
|
|
case CInstanceConfigurableElement::EStringParameter:
|
|
|
|
bool bHasCreatedSubsystemObject;
|
|
|
|
if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
|
|
bHasCreatedSubsystemObject, strError)) {
|
|
|
|
return false;
|
|
}
|
|
// Check for creation error
|
|
if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
|
|
|
|
strError = getMappingError("Not found", "Subsystem object mapping key is missing",
|
|
pInstanceConfigurableElement);
|
|
return false;
|
|
}
|
|
// Not created and no error, keep diving
|
|
bKeepDiving = !bHasCreatedSubsystemObject;
|
|
|
|
return true;
|
|
|
|
default:
|
|
assert(0);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CSubsystem::mapEnd()
|
|
{
|
|
// Unstack context
|
|
_contextStack.pop();
|
|
}
|