/******************************************************************************* | |
* Copyright (c) 2016 - 2017 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: | |
* Monika Wenger, Alois Zoitl - initial API and implementation and/or initial documentation | |
* Jose Cabral - Cleaning of code and error logging added | |
*******************************************************************************/ | |
#include "processinterface.h" | |
#include <extevhandlerhelper.h> | |
#include <unistd.h> | |
#include <mlpiGlobal.h> | |
#include <mlpiApiLib.h> | |
#include <mlpiLogicLib.h> | |
#include <util/wchar16.h> | |
const char * const CMLPIFaceProcessInterface::scmOK = "OK"; | |
const char * const CMLPIFaceProcessInterface::scmAPINotInitialised = "API not initialized"; | |
const char * const CMLPIFaceProcessInterface::scmFBNotInitialised = "FB not initialized"; | |
const char * const CMLPIFaceProcessInterface::scmCallToApiFailed = "Call to API Failed"; | |
MLPIHANDLE CMLPIFaceProcessInterface::smConnection = MLPI_INVALIDHANDLE; | |
CMLPIFaceProcessInterface::CMLPIFaceProcessInterface(CResource *paSrcRes, const SFBInterfaceSpec *paInterfaceSpec, const CStringDictionary::TStringId paInstanceNameId, TForteByte *paFBConnData, TForteByte *paFBVarsData) : | |
CProcessInterfaceBase(paSrcRes, paInterfaceSpec, paInstanceNameId, paFBConnData, paFBVarsData), mVariableName(0){ | |
} | |
CMLPIFaceProcessInterface::~CMLPIFaceProcessInterface(){ | |
deinitialise(); | |
} | |
void CMLPIFaceProcessInterface::disconnectFromMLPI(){ //TODO: this is never called. Where should it be? | |
if(MLPI_INVALIDHANDLE != smConnection){ | |
MLPIRESULT result = mlpiApiDisconnect(&smConnection); | |
if(!MLPI_FAILED(result)){ | |
DEVLOG_INFO("Successfully disconnected from MLPI!\n"); | |
} | |
else{ | |
DEVLOG_INFO("Error on disconnect from MLPI with 0x%08x\n", (unsigned ) result); | |
} | |
} | |
} | |
bool CMLPIFaceProcessInterface::connectToMLPI(){ | |
smConnection = MLPI_INVALIDHANDLE; | |
bool retVal = false; | |
DEVLOG_INFO("Trying to connect to the Api\n"); | |
MLPIRESULT result = mlpiApiConnect(MLPI_LOCALHOST, &smConnection); | |
if(!MLPI_FAILED(result)){ | |
DEVLOG_INFO("Connection to the API succeed\n"); | |
retVal = true; | |
} | |
else{ | |
DEVLOG_ERROR("Failed to connect to the API: 0x%08X\n", (unsigned ) result); | |
} | |
return retVal; | |
} | |
bool CMLPIFaceProcessInterface::initialise(bool paInput){ | |
bool retVal = false; | |
/* | |
* Starting forte at boot in the PLC has the effect of failing when connecting to the MLPI | |
* probably because the stack is not ready yet. So this waits until mMaxNumberOfTriesToReconnect seconds or succeed, | |
* whichever happens first, in order to continue. | |
*/ | |
if(MLPI_INVALIDHANDLE == smConnection){ | |
unsigned int connectRetries = 0; | |
CMLPIFaceProcessInterface::connectToMLPI(); | |
while(MLPI_INVALIDHANDLE == smConnection && mMaxNumberOfTriesToReconnect > connectRetries){ | |
CThread::sleepThread(1000); | |
CMLPIFaceProcessInterface::connectToMLPI(); | |
connectRetries++; | |
} | |
} | |
if(MLPI_INVALIDHANDLE != smConnection){ | |
mVariableName = new WCHAR16[PARAMS().length() + 1]; | |
if(0 != mbstowcs16(mVariableName, PARAMS().getValue(), PARAMS().length() + 1)){ //+1 for the copying the null terminator | |
STATUS() = scmOK; | |
retVal = true; | |
if(paInput){ | |
getExtEvHandler<CMLPIFaceProcessInterface::CIOHandler>(*this).registerIXFB(this); | |
if(!getExtEvHandler<CMLPIFaceProcessInterface::CIOHandler>(*this).isAlive()){ | |
getExtEvHandler<CMLPIFaceProcessInterface::CIOHandler>(*this).start(); | |
} | |
} | |
} | |
else{ | |
DEVLOG_ERROR("Fail transforming the PARAM name\n"); | |
STATUS() = scmFBNotInitialised; | |
} | |
} | |
else{ | |
DEVLOG_ERROR("Couldn't initialize API\n"); | |
STATUS() = scmAPINotInitialised; | |
} | |
return retVal; | |
} | |
bool CMLPIFaceProcessInterface::deinitialise(){ | |
getExtEvHandler<CMLPIFaceProcessInterface::CIOHandler>(*this).unregisterIXFB(this); | |
delete[] mVariableName; | |
STATUS() = scmAPINotInitialised; | |
return true; | |
} | |
bool CMLPIFaceProcessInterface::readPin(){ | |
return true; | |
} | |
bool CMLPIFaceProcessInterface::writePin(){ | |
bool retVal = false; | |
if(MLPI_INVALIDHANDLE != smConnection){ | |
BOOL8 data = OUT_X(); | |
MLPIRESULT result = mlpiLogicWriteVariableBySymbolBool8(smConnection, mVariableName, data); | |
if(!MLPI_FAILED(result)){ | |
STATUS() = scmOK; | |
retVal = true; | |
} | |
else{ | |
DEVLOG_ERROR("Failed to write: 0x%08X\n", (unsigned ) result); | |
STATUS() = scmCallToApiFailed; | |
} | |
} | |
else{ | |
DEVLOG_ERROR("Cannot write pin. The API is not initialized.\n"); | |
STATUS() = scmAPINotInitialised; | |
} | |
return retVal; | |
} | |
bool CMLPIFaceProcessInterface::checkInputData(){ | |
bool retVal = false; | |
if(MLPI_INVALIDHANDLE != smConnection){ | |
BOOL8 data = FALSE; | |
MLPIRESULT result = mlpiLogicReadVariableBySymbolBool8(smConnection, mVariableName, &data); | |
if(!MLPI_FAILED(result)){ | |
bool newData = (data != FALSE) ? true : false; | |
if(newData != IN_X()){ | |
IN_X() = newData; | |
retVal = true; | |
} | |
} | |
else{ | |
DEVLOG_ERROR("Failed to read: 0x%08X\n", (unsigned ) result); | |
STATUS() = scmCallToApiFailed; | |
} | |
} | |
else{ | |
DEVLOG_ERROR("Cannot read pin. The API is not initialized.\n"); | |
STATUS() = scmAPINotInitialised; | |
} | |
return retVal; | |
} | |
DEFINE_HANDLER(CMLPIFaceProcessInterface::CIOHandler) | |
CMLPIFaceProcessInterface::CIOHandler::CIOHandler(CDeviceExecution& pa_poDeviceExecution) : CExternalEventHandler(pa_poDeviceExecution){ | |
} | |
CMLPIFaceProcessInterface::CIOHandler::~CIOHandler(){ | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::registerIXFB(CMLPIFaceProcessInterface *pa_poFB){ | |
mReadFBListSync.lock(); | |
mReadFBList.pushBack(pa_poFB); | |
mReadFBListSync.unlock(); | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::unregisterIXFB(CMLPIFaceProcessInterface *pa_poFB){ | |
mReadFBListSync.lock(); | |
TReadFBContainer::Iterator itRunner(mReadFBList.begin()); | |
TReadFBContainer::Iterator itRefNode(mReadFBList.end()); | |
TReadFBContainer::Iterator itEnd(mReadFBList.end()); | |
while(itRunner != itEnd){ | |
if(*itRunner == pa_poFB){ | |
if(itRefNode == itEnd){ | |
mReadFBList.popFront(); | |
} | |
else{ | |
mReadFBList.eraseAfter(itRefNode); | |
} | |
break; | |
} | |
itRefNode = itRunner; | |
++itRunner; | |
} | |
mReadFBListSync.unlock(); | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::run(){ | |
while(isAlive()){ | |
CThread::sleepThread(1); | |
updateReadData(); | |
} | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::updateReadData(){ | |
TReadFBContainer::Iterator itEnd(mReadFBList.end()); | |
for(TReadFBContainer::Iterator itRunner = mReadFBList.begin(); itRunner != itEnd; ++itRunner){ | |
if((*itRunner)->checkInputData()){ | |
startNewEventChain(*itRunner); | |
} | |
} | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::enableHandler(void){ | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::disableHandler(void){ | |
} | |
void CMLPIFaceProcessInterface::CIOHandler::setPriority(int){ | |
} | |
int CMLPIFaceProcessInterface::CIOHandler::getPriority(void) const{ | |
return 0; | |
} |