blob: 8402cc5398165bf615391294a7a8bc2dd7e86781 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006-2014 ACIN, Profactor GmbH, fortiss GmbH
* 2018 Johannes Kepler University
* 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:
* Rene Smodic, Alois Zoitl, Michael Hofmann, Martin Melik Merkumians,
* Patrick Smejkal
* - initial implementation and rework communication infrastructure
* Alois Zoitl - introduced new CGenFB class for better handling generic FBs
*******************************************************************************/
#include <fortenew.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "commfb.h"
#ifdef FORTE_ENABLE_GENERATED_SOURCE_CPP
#include "commfb_gen.cpp"
#endif
#include "../resource.h"
#include "comlayer.h"
#include "comlayersmanager.h"
using namespace forte::com_infra;
const CStringDictionary::TStringId CCommFB::scm_aunRequesterEventInputNameIds[2] = { g_nStringIdINIT, g_nStringIdREQ };
const CStringDictionary::TStringId CCommFB::scm_aunRequesterEventOutputNameIds[2] = { g_nStringIdINITO, g_nStringIdCNF };
const CStringDictionary::TStringId CCommFB::scm_aunResponderEventInputNameIds[2] = { g_nStringIdINIT, g_nStringIdRSP };
const CStringDictionary::TStringId CCommFB::scm_aunResponderEventOutputNameIds[2] = { g_nStringIdINITO, g_nStringIdIND };
const TForteInt16 CCommFB::scm_anEIWithIndexes[] = { 0, 3 };
const TForteInt16 CCommFB::scm_anEOWithIndexes[] = { 0, 3, -1 };
CCommFB::CCommFB(const CStringDictionary::TStringId pa_nInstanceNameId, CResource *pa_poSrcRes, forte::com_infra::EComServiceType pa_eCommServiceType) :
CBaseCommFB(pa_nInstanceNameId, pa_poSrcRes, pa_eCommServiceType) {
}
CCommFB::~CCommFB() {
}
EMGMResponse CCommFB::changeFBExecutionState(EMGMCommandType pa_unCommand) {
EMGMResponse retVal = CEventSourceFB::changeFBExecutionState(pa_unCommand);
if ((e_RDY == retVal) && (cg_nMGM_CMD_Kill == pa_unCommand)) {
//when we are killed we'll close the connection so that it can safely be opened again after an reset
closeConnection();
}
return retVal;
}
void CCommFB::executeEvent(int paEIID) {
EComResponse resp = e_Nothing;
switch (paEIID) {
case scm_nEventINITID:
if (true == QI()) {
resp = openConnection();
}
else {
closeConnection();
resp = e_InitTerminated;
}
break;
case scm_nSendNotificationEventID:
resp = sendData();
break;
case cg_nExternalEventID:
resp = receiveData();
break;
default:
break;
}
if(resp & e_Terminated) {
if(m_eCommServiceType == e_Server && scm_nEventINITID != paEIID) { //if e_Terminated happened in INIT event, server shouldn't be silent
//servers will not send information on client termination and should silently start to listen again
resp = e_Nothing;
} else {
//subscribers and clients will close the connection and inform the user
closeConnection();
}
}
if (e_Nothing != resp) {
STATUS() = scm_sResponseTexts[resp & 0xF];
QO() = !(resp & scg_unComNegative);
if (scg_unINIT & resp) {
sendOutputEvent(scm_nEventINITOID);
}
else {
sendOutputEvent(scm_nReceiveNotificationEventID);
}
}
}
EComResponse CCommFB::sendData() {
EComResponse resp = e_Nothing;
if (true == QI()) {
if (m_eCommServiceType != e_Subscriber) {
if (0 != m_poTopOfComStack) {
resp = m_poTopOfComStack->sendData(static_cast<void*>(getSDs()), m_pstInterfaceSpec->m_nNumDIs - 2);
if ((resp == e_ProcessDataOk) && (m_eCommServiceType != e_Publisher)) {
// client and server will not directly send a cnf/ind event
resp = e_Nothing;
}
}
else {
resp = e_ProcessDataNoSocket;
}
}
}
else {
resp = e_ProcessDataInhibited; // we are not allowed to send data
}
return resp;
}
bool CCommFB::createInterfaceSpec(const char *paConfigString, SFBInterfaceSpec &paInterfaceSpec){
TIdentifier tempstring;
const char *sParamA = 0;
const char *sParamB = 0;
paInterfaceSpec.m_nNumEIs = 2;
paInterfaceSpec.m_nNumEOs = 2;
memcpy(tempstring, paConfigString, (strlen(paConfigString) > cg_nIdentifierLength) ? cg_nIdentifierLength : strlen(paConfigString) + 1); //plus 1 for the null character
tempstring[cg_nIdentifierLength] = '\0';
size_t inlength = strlen(tempstring);
size_t i;
for (i = 0; i < inlength - 1; i++) { // search first underscore
if (tempstring[i] == '_') {
sParamA = sParamB = &(tempstring[i + 1]);
break;
}
}
if(0 != sParamA) { // search for 2nd underscore
for (i = i + 1; i < inlength - 1; i++) {
if (tempstring[i] == '_') {
tempstring[i] = '\0';
sParamB = &(tempstring[i + 1]);
break;
}
}
}
if (0 == sParamB){ // no underscore found
return false;
}
configureDIs(sParamA, paInterfaceSpec);
configureDOs(sParamB, paInterfaceSpec);
if (forte::com_infra::e_Requester == (forte::com_infra::e_Requester & m_eCommServiceType)) {
paInterfaceSpec.m_aunEINames = scm_aunRequesterEventInputNameIds;
paInterfaceSpec.m_aunEONames = scm_aunRequesterEventOutputNameIds;
}
else {
if (forte::com_infra::e_Responder == (forte::com_infra::e_Responder & m_eCommServiceType)) {
paInterfaceSpec.m_aunEINames = scm_aunResponderEventInputNameIds;
paInterfaceSpec.m_aunEONames = scm_aunResponderEventOutputNameIds;
}
}
paInterfaceSpec.m_anEIWithIndexes = scm_anEIWithIndexes;
paInterfaceSpec.m_anEOWithIndexes = scm_anEOWithIndexes;
return true;
}
void CCommFB::configureDIs(const char *paDIConfigString, SFBInterfaceSpec &paInterfaceSpec){
CStringDictionary::TStringId* diDataTypeNames;
CStringDictionary::TStringId* diNames;
TDataIOID* eiWith;
paInterfaceSpec.m_nNumDIs = 2;
if (forte::com_infra::e_DataInputs == (forte::com_infra::e_DataInputs & m_eCommServiceType)) {
//TODO: Check range of sParamA
paInterfaceSpec.m_nNumDIs = static_cast<TForteUInt8>(paInterfaceSpec.m_nNumDIs + forte::core::util::strtol(paDIConfigString, 0, 10));
diDataTypeNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDIs];
diNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDIs];
eiWith = new TDataIOID[paInterfaceSpec.m_nNumDIs - 2 + scmMinWithLength];
generateGenericDataPointArrays("SD_", &(diDataTypeNames[2]), &(diNames[2]), paInterfaceSpec.m_nNumDIs - 2);
}
else {
diDataTypeNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDIs];
diNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDIs];
eiWith = new TDataIOID[scmMinWithLength];
}
paInterfaceSpec.m_aunDIDataTypeNames = diDataTypeNames;
paInterfaceSpec.m_aunDINames = diNames;
paInterfaceSpec.m_anEIWith = eiWith;
eiWith[0] = 0;
eiWith[1] = 1;
eiWith[2] = scmWithListDelimiter;
eiWith[3] = 0;
eiWith[4] = 1;
size_t i;
for (i = 0; i < paInterfaceSpec.m_nNumDIs - 2U; i++) {
eiWith[i + 5U] = static_cast<TForteUInt8>(i + 2U);
}
eiWith[i + 5U] = scmWithListDelimiter;
diDataTypeNames[0] = g_nStringIdBOOL;
diNames[0] = g_nStringIdQI;
#ifdef FORTE_USE_WSTRING_DATATYPE
diDataTypeNames[1] = g_nStringIdWSTRING;
#else //FORTE_USE_WSTRING_DATATYPE
diDataTypeNames[1] = g_nStringIdSTRING;
#endif //FORTE_USE_WSTRING_DATATYPE
diNames[1] = g_nStringIdID;
}
void CCommFB::configureDOs(const char *paDOConfigString, SFBInterfaceSpec &paInterfaceSpec){
CStringDictionary::TStringId* doDataTypeNames;
CStringDictionary::TStringId* doNames;
TDataIOID* eoWith;
paInterfaceSpec.m_nNumDOs = 2;
if(forte::com_infra::e_DataOutputs == (forte::com_infra::e_DataOutputs & m_eCommServiceType)){
//TODO: Check range of sParamA
paInterfaceSpec.m_nNumDOs = static_cast<TForteUInt8>(paInterfaceSpec.m_nNumDOs + forte::core::util::strtol(paDOConfigString, 0, 10));
doDataTypeNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDOs];
doNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDOs];
eoWith = new TDataIOID[paInterfaceSpec.m_nNumDOs - 2 + scmMinWithLength];
generateGenericDataPointArrays("RD_", &(doDataTypeNames[2]), &(doNames[2]), paInterfaceSpec.m_nNumDOs - 2);
}
else{
doDataTypeNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDOs];
doNames = new CStringDictionary::TStringId[paInterfaceSpec.m_nNumDOs];
eoWith = new TDataIOID[scmMinWithLength];
}
paInterfaceSpec.m_aunDONames = doNames;
paInterfaceSpec.m_aunDODataTypeNames = doDataTypeNames;
paInterfaceSpec.m_anEOWith = eoWith;
eoWith[0] = 0;
eoWith[1] = 1;
eoWith[2] = scmWithListDelimiter;
eoWith[3] = 0;
eoWith[4] = 1;
size_t i;
for(i = 0; i < paInterfaceSpec.m_nNumDOs - 2U; i++){
eoWith[i + 5U] = static_cast<TForteUInt8>(i + 2U);
}
eoWith[i + 5U] = scmWithListDelimiter;
doDataTypeNames[0] = g_nStringIdBOOL;
doNames[0] = g_nStringIdQO;
#ifdef FORTE_USE_WSTRING_DATATYPE
doDataTypeNames[1] = g_nStringIdWSTRING;
#else
doDataTypeNames[1] = g_nStringIdSTRING;
#endif
doNames[1] = g_nStringIdSTATUS;
}
EComResponse CCommFB::receiveData() {
EComResponse eResp;
EComResponse eRetVal = e_Nothing;
const unsigned int comInterruptQueueCountCopy = m_unComInterruptQueueCount;
for (size_t i = 0; i < comInterruptQueueCountCopy; ++i) {
eResp = m_apoInterruptQueue[i]->processInterrupt();
if (eResp > eRetVal) {
eRetVal = eResp;
}
}
m_unComInterruptQueueCount -= comInterruptQueueCountCopy;
for (unsigned int i = 0; i < m_unComInterruptQueueCount; ++i) {
m_apoInterruptQueue[i] = m_apoInterruptQueue[i + comInterruptQueueCountCopy];
}
return eRetVal;
}
char *CCommFB::getDefaultIDString(const char *paID) {
return buildIDString("fbdk[].ip[", paID, "]");
}