380 lines
12 KiB
C++
380 lines
12 KiB
C++
/**
|
|
* @file
|
|
*
|
|
* @copyright
|
|
* @verbatim
|
|
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla
|
|
Public License, v. 2.0. If a copy of the MPL was not distributed
|
|
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
If it is not possible or desirable to put the notice in a particular file, then
|
|
You may include the notice in a location (such as a LICENSE file in a
|
|
relevant directory) where a recipient would be likely to look for such a notice.
|
|
|
|
You may add additional accurate notices of copyright ownership.
|
|
@endverbatim
|
|
*/
|
|
|
|
#include "target.h"
|
|
|
|
#include <memory> //std::unique_ptr<>
|
|
#include "a_util/result/error_def.h"
|
|
#include "legacy_error_macros.h"
|
|
|
|
#include "codec/access_element.h"
|
|
|
|
#include "mapping/configuration/map_configuration.h"
|
|
|
|
namespace mapping
|
|
{
|
|
namespace rt
|
|
{
|
|
//define all needed error types and values locally
|
|
_MAKE_RESULT(-3, ERR_UNEXPECTED)
|
|
_MAKE_RESULT(-4, ERR_POINTER)
|
|
_MAKE_RESULT(-12, ERR_MEMORY)
|
|
}
|
|
}
|
|
|
|
using namespace mapping;
|
|
using namespace mapping::rt;
|
|
|
|
Target::Target(IMappingEnvironment& oEnv) :
|
|
_counter(0), _env(oEnv)
|
|
{
|
|
}
|
|
|
|
Target::~Target()
|
|
{
|
|
for (TargetElementList::iterator it = _target_elements.begin();
|
|
it != _target_elements.end(); ++it)
|
|
{
|
|
delete *it;
|
|
}
|
|
_target_elements.clear();
|
|
_simulation_time_elements.clear();
|
|
}
|
|
|
|
a_util::result::Result Target::create(const oo::MapConfiguration& oMapConfig,
|
|
const oo::MapTarget& oMapTarget, const std::string& strTargetDescription,
|
|
SourceMap& oSources)
|
|
{
|
|
_name = oMapTarget.getName();
|
|
_type = oMapTarget.getType();
|
|
ddl::CodecFactory oFactory(_type.c_str(), strTargetDescription.c_str());
|
|
RETURN_IF_FAILED(oFactory.isValid());
|
|
|
|
// Alloc and zero memory
|
|
_buffer.resize(oFactory.getStaticBufferSize(), 0);
|
|
|
|
// Begin here, end when target is destroyed or after reset
|
|
_codec.reset(new ddl::StaticCodec(oFactory.makeStaticCodecFor(&_buffer[0], _buffer.size())));
|
|
|
|
// Get structure from DDL
|
|
const ddl::DDLDescription* pDescription = oMapConfig.getDescription();
|
|
if (!pDescription) { return ERR_POINTER; }
|
|
const ddl::DDLComplex* pStruct = pDescription->getStructByName(_type);
|
|
if (!pStruct) { return ERR_POINTER; }
|
|
|
|
// Create element for each assignment in mapping configuration
|
|
const oo::MapAssignmentList& oAssignmentList = oMapTarget.getAssignmentList();
|
|
for(oo::MapAssignmentList::const_iterator itAssignment = oAssignmentList.begin();
|
|
itAssignment != oAssignmentList.end(); ++itAssignment)
|
|
{
|
|
const ddl::DDLElement* pElem = NULL;
|
|
bool bIsArrayElement = false;
|
|
RETURN_IF_FAILED(DDLHelper::LookupElement(*pStruct, itAssignment->getTo(),
|
|
pElem, bIsArrayElement));
|
|
|
|
unsigned int szElement = pElem->getArraysize();
|
|
if(bIsArrayElement)
|
|
{
|
|
szElement = 1;
|
|
}
|
|
|
|
std::string strPath = itAssignment->getTo();
|
|
if (szElement > 1)
|
|
{
|
|
strPath.append("[0]");
|
|
}
|
|
|
|
ddl::DDLComplex* pComplex = dynamic_cast<ddl::DDLComplex*>(pElem->getTypeObject());
|
|
if (pComplex)
|
|
{
|
|
// No StructElement is created for the actual struct, only for its elements. Therefore, if
|
|
// the assignment is a struct, we need to amend the path by the first element of the struct
|
|
if (pComplex->getElements().empty()) return ERR_UNEXPECTED;
|
|
strPath.push_back('.');
|
|
strPath.append(pComplex->getElements()[0]->getName());
|
|
}
|
|
|
|
size_t nIdx = 0;
|
|
RETURN_IF_FAILED(ddl::access_element::find_index(*_codec, strPath, nIdx));
|
|
void* pTargetElementPtr = _codec->getElementAddress(nIdx);
|
|
|
|
// Create target element
|
|
std::unique_ptr<TargetElement> pElement(new TargetElement(this));
|
|
RETURN_IF_FAILED(pElement->create(pTargetElementPtr, pElem->getTypeObject(),
|
|
szElement, itAssignment->getTo()));
|
|
|
|
// If a constant is given, there can be no transformation
|
|
if(!itAssignment->getConstant().empty())
|
|
{
|
|
_constant_elements.push_back(make_pair(itAssignment->getConstant(), pElement.get()));
|
|
|
|
}
|
|
else if(!itAssignment->getFunction().empty())
|
|
{
|
|
if(itAssignment->getFunction() == "simulation_time")
|
|
{
|
|
_simulation_time_elements.push_back(pElement.get());
|
|
}
|
|
else if(itAssignment->getFunction() == "trigger_counter")
|
|
{
|
|
uint64_t nMod = 0;
|
|
if (!itAssignment->getModulo().empty())
|
|
{
|
|
nMod = a_util::strings::toUInt64(itAssignment->getModulo());
|
|
}
|
|
_counter_elements.push_back(std::make_pair(nMod, pElement.get()));
|
|
}
|
|
else if(itAssignment->getFunction() == "received")
|
|
{
|
|
// Add assignments to source
|
|
SourceMap::iterator itSource = oSources.find(itAssignment->getSource());
|
|
if (itSource == oSources.end())
|
|
{
|
|
return ERR_UNEXPECTED;
|
|
}
|
|
|
|
RETURN_IF_FAILED(itSource->second->addAssignment(oMapConfig, "received()", pElement.get()));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Add Transformation for Mapping configuration
|
|
const std::string& strTransformation = itAssignment->getTransformation();
|
|
if(!strTransformation.empty())
|
|
{
|
|
RETURN_IF_FAILED(pElement->setTransformation(
|
|
oMapConfig.getTransformation(strTransformation)));
|
|
}
|
|
|
|
// Add assignments to source
|
|
SourceMap::iterator itSource = oSources.find(itAssignment->getSource());
|
|
if (itSource == oSources.end())
|
|
{
|
|
return ERR_UNEXPECTED;
|
|
}
|
|
|
|
// getFrom() is empty when the source itself is referenced
|
|
RETURN_IF_FAILED(itSource->second->addAssignment(oMapConfig, itAssignment->getFrom(), pElement.get()));
|
|
}
|
|
|
|
_target_elements.push_back(pElement.release());
|
|
}
|
|
|
|
// initialize memory
|
|
RETURN_IF_FAILED(reset(oMapConfig));
|
|
|
|
return a_util::result::SUCCESS;
|
|
}
|
|
|
|
a_util::result::Result Target::reset(const oo::MapConfiguration& oMapConfig)
|
|
{
|
|
a_util::result::Result nResult = a_util::result::SUCCESS;
|
|
// Reset Counter
|
|
_counter = 0;
|
|
|
|
// Set default values from DDL
|
|
const ddl::DDLDescription* pDescription = oMapConfig.getDescription();
|
|
if (!pDescription) { return ERR_POINTER; }
|
|
const ddl::DDLComplex* pStruct = pDescription->getStructByName(_type);
|
|
if (!pStruct) { return ERR_POINTER; }
|
|
|
|
// Set default values from DDL in a newly created data sample
|
|
for (size_t nIdx = 0; nIdx < _codec->getElementCount(); ++nIdx)
|
|
{
|
|
const ddl::StructElement* pElement = NULL;
|
|
if (isFailed(_codec->getElement(nIdx, pElement)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const ddl::DDLElement* pElem = NULL;
|
|
bool bIsArrayElement = false;
|
|
a_util::result::Result nCurrentResult = DDLHelper::LookupElement(*pStruct,
|
|
pElement->name, pElem, bIsArrayElement);
|
|
|
|
unsigned int nLastElementIndex = 1;
|
|
std::string strDefaultValue;
|
|
if (isOk(nCurrentResult))
|
|
{
|
|
nLastElementIndex = pElem->getArraysize();
|
|
// Element Description was found ... check for a default value
|
|
if (pElem->isDefaultValid())
|
|
{
|
|
strDefaultValue = pElem->getDefaultValue();
|
|
}
|
|
}
|
|
|
|
// Set error if no error happend so far
|
|
if (isOk(nResult))
|
|
{
|
|
nResult = nCurrentResult;
|
|
}
|
|
|
|
if (strDefaultValue.empty())
|
|
{
|
|
// No default detected, just reset this entry
|
|
ddl::access_element::reset(*_codec, pElement->name);
|
|
}
|
|
else
|
|
{
|
|
a_util::variant::Variant var;
|
|
switch (pElement->type)
|
|
{
|
|
case a_util::variant::VT_Bool:
|
|
var.reset(a_util::strings::toBool(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Int8:
|
|
var.reset(a_util::strings::toInt8(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_UInt8:
|
|
var.reset(a_util::strings::toUInt8(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Int16:
|
|
var.reset(a_util::strings::toInt16(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_UInt16:
|
|
var.reset(a_util::strings::toUInt16(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Int32:
|
|
var.reset(a_util::strings::toInt32(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_UInt32:
|
|
var.reset(a_util::strings::toUInt32(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Int64:
|
|
var.reset(a_util::strings::toInt64(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_UInt64:
|
|
var.reset(a_util::strings::toUInt64(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Float:
|
|
var.reset(a_util::strings::toFloat(strDefaultValue));
|
|
break;
|
|
case a_util::variant::VT_Double:
|
|
var.reset(a_util::strings::toDouble(strDefaultValue));
|
|
break;
|
|
default:
|
|
ddl::access_element::reset(*_codec, pElement->name);
|
|
break;
|
|
}
|
|
|
|
if (!var.isEmpty())
|
|
{
|
|
nCurrentResult = _codec->setElementValue(nIdx, var);
|
|
}
|
|
|
|
// Set error if no error happend so far
|
|
if (isOk(nResult))
|
|
{
|
|
nResult = nCurrentResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set constant elements
|
|
if (isOk(nResult))
|
|
{
|
|
for(Constants::iterator it = _constant_elements.begin(); it != _constant_elements.end(); it++)
|
|
{
|
|
nResult = it->second->setDefaultValue(it->first);
|
|
}
|
|
}
|
|
return nResult;
|
|
}
|
|
|
|
const std::string& Target::getName() const
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
const std::string& Target::getType() const
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
const TargetElementList& Target::getElementList() const
|
|
{
|
|
return _target_elements;
|
|
}
|
|
|
|
size_t Target::getSize() const
|
|
{
|
|
return _buffer.size();
|
|
}
|
|
|
|
a_util::result::Result Target::updateAccessFunctionValues()
|
|
{
|
|
// set simulation time for simulation_time assignments
|
|
timestamp_t tmTime = _env.getTime();
|
|
for(std::vector<TargetElement*>::const_iterator it = _simulation_time_elements.begin();
|
|
it != _simulation_time_elements.end(); it++)
|
|
{
|
|
(*it)->setValue(&tmTime, e_int64, sizeof(timestamp_t));
|
|
}
|
|
|
|
return a_util::result::SUCCESS;
|
|
}
|
|
|
|
a_util::result::Result Target::updateTriggerFunctionValues()
|
|
{
|
|
// increment counter
|
|
_counter++;
|
|
|
|
// write counter into trigger_counter assignments
|
|
for(TriggerCounters::const_iterator it = _counter_elements.begin(); it != _counter_elements.end(); it++)
|
|
{
|
|
uint64_t nValue = _counter;
|
|
if (it->first != 0)
|
|
{
|
|
nValue %= it->first;
|
|
}
|
|
it->second->setValue(&nValue, e_uint64, sizeof(nValue));
|
|
}
|
|
|
|
return a_util::result::SUCCESS;
|
|
}
|
|
|
|
a_util::result::Result Target::getCurrentBuffer(void* pTargetBuffer, size_t szTargetBuffer)
|
|
{
|
|
if(szTargetBuffer < _buffer.size())
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
|
|
updateAccessFunctionValues();
|
|
|
|
aquireReadLock();
|
|
a_util::memory::copy(pTargetBuffer, szTargetBuffer, &_buffer[0], _buffer.size());
|
|
releaseReadLock();
|
|
return a_util::result::SUCCESS;
|
|
}
|
|
|
|
a_util::result::Result Target::getBufferRef(const void*& pBuffer, size_t& szTargetBuffer)
|
|
{
|
|
updateAccessFunctionValues();
|
|
|
|
// synchronization is done by the caller!
|
|
pBuffer = &_buffer[0];
|
|
szTargetBuffer = _buffer.size();
|
|
|
|
return a_util::result::SUCCESS;
|
|
}
|
|
|