blob: 81853a3cb8b63fee6c3962537183e394bc016ad6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 - 2015 Profactor GmbH, ACIN, fortiss GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Thomas Strasser, Alois Zoitl, Gunnar Grabmaier, Gerhard Ebenhofer,
* Martin Melik Merkumians, Ingo Hegny
* - initial implementation and rework communication infrastructure
*******************************************************************************/
#include <string.h>
#include "cfb.h"
#include "adapter.h"
#include "resource.h"
#include "utils/criticalregion.h"
#include "if2indco.h"
CCompositeFB::CCompositeFB(CResource *pa_poSrcRes, const SFBInterfaceSpec *pa_pstInterfaceSpec,
const CStringDictionary::TStringId pa_nInstanceNameId, const SCFB_FBNData * const pa_cpoFBNData,
TForteByte *pa_acFBConnData, TForteByte *pa_acFBVarsData) :
CFunctionBlock(pa_poSrcRes, pa_pstInterfaceSpec, pa_nInstanceNameId, pa_acFBConnData, pa_acFBVarsData),
mIf2InDConns(0),
m_apoIn2IfDConns(0),
cm_cpoFBNData(pa_cpoFBNData),
m_apoEventConnections(0),
m_apoDataConnections(0),
mInterface2InternalEventCons(0){
createInternalFBs();
createEventConnections();
createDataConnections();
setParams();
//remove adapter-references for CFB
for(TForteUInt8 i = 0; i < pa_pstInterfaceSpec->m_nNumAdapters; i++){
if(0 != m_apoAdapters){
static_cast<CAdapter*>(m_apoAdapters[i])->setParentFB(0, 0);
}
}
}
CCompositeFB::~CCompositeFB(){
if(cm_cpoFBNData->m_nNumFBs){
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFBs; ++i){
delete m_apoInternalFBs[i];
}
delete[] m_apoInternalFBs;
}
//only delete the interface to internal event connections all other connections are managed by their source's FBs
//this has to be done even if we don't have any event connection to ensure correct behavior
for(unsigned int i = 0; i < m_pstInterfaceSpec->m_nNumEIs; ++i){
delete mInterface2InternalEventCons[i];
}
delete[] mInterface2InternalEventCons;
if(cm_cpoFBNData->m_nNumEventConnections){
delete[] m_apoEventConnections;
}
if(cm_cpoFBNData->m_nNumDataConnections){
if(0 != m_apoDataConnections){
delete[] m_apoDataConnections;
}
if(0 != mIf2InDConns){
delete[] mIf2InDConns;
}
if(0 != m_apoIn2IfDConns){
delete[] m_apoIn2IfDConns;
}
}
}
bool CCompositeFB::connectDI(TPortId paDIPortId, CDataConnection *paDataCon){
bool retVal = false;
if(cgInternal2InterfaceMarker & paDIPortId){
paDIPortId = static_cast<TPortId>(paDIPortId & cgInternal2InterfaceRemovalMask);
if(paDIPortId < m_pstInterfaceSpec->m_nNumDOs){
m_apoIn2IfDConns[paDIPortId] = paDataCon;
retVal = true;
}
}
else if(paDIPortId < m_pstInterfaceSpec->m_nNumDIs){
bool needsCloning = (getDI(paDIPortId)->getDataTypeID() == CIEC_ANY::e_ANY);
retVal = CFunctionBlock::connectDI(paDIPortId, paDataCon);
if((true == retVal) && (true == needsCloning) && (0 != paDataCon)
&& (0 != paDataCon->getValue())){
//if internal connected update the connections data type and maybe internal further connection points
(mIf2InDConns + paDIPortId)->setValue(getDI(paDIPortId));
(mIf2InDConns + paDIPortId)->cloneInputInterfaceValue();
}
}
return retVal;
}
bool CCompositeFB::configureGenericDO(TPortId paDOPortId, const CIEC_ANY &paRefValue){
bool bRetVal = CFunctionBlock::configureGenericDO(paDOPortId, paRefValue);
if(true == bRetVal && 0 != m_apoIn2IfDConns[paDOPortId]){
//issue a reconfiguration attempt so that all connection end points in this connection are also correctly configured
m_apoIn2IfDConns[paDOPortId]->connectToCFBInterface(this, paDOPortId);
}
return bRetVal;
}
EMGMResponse CCompositeFB::changeFBExecutionState(EMGMCommandType pa_unCommand){
EMGMResponse nRetVal = CFunctionBlock::changeFBExecutionState(pa_unCommand);
for(unsigned int i = 0; ((i < cm_cpoFBNData->m_nNumFBs) && (e_RDY == nRetVal)); ++i){
if(m_apoInternalFBs[i]){
nRetVal = m_apoInternalFBs[i]->changeFBExecutionState(pa_unCommand);
}
}
//Update FB parameters that maybe got overwritten by default values of the FB
if((cg_nMGM_CMD_Reset == pa_unCommand) && (e_IDLE == getState())){
setParams();
}
return nRetVal;
}
#ifdef FORTE_SUPPORT_MONITORING
CFunctionBlock *CCompositeFB::getFB(forte::core::TNameIdentifier::CIterator &paNameListIt){
CFunctionBlock *retVal = 0;
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFBs; ++i){
if(m_apoInternalFBs[i]->getInstanceNameId() == *paNameListIt){
if(paNameListIt.isLastEntry()){
retVal = m_apoInternalFBs[i];
} else {
//we are looking for a child of this fB
++paNameListIt;
retVal = m_apoInternalFBs[i]->getFB(paNameListIt);
}
}
}
if(0 == retVal){
//check if it is an adapter of the function block
retVal = CFunctionBlock::getFB(paNameListIt);
}
return retVal;
}
#endif
CIEC_ANY *CCompositeFB::getVar(CStringDictionary::TStringId *paNameList,
unsigned int paNameListSize){
CIEC_ANY *retVal = 0;
if(1 > paNameListSize){
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFBs; ++i){
if(*paNameList == m_apoInternalFBs[i]->getInstanceNameId()){
paNameList++;
paNameListSize--;
retVal = m_apoInternalFBs[i]->getVar(paNameList, paNameListSize);
break;
}
}
}
else{
retVal = CFunctionBlock::getVar(paNameList, paNameListSize);
}
return retVal;
}
void CCompositeFB::executeEvent(int pa_nEIID){
if(cgInternal2InterfaceMarker & pa_nEIID){
sendInternal2InterfaceOutputEvent(static_cast<TEventID>(pa_nEIID
& cgInternal2InterfaceRemovalMask));
}
else{
if(pa_nEIID < m_pstInterfaceSpec->m_nNumEIs && 0 != mInterface2InternalEventCons[pa_nEIID]){
mInterface2InternalEventCons[pa_nEIID]->triggerEvent(*m_poInvokingExecEnv);
}
}
}
void CCompositeFB::sendInternal2InterfaceOutputEvent(int pa_nEOID){
//handle sampling of internal 2 interface data connections
if((pa_nEOID < m_pstInterfaceSpec->m_nNumEOs) && (0 != m_pstInterfaceSpec->m_anEOWithIndexes) &&
(-1 != m_pstInterfaceSpec->m_anEOWithIndexes[pa_nEOID])){
const TDataIOID *poEOWithStart =
&(m_pstInterfaceSpec->m_anEOWith[m_pstInterfaceSpec->m_anEOWithIndexes[pa_nEOID]]);
// TODO think on this lock
{
CCriticalRegion criticalRegion(getResource().m_oResDataConSync);
for(int i = 0; poEOWithStart[i] != 255; ++i){
if(0 != m_apoIn2IfDConns[poEOWithStart[i]]){
m_apoIn2IfDConns[poEOWithStart[i]]->readData(getDO(poEOWithStart[i]));
}
}
}
}
sendOutputEvent(pa_nEOID);
}
void CCompositeFB::createInternalFBs(){
if(cm_cpoFBNData->m_nNumFBs){
m_apoInternalFBs = new TFunctionBlockPtr[cm_cpoFBNData->m_nNumFBs];
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFBs; ++i){
m_apoInternalFBs[i] =
CTypeLib::createFB(cm_cpoFBNData->m_pstFBInstances[i].m_nFBInstanceNameId, cm_cpoFBNData->m_pstFBInstances[i].m_nFBTypeNameId, getResourcePtr());
}
}
}
void CCompositeFB::createEventConnections(){
prepareIf2InEventCons(); //the interface to internal event connections are needed even if they are not connected therefore we have to create them correctly in any case
if(0 != cm_cpoFBNData->m_nNumEventConnections){
m_apoEventConnections = new CEventConnection *[cm_cpoFBNData->m_nNumEventConnections]; //TODO for a major revison this list could be ommited but requires a change in the faned out connections
CFunctionBlock *poSrcFB;
CFunctionBlock *poDstFB;
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumEventConnections; ++i){
const SCFB_FBConnectionData *cpstCurrentConn = &(cm_cpoFBNData->m_pstEventConnections[i]);
//FIXME implement way to inform FB creator that creation failed
poSrcFB = getFunctionBlock(cpstCurrentConn->m_nSrcFBNum);
poDstFB = getFunctionBlock(cpstCurrentConn->m_nDstFBNum);
if((0 != poSrcFB) && (0 != poDstFB)){
if(this == poSrcFB){
m_apoEventConnections[i] =
mInterface2InternalEventCons[getEIID(cpstCurrentConn->m_nSrcId)];
}
else{
m_apoEventConnections[i] = poSrcFB->getEOConnection(cpstCurrentConn->m_nSrcId);
}
establishConnection(m_apoEventConnections[i], poDstFB, cpstCurrentConn->m_nDstId);
}
else{
DEVLOG_ERROR("Could not create event connection in CFB");
}
}
//now handle the fanned out connections
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFannedOutEventConnections; ++i){
const SCFB_FBFannedOutConnectionData *cpstCurrentFannedConn = &(cm_cpoFBNData->m_pstFannedOutEventConnections[i]);
poDstFB = getFunctionBlock(cpstCurrentFannedConn->m_nDstFBNum);
establishConnection(m_apoEventConnections[cpstCurrentFannedConn->m_nConnectionNum],
poDstFB, cpstCurrentFannedConn->m_nDstId);
}
}
}
void CCompositeFB::prepareIf2InEventCons(){
if(0 != m_pstInterfaceSpec->m_nNumEIs){
mInterface2InternalEventCons = new TEventConnectionPtr[m_pstInterfaceSpec->m_nNumEIs];
//FIXME find a way to avoid that each connection has to be allocated separately
for(TPortId i = 0; i < m_pstInterfaceSpec->m_nNumEIs; i++){
mInterface2InternalEventCons[i] = new CEventConnection(this, i);
}
}
}
void CCompositeFB::establishConnection(CConnection *paCon, CFunctionBlock *paDstFb,
CStringDictionary::TStringId paDstNameId){
if(this == paDstFb){
paCon->connectToCFBInterface(paDstFb, paDstNameId);
}
else{
paCon->connect(paDstFb, paDstNameId);
}
}
void CCompositeFB::createDataConnections(){
if(cm_cpoFBNData->m_nNumDataConnections){
if(m_pstInterfaceSpec->m_nNumDIs){
prepareIf2InDataCons();
}
if(m_pstInterfaceSpec->m_nNumDOs){
m_apoIn2IfDConns = new CDataConnection *[m_pstInterfaceSpec->m_nNumDOs];
for(TPortId i = 0; i < m_pstInterfaceSpec->m_nNumDOs; i++){
m_apoIn2IfDConns[i] = 0;
}
}
m_apoDataConnections = new CDataConnection *[cm_cpoFBNData->m_nNumDataConnections];
CFunctionBlock *poSrcFB;
CFunctionBlock *poDstFB;
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumDataConnections; ++i){
const SCFB_FBConnectionData *cpstCurrentConn = &(cm_cpoFBNData->m_pstDataConnections[i]);
//FIXME implement way to inform FB creator that creation failed
poSrcFB = getFunctionBlock(cpstCurrentConn->m_nSrcFBNum);
poDstFB = getFunctionBlock(cpstCurrentConn->m_nDstFBNum);
if((0 != poSrcFB) && (0 != poDstFB)){
if(this == poSrcFB){
m_apoDataConnections[i] = &(mIf2InDConns[getDIID(cpstCurrentConn->m_nSrcId)]);
}
else{
m_apoDataConnections[i] = poSrcFB->getDOConnection(cpstCurrentConn->m_nSrcId);
}
establishConnection(m_apoDataConnections[i], poDstFB, cpstCurrentConn->m_nDstId);
}
else{
DEVLOG_ERROR("Could not create event connection in CFB");
}
}
//now handle the fanned out connections
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumFannedOutDataConnections; ++i){
const SCFB_FBFannedOutConnectionData *cpstCurrentFannedConn = &(cm_cpoFBNData->m_pstFannedOutDataConnections[i]);
poDstFB = getFunctionBlock(cpstCurrentFannedConn->m_nDstFBNum);
establishConnection(m_apoDataConnections[cpstCurrentFannedConn->m_nConnectionNum],
poDstFB, cpstCurrentFannedConn->m_nDstId);
}
}
}
void CCompositeFB::prepareIf2InDataCons(){
mIf2InDConns = new CInterface2InternalDataConnection[m_pstInterfaceSpec->m_nNumDIs];
for(TPortId i = 0; i < m_pstInterfaceSpec->m_nNumDIs; i++){
(mIf2InDConns + i)->setSource(this, i);
}
}
void CCompositeFB::setParams(){
for(unsigned int i = 0; i < cm_cpoFBNData->m_nNumParams; ++i){
const SCFB_FBParameter *pstCurrentParam = &(cm_cpoFBNData->m_pstParams[i]);
CIEC_ANY *poDI =
m_apoInternalFBs[pstCurrentParam->m_nFBNum]->getDataInput(pstCurrentParam->m_nDINameID);
if(0 != poDI){
poDI->fromString(pstCurrentParam->m_acParamValue);
}
else{
DEVLOG_ERROR("Could not get date input for setting a parameter");
}
}
}
CFunctionBlock *CCompositeFB::getFunctionBlock(int pa_nFBNum){
CFunctionBlock *poRetVal = 0;
if(-1 == pa_nFBNum){
poRetVal = this;
}
else if(0 <= pa_nFBNum){
if(scm_nAdapterMarker == (scm_nAdapterMarker & pa_nFBNum)){
pa_nFBNum &= scm_nAdapterFBRange;
if(pa_nFBNum < m_pstInterfaceSpec->m_nNumAdapters){
poRetVal = m_apoAdapters[pa_nFBNum];
}
}
else{
if(static_cast<unsigned int>(pa_nFBNum) < cm_cpoFBNData->m_nNumFBs){
poRetVal = m_apoInternalFBs[pa_nFBNum];
}
}
}
return poRetVal;
}