blob: 4bf43d918e03364540240f86bc9cef47e34f9de5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 -2014 AIT, 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:
* Filip Andren, Patrick Smejkal, Alois Zoitl, Martin Melik-Merkumians - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "opccomlayer.h"
#include "../../arch/devlog.h"
#include "commfb.h"
#include "opcconnection.h"
#include "opcconnectionhandler.h"
#include "Variant.h"
#include <criticalregion.h>
using namespace forte::com_infra;
COpcComLayer::COpcComLayer(CComLayer* pa_poUpperLayer, CBaseCommFB* pa_poComFB) :
CComLayer(pa_poUpperLayer, pa_poComFB), m_acHost(0), m_acServerName(0), m_nUpdateRate(0), m_nDeadBand(0), m_bLayerParamsOK(false), m_pOpcConnection(0), m_eInterruptResp(e_Nothing){
m_acOpcGroupName = m_poFb->getInstanceName();
}
COpcComLayer::~COpcComLayer(){
}
EComResponse COpcComLayer::sendData(void *pa_pvData, unsigned int pa_unSize){
EComResponse eRetVal = e_ProcessDataOk;
if((0 != m_poFb)){
if(m_pOpcConnection->isConnected()){
switch (m_poFb->getComServiceType()){
case e_Server:
//TODO
break;
case e_Client: {
convertInputData(pa_pvData, pa_unSize);
TOpcProcessVarList::Iterator itEnd = m_lFBInputVars.end();
for(TOpcProcessVarList::Iterator it = m_lFBInputVars.begin(); it != itEnd; ++it){
if(it->getIsActive()) {
m_pOpcConnection->send_sendItemData((*it));
}
}
break;
}
case e_Publisher:
//do nothing as OPC cannot be publisher
break;
case e_Subscriber:
//do nothing as subscribers do not send data
break;
}
}
}
return eRetVal;
}
EComResponse COpcComLayer::processInterrupt(){
EComResponse eRet = e_Nothing;
EComResponse currentComResponse;
{
CCriticalRegion criticalRegion(m_oSync);
TComResponseList::Iterator comIt(m_lComResponses.begin());
currentComResponse = *comIt;
m_lComResponses.popFront();
}
switch (currentComResponse){
case e_ProcessDataOk:
switch (m_eConnectionState){
case e_Connected: {
CIEC_ANY *apoRDs = m_poFb->getRDs();
unsigned int nrRDs = m_poFb->getNumRD();
TOpcProcessVarList::Iterator itEnd = m_lFBOutputVars.end();
TOpcProcessVarList::Iterator it = m_lFBOutputVars.begin();
for(unsigned int i = 0; i < nrRDs && it != itEnd; i++, ++it){
setOutputValue(&apoRDs[i], &it->updateValue());
}
break;
}
case e_Disconnected:
case e_Listening:
case e_ConnectedAndListening:
default:
break;
}
eRet = e_ProcessDataOk;
break;
case e_InitInvalidId:
eRet = e_InitInvalidId;
break;
case e_InitTerminated:
eRet = e_InitTerminated;
break;
}
return eRet;
}
EComResponse COpcComLayer::recvData(const void *, unsigned int){
EComResponse eRet = e_Nothing;
switch (m_poFb->getComServiceType()){
case e_Server:
//TODO
break;
case e_Client: {
switch (m_pOpcConnection->getConnectionState()){
case COpcConnection::e_Connected:
// Successfully connected --> adding OPC items
if(addOpcItems() < 0){
//TODO
} else {
m_eConnectionState = e_Connected;
}
break;
case COpcConnection::e_ConnectionFailed:
{
CCriticalRegion criticalRegion(m_oSync);
m_lComResponses.pushBack(e_InitTerminated);
}
m_poFb->interruptCommFB(this);
eRet = e_InitTerminated;
break;
case COpcConnection::e_ItemAddedOk:
//do nothing
break;
case COpcConnection::e_ItemAddedFailed:
{
CCriticalRegion criticalRegion(m_oSync);
m_lComResponses.pushBack(e_InitTerminated);
}
m_poFb->interruptCommFB(this);
eRet = e_InitTerminated;
break;
case COpcConnection::e_DataReceived: {
int nRetVal = m_pOpcConnection->receiveData(m_acOpcGroupName, &m_lFBOutputVars);
if (nRetVal > 0) {
//we successfully received data
CCriticalRegion criticalRegion(m_oSync);
m_lComResponses.pushBack(e_ProcessDataOk);
}
m_poFb->interruptCommFB(this);
eRet = e_ProcessDataOk;
break;
}
case COpcConnection::e_Disconnected:
//TODO error during connection try
break;
default:
break;
}
break;
}
case e_Publisher:
//do nothing as publisher cannot receive data
case e_Subscriber:
//do nothing as OPC cannot be subscribers
break;
}
return eRet;
}
EComResponse COpcComLayer::openConnection(char *pa_acLayerParameter){
EComResponse eRetVal = e_InitInvalidId;
m_eConnectionState = e_Disconnected;
switch (m_poFb->getComServiceType()){
case e_Server:
//TODO
break;
case e_Client:
processClientParams(pa_acLayerParameter);
if(m_bLayerParamsOK){
eRetVal = e_InitOk;
m_pOpcConnection = COpcConnectionHandler::getInstance().getOpcConnection(m_acHost, m_acServerName, m_acOpcGroupName, m_nUpdateRate, m_nDeadBand, this);
m_pOpcConnection->send_connect();
COpcConnection::EOpcConnectionEvents connState = m_pOpcConnection->getConnectionState();
if (connState == COpcConnection::e_Connected) {
m_eConnectionState = e_Connected;
addOpcItems();
}
else if(connState == COpcConnection::e_ConnectionFailed) {
eRetVal = e_InitTerminated;
}
}
break;
case e_Publisher:
//do nothing, OPC cannot be publisher
break;
case e_Subscriber:
//do nothing, OPC cannot be subscriber
break;
}
return eRetVal;
}
void COpcComLayer::closeConnection(){
DEVLOG_DEBUG("COpcComLayer::closeConnection() \n");
COpcConnectionHandler::getInstance().removeOpcConnection(m_pOpcConnection->getHost(), m_pOpcConnection->getServerName(), m_acOpcGroupName);
m_eConnectionState = e_Disconnected;
}
int COpcComLayer::addOpcItems(){
int result = 0;
// Add input items
TOpcProcessVarList::Iterator itEnd = m_lFBInputVars.end();
for(TOpcProcessVarList::Iterator it = m_lFBInputVars.begin(); it != itEnd; ++it){
result = m_pOpcConnection->send_addItem(*it);
}
// Add output items
itEnd = m_lFBOutputVars.end();
for(TOpcProcessVarList::Iterator it = m_lFBOutputVars.begin(); it != itEnd; ++it){
result = m_pOpcConnection->send_addItem(*it);
}
return result;
}
void COpcComLayer::setOutputValue(CIEC_ANY *pa_pDataOut, Variant * pa_pValue){
switch (pa_pDataOut->getDataTypeID()){
case CIEC_ANY::e_BOOL:
pa_pDataOut->setValue(CIEC_BOOL(pa_pValue->get<bool>()));
break;
case CIEC_ANY::e_SINT:
pa_pDataOut->setValue(CIEC_SINT(pa_pValue->get<TForteInt8>()));
break;
case CIEC_ANY::e_INT:
pa_pDataOut->setValue(CIEC_INT(pa_pValue->get<TForteInt16>()));
break;
case CIEC_ANY::e_DINT:
pa_pDataOut->setValue(CIEC_DINT(pa_pValue->get<TForteInt32>()));
break;
case CIEC_ANY::e_LINT:
pa_pDataOut->setValue(CIEC_LINT(pa_pValue->get<TForteInt64>()));
break;
case CIEC_ANY::e_USINT:
pa_pDataOut->setValue(CIEC_USINT(pa_pValue->get<TForteUInt8>()));
break;
case CIEC_ANY::e_UINT:
pa_pDataOut->setValue(CIEC_UINT(pa_pValue->get<TForteUInt16>()));
break;
case CIEC_ANY::e_UDINT:
pa_pDataOut->setValue(CIEC_UDINT(pa_pValue->get<TForteUInt32>()));
break;
case CIEC_ANY::e_ULINT:
pa_pDataOut->setValue(CIEC_ULINT(pa_pValue->get<TForteUInt64>()));
break;
case CIEC_ANY::e_BYTE:
pa_pDataOut->setValue(CIEC_BYTE(pa_pValue->get<TForteByte>()));
break;
case CIEC_ANY::e_WORD:
pa_pDataOut->setValue(CIEC_WORD(pa_pValue->get<TForteWord>()));
break;
case CIEC_ANY::e_DWORD:
pa_pDataOut->setValue(CIEC_DWORD(pa_pValue->get<TForteDWord>()));
break;
case CIEC_ANY::e_LWORD:
pa_pDataOut->setValue(CIEC_LWORD(pa_pValue->get<TForteLWord>()));
break;
case CIEC_ANY::e_REAL:
pa_pDataOut->setValue(CIEC_REAL(pa_pValue->get<TForteFloat>()));
break;
case CIEC_ANY::e_LREAL:
pa_pDataOut->setValue(CIEC_LREAL(pa_pValue->get<TForteDFloat>()));
break;
default:
//TODO
break;
}
}
void COpcComLayer::processClientParams(char* pa_acLayerParams){
char *chrStorage;
char *chrHost;
char *chrServer;
char *temp;
// Get Host
chrStorage = strchr(pa_acLayerParams, ':');
if(chrStorage == 0) {
return;
}
*chrStorage = '\0';
++chrStorage;
chrHost = (char*) malloc(strlen(pa_acLayerParams) + 1);
strcpy(chrHost, pa_acLayerParams);
if(strcmp(chrHost, "127.0.0.1") == 0 || strcmp(chrHost, "localhost") == 0) {
m_acHost = "";
} else {
m_acHost = chrHost;
}
// Get server name
temp = chrStorage;
chrStorage = strchr(chrStorage, ':');
if(chrStorage == 0){
if (chrHost){
free(chrHost);
}
return;
}
*chrStorage = '\0';
++chrStorage;
chrServer = (char*) malloc(strlen(temp) + 1);
strcpy(chrServer, temp);
m_acServerName = chrServer;
// Get update rate
m_nUpdateRate = atol(chrStorage);
chrStorage = strchr(chrStorage, ':');
if(chrStorage == 0){
if (chrHost){
free(chrHost);
}
return;
}
*chrStorage = '\0';
++chrStorage;
// Get dead band
m_nDeadBand = (float) atof(chrStorage);
chrStorage = strchr(chrStorage, ':');
if(chrStorage == 0){
if (chrHost){
free(chrHost);
}
return;
}
*chrStorage = '\0';
++chrStorage;
// Get FB input items
char * inputItems = chrStorage;
chrStorage = strchr(chrStorage, ':');
if(chrStorage == 0){
if (chrHost){
free(chrHost);
}
return;
}
*chrStorage = '\0';
++chrStorage;
int nrItems = 0;
char *pch;
pch = strtok(inputItems, ",");
while(pch != NULL){
char *itemName = (char*) malloc(strlen(pch) + 1);
strcpy(itemName, pch);
m_lFBInputVars.pushBack(new COpcProcessVar(m_acOpcGroupName, itemName, COpcProcessVar::e_FBInput));
nrItems++;
pch = strtok(NULL, ",");
}
// Get FB output items
pch = strtok(chrStorage, ",");
while(pch != NULL){
char *itemName = (char*) malloc(strlen(pch) + 1);
strcpy(itemName, pch);
m_lFBOutputVars.pushBack(new COpcProcessVar(m_acOpcGroupName, itemName, COpcProcessVar::e_FBOutput));
nrItems++;
pch = strtok(NULL, ",");
}
if(nrItems > 0) {
m_bLayerParamsOK = true;
}
}
void COpcComLayer::convertInputData(void *pa_pData, unsigned int pa_nSize){
//CIEC_ANY *apoSDs = static_cast<CIEC_ANY*>(pa_pData);
unsigned int nrSDs = pa_nSize;
unsigned int sdIndex = 0;
TOpcProcessVarList::Iterator it_var = m_lFBInputVars.begin();
TOpcProcessVarList::Iterator itEnd = m_lFBInputVars.end();
while(sdIndex < nrSDs && it_var != itEnd){
// CIEC_ANY *dataIn = &apoSDs[sdIndex];
Variant newVariant;
//unsigned int valueSize = 0;
//valueSize = getInputValueSize(dataIn, &newVariant);;
it_var->setNewValue(newVariant);
++it_var;
++sdIndex;
}
}
template<typename T>
void COpcComLayer::getInputValue(void * pa_pData, Variant * pa_pNewValue){
T* vData = (T*) pa_pData;
T data = vData[0];
pa_pNewValue->set<T>(data);
}
unsigned int COpcComLayer::getInputValueSize(CIEC_ANY* pa_pData, Variant * pa_pNewValue){
switch (pa_pData->getDataTypeID()){
case CIEC_ANY::e_BOOL:
{
pa_pNewValue->set<bool>((bool) *(dynamic_cast<CIEC_BOOL*>(pa_pData)));
return sizeof(bool);
}
case CIEC_ANY::e_SINT:
{
pa_pNewValue->set<CHAR>((CHAR) *(dynamic_cast<CIEC_SINT*>(pa_pData)));
return sizeof(TForteInt8);
}
case CIEC_ANY::e_INT:
{
CIEC_INT* tempInt = dynamic_cast<CIEC_INT*>(pa_pData);
TForteInt16 forteInt = (TForteInt16) (*tempInt);
pa_pNewValue->set<TForteInt16>(forteInt);
return sizeof(TForteInt16);
}
case CIEC_ANY::e_DINT:
{
pa_pNewValue->set<TForteInt32>((TForteInt32) *(dynamic_cast<CIEC_DINT*>(pa_pData)));
return sizeof(TForteInt32);
}
case CIEC_ANY::e_LINT:
{
pa_pNewValue->set<TForteInt64>((TForteInt64) *(dynamic_cast<CIEC_LINT*>(pa_pData)));
return sizeof(TForteInt64);
}
case CIEC_ANY::e_USINT:
{
pa_pNewValue->set<TForteUInt8>((TForteUInt8) *(dynamic_cast<CIEC_USINT*>(pa_pData)));
return sizeof(TForteUInt8);
}
case CIEC_ANY::e_UINT:
{
pa_pNewValue->set<TForteUInt16>((TForteUInt16) *(dynamic_cast<CIEC_UINT*>(pa_pData)));
return sizeof(TForteUInt16);
}
case CIEC_ANY::e_UDINT:
{
pa_pNewValue->set<TForteUInt32>((TForteUInt32) *(dynamic_cast<CIEC_UDINT*>(pa_pData)));
return sizeof(TForteUInt32);
}
case CIEC_ANY::e_ULINT:
{
pa_pNewValue->set<TForteUInt64>((TForteUInt64) *(dynamic_cast<CIEC_ULINT*>(pa_pData)));
return sizeof(TForteUInt64);
}
case CIEC_ANY::e_BYTE:
{
pa_pNewValue->set<TForteByte>((TForteByte) *(dynamic_cast<CIEC_BYTE*>(pa_pData)));
return sizeof(TForteByte);
}
case CIEC_ANY::e_WORD:
{
pa_pNewValue->set<TForteWord>((TForteWord) *(dynamic_cast<CIEC_WORD*>(pa_pData)));
return sizeof(TForteWord);
}
case CIEC_ANY::e_DWORD:
{
pa_pNewValue->set<TForteDWord>((TForteDWord) *(dynamic_cast<CIEC_DWORD*>(pa_pData)));
return sizeof(TForteDWord);
}
case CIEC_ANY::e_LWORD:
{
pa_pNewValue->set<TForteLWord>((TForteLWord) *(dynamic_cast<CIEC_LWORD*>(pa_pData)));
return sizeof(TForteLWord);
}
case CIEC_ANY::e_REAL:
{
pa_pNewValue->set<TForteFloat>((TForteFloat) *(dynamic_cast<CIEC_REAL*>(pa_pData)));
return sizeof(TForteFloat);
}
case CIEC_ANY::e_LREAL:
{
pa_pNewValue->set<TForteDFloat>((TForteDFloat) *(dynamic_cast<CIEC_LREAL*>(pa_pData)));
return sizeof(TForteDFloat);
}
default:
//TODO
break;
}
return 0;
}