blob: f76c6c9b525516f5df59446d3c63d7e73cc79030 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 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:
* Milan Vathoopan, Alois Zoitl - initial API and implementation and/or initial documentation
* Milan Vathoopan - Extended functionality with anlog input and output blocks
*******************************************************************************/
#include "processinterface.h"
#include <sstream>
#include <datatype.h>
#include <extevhandlerhelper.h>
DEFINE_HANDLER(WagoPFCProcessInterface::CKBusHandler)
WagoPFCProcessInterface::WagoPFCProcessInterface(forte::core::CFBContainer &paContainer, const SFBInterfaceSpec *paInterfaceSpec,
const CStringDictionary::TStringId paInstanceNameId) :
CProcessInterfaceBase(paContainer, paInterfaceSpec, paInstanceNameId), mSlot(0), mChannel(0), mTerminalInfo(0), mInitialized(false) {
}
WagoPFCProcessInterface::~WagoPFCProcessInterface() {
deinitialise();
}
bool WagoPFCProcessInterface::initialise(bool paInput, CEventChainExecutionThread *const paECET) {
mInitialized = false;
std::vector<std::string> paramsList(generateParameterList());
char *pBuffer;
if(!paramsList.empty()) {
mSlot = strtol(paramsList[0].c_str(), &pBuffer, 10);
mChannel = strtol(paramsList[1].c_str(), &pBuffer, 10);
}
if((getExtEvHandler<CKBusHandler>(*this).isIdValid(static_cast<TForteUInt8>(mSlot)))) {
mTerminalInfo = getExtEvHandler<CKBusHandler>(*this).getTerminalInfo(static_cast<TForteUInt8>(mSlot));
if(0 != mTerminalInfo) {
if((paInput) && (getDO(2)->getDataTypeID() == CIEC_ANY::e_BOOL)) {
getExtEvHandler<CKBusHandler>(*this).registerKBusReadFB(this);
}
QO() = QI();
if(!getExtEvHandler<CKBusHandler>(*this).isAlive()) {
getExtEvHandler<CKBusHandler>(*this).start();
}
mInitialized = true;
setEventChainExecutor(paECET);
}
}
return mInitialized;
}
bool WagoPFCProcessInterface::deinitialise() {
getExtEvHandler<CKBusHandler>(*this).unregisterKBusReadFB(this);
return true;
}
bool WagoPFCProcessInterface::readPin() {
return true;
}
bool WagoPFCProcessInterface::writePin() {
getExtEvHandler<CKBusHandler>(*this).writeOutputDataBitToKBus(mTerminalInfo, mChannel, OUT_X());
return true;
}
bool WagoPFCProcessInterface::readWord() {
TForteWord inDataWord(0);
getExtEvHandler<CKBusHandler>(*this).readInputDataWordfromKBus(mTerminalInfo, mChannel, &inDataWord);
IN_W() = inDataWord;
return true;
}
bool WagoPFCProcessInterface::writeWord() {
getExtEvHandler<CKBusHandler>(*this).writeOutputDataWordToKBus(mTerminalInfo, mChannel, OUT_W());
return true;
}
bool WagoPFCProcessInterface::checkInputData() {
bool retVal = false;
bool inDataBool(false);
getExtEvHandler<CKBusHandler>(*this).readInputDataBitfromKBus(mTerminalInfo, mChannel, &inDataBool);
if(inDataBool != IN_X()) {
IN_X() = inDataBool;
retVal = true;
}
return retVal;
}
WagoPFCProcessInterface::CKBusHandler::CKBusHandler(CDeviceExecution& paDeviceExecution) :
CExternalEventHandler(paDeviceExecution), mTaskId(0) { // 0 has been taken from example may needs to be rechecked
tDeviceInfo deviceList[10]; // the list of devices given by the ADI
size_t nrDevicesFound; // number of devices found
mAppDevInterface = adi_GetApplicationInterface();
mAppDevInterface->Init();
mAppDevInterface->ScanDevices();
mAppDevInterface->GetDeviceList(sizeof(deviceList), deviceList, &nrDevicesFound);
// find kbus device
for(size_t i = 0; i < nrDevicesFound; ++i) {
if(strcmp(deviceList[i].DeviceName, "libpackbus") == 0) {
mKBusDeviceId = deviceList[i].DeviceId;
if(mAppDevInterface->OpenDevice(mKBusDeviceId) == DAL_SUCCESS) {
if(loadTerminalInformation()) {
return; //we successfully initialized everything so we can return
}
}
}
}
//if we are here the initialization could not be finished clean up and close everything
closeKBusInterface();
}
WagoPFCProcessInterface::CKBusHandler::~CKBusHandler() {
closeKBusInterface();
}
bool WagoPFCProcessInterface::CKBusHandler::isKBusRunning() {
return ((isAlive()) && (mKBusDeviceId != scmInvalidDeviceId));
}
bool WagoPFCProcessInterface::CKBusHandler::loadTerminalInformation() {
bool bRetVal = false;
if(KbusInfo_Failed != ldkc_KbusInfo_Create()) {
if(KbusInfo_Failed != ldkc_KbusInfo_GetTerminalInfo(OS_ARRAY_SIZE(mTerminalDescription), mTerminalDescription, &mTerminalCount)) {
if(KbusInfo_Failed != ldkc_KbusInfo_GetTerminalList(OS_ARRAY_SIZE(mTerminalIds), mTerminalIds, nullptr)) {
bRetVal = true;
} else {
DEVLOG_ERROR("CKBusHandler: ldkc_KbusInfo_GetTerminalList() failed\n");
}
} else {
DEVLOG_ERROR("CKBusHandler: ldkc_KbusInfo_GetTerminalInfo() failed\n");
}
bRetVal = true;
} else {
DEVLOG_ERROR("CKBusHandler: ldkc_KbusInfo_Create() failed\n");
}
if(!bRetVal) {
ldkc_KbusInfo_Destroy();
}
return bRetVal;
}
bool WagoPFCProcessInterface::CKBusHandler::isIdValid(TForteUInt8 paSlot) {
return (paSlot <= mTerminalCount);
}
tldkc_KbusInfo_TerminalInfo *WagoPFCProcessInterface::CKBusHandler::getTerminalInfo(TForteUInt8 paSlot) {
tldkc_KbusInfo_TerminalInfo *pstRetVal = 0;
if(paSlot <= mTerminalCount) {
pstRetVal = &(mTerminalDescription[paSlot]);
}
return pstRetVal;
}
void WagoPFCProcessInterface::CKBusHandler::run() {
//TODO add thread priority settings
//bool retVal= false;
tApplicationStateChangedEvent stEvent;
// Set application state to "Running" to drive kbus by ourselves.
stEvent.State = ApplicationState_Running;
if(DAL_SUCCESS == mAppDevInterface->ApplicationStateChanged(stEvent)) {
while(isAlive()) {
CThread::sleepThread(10); // wait 10 ms TODO make this configurable
if(!triggerKBusCycle()) {
//we have severe problem exit KBus handling thread
//TODO check how can we recover or at least inform the user
break;
}
// read inputs inform FBs
updateReadData();
}
} else {
DEVLOG_ERROR("CKBusHandler: Set application state to 'Running' failed\n");
}
closeKBusInterface();
}
bool WagoPFCProcessInterface::CKBusHandler::triggerKBusCycle() {
bool bRetVal = false;
uint32_t unPushRetVal = 0;
if(DAL_SUCCESS == mAppDevInterface->CallDeviceSpecificFunction("libpackbus_Push", &unPushRetVal)) {
if(DAL_SUCCESS == unPushRetVal) {
mAppDevInterface->WatchdogTrigger();
bRetVal = true;
} else {
DEVLOG_ERROR("CKBusHandler: Function 'libpackbus_Push' failed\n");
}
} else {
DEVLOG_ERROR("CKBusHandler: CallDeviceSpecificFunction for 'libpackbus_Push' failed\n");
}
return bRetVal;
}
std::vector<std::string> WagoPFCProcessInterface::generateParameterList() {
std::stringstream streamBuf(std::string(PARAMS().getValue()));
std::vector<std::string> retVal;
std::string segment;
while(std::getline(streamBuf, segment, '.')) { //seperate the PARAMS input by '.' for easier processing
retVal.push_back(segment);
}
return retVal;
}
void WagoPFCProcessInterface::CKBusHandler::updateReadData() {
//long pa_Value = strtol(mIndata, nullptr, 16);
mReadFBListSync.lock();
mAppDevInterface->ReadStart(mKBusDeviceId, mTaskId); /* lock PD-In data */
TReadFBContainer::Iterator itEnd(mReadFBList.end());
for(TReadFBContainer::Iterator itRunner = mReadFBList.begin(); itRunner != itEnd; ++itRunner) {
if((*itRunner)->checkInputData()) {
// If data has changed, give the indication event
startNewEventChain(*itRunner);
}
}
mAppDevInterface->ReadEnd(mKBusDeviceId, mTaskId); /* unlock PD-In data */
mReadFBListSync.unlock();
}
void WagoPFCProcessInterface::CKBusHandler::registerKBusReadFB(WagoPFCProcessInterface *paFB) {
mReadFBListSync.lock();
mReadFBList.pushBack(paFB);
mReadFBListSync.unlock();
}
void WagoPFCProcessInterface::CKBusHandler::unregisterKBusReadFB(WagoPFCProcessInterface *paFB) {
mReadFBListSync.lock();
TReadFBContainer::Iterator itRunner(mReadFBList.begin());
TReadFBContainer::Iterator itRefNode(mReadFBList.end());
TReadFBContainer::Iterator itEnd(mReadFBList.end());
while(itRunner != itEnd) {
if(*itRunner == paFB) {
if(itRefNode == itEnd) {
mReadFBList.popFront();
} else {
mReadFBList.eraseAfter(itRefNode);
}
break;
}
itRefNode = itRunner;
++itRunner;
}
mReadFBListSync.unlock();
}
void WagoPFCProcessInterface::CKBusHandler::writeOutputDataBitToKBus(tldkc_KbusInfo_TerminalInfo *paTerminal, TForteUInt32 paChannel, bool paOutDataBool) {
mAppDevInterface->WriteStart(mKBusDeviceId, mTaskId);
mAppDevInterface->WriteBool(mKBusDeviceId, mTaskId, ((paTerminal->OffsetOutput_bits) + paChannel), paOutDataBool);
mAppDevInterface->WriteEnd(mKBusDeviceId, mTaskId);
}
void WagoPFCProcessInterface::CKBusHandler::readInputDataBitfromKBus(tldkc_KbusInfo_TerminalInfo *paTerminal, TForteUInt32 paChannel, bool *paInDataBool) {
mAppDevInterface->ReadBool(mKBusDeviceId, mTaskId, ((paTerminal->OffsetInput_bits) + paChannel), paInDataBool);
}
void WagoPFCProcessInterface::CKBusHandler::readInputDataWordfromKBus(tldkc_KbusInfo_TerminalInfo *paTerminal, TForteUInt32 paChannel,
TForteWord *paInDataWord) {
TForteByte InData[2];
mAppDevInterface->ReadStart(mKBusDeviceId, mTaskId); /* lock PD-In data */
mAppDevInterface->ReadBytes(mKBusDeviceId, mTaskId, ((paTerminal->OffsetInput_bits) + (paChannel * 2)), 2, InData);
mAppDevInterface->ReadEnd(mKBusDeviceId, mTaskId); /* unlock PD-In data */
*paInDataWord = static_cast<TForteWord>((static_cast<TForteWord>(InData[1]) << 8) + (static_cast<TForteWord>(InData[0])));
}
void WagoPFCProcessInterface::CKBusHandler::writeOutputDataWordToKBus(tldkc_KbusInfo_TerminalInfo *paTerminal, TForteUInt32 paChannel,
TForteWord paOutDataWord) {
TForteByte outData[2];
outData[0] = static_cast<TForteByte>(paOutDataWord & 0x00FF);
outData[1] = static_cast<TForteByte>(paOutDataWord >> 8);
mAppDevInterface->WriteStart(mKBusDeviceId, mTaskId);
mAppDevInterface->WriteBytes(mKBusDeviceId, mTaskId, ((paTerminal->OffsetOutput_bits) + (paChannel * 2)), 2, outData);
mAppDevInterface->WriteEnd(mKBusDeviceId, mTaskId);
}
void WagoPFCProcessInterface::CKBusHandler::closeKBusInterface() {
if(0 != mAppDevInterface) {
mAppDevInterface->CloseDevice(mKBusDeviceId); // close kbus device
mAppDevInterface->Exit(); // disconnect ADI-Interface
mKBusDeviceId = scmInvalidDeviceId;
mAppDevInterface = 0;
}
}
void WagoPFCProcessInterface::CKBusHandler::enableHandler() {
}
void WagoPFCProcessInterface::CKBusHandler::disableHandler() {
}
void WagoPFCProcessInterface::CKBusHandler::setPriority(int) {
}
int WagoPFCProcessInterface::CKBusHandler::getPriority() const {
return 0;
}