/** * @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 //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(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 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::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; }