blob: 07d18f81d9e379eceecb9c8392b59bb54bef968f [file] [log] [blame]
/*******************************************************************************
* 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;
}