From 0f4785319905b0e0ede0ac0bc96a933030040c3b Mon Sep 17 00:00:00 2001 From: "m.marn" <m.marn@gsi.de> Date: Mon, 18 Sep 2023 08:42:59 +0000 Subject: [PATCH] Refactor: Integration of PLC Actions into Block model Closes #22 See merge request silecs/opensilecs!53 --- .../interface/core/PLCRecvAction.cpp | 403 ---------- .../interface/core/PLCRecvAction.h | 74 -- .../interface/core/PLCSendAction.cpp | 382 ---------- .../interface/core/PLCSendAction.h | 74 -- .../interface/equipment/PLCBlock.cpp | 719 +++++++++++++++++- .../interface/equipment/PLCBlock.h | 45 +- .../interface/equipment/SilecsBlock.cpp | 11 - .../interface/equipment/SilecsBlock.h | 32 +- .../interface/equipment/SilecsCluster.cpp | 4 +- .../interface/equipment/SilecsCluster.h | 4 +- .../interface/equipment/SilecsDevice.cpp | 8 +- .../interface/equipment/SilecsDevice.h | 7 +- .../interface/equipment/SilecsPLC.cpp | 54 +- .../interface/equipment/SilecsPLC.h | 4 +- 14 files changed, 744 insertions(+), 1077 deletions(-) delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp deleted file mode 100644 index 85a4c0f..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#include <silecs-communication/interface/core/SilecsService.h> -#include <silecs-communication/interface/core/PLCAction.h> -#include <silecs-communication/interface/core/PLCRecvAction.h> -#include <silecs-communication/interface/communication/SilecsConnection.h> -#include <silecs-communication/interface/equipment/SilecsPLC.h> -#include <silecs-communication/interface/equipment/SilecsDevice.h> -#include <silecs-communication/interface/equipment/SilecsBlock.h> -#include <silecs-communication/interface/equipment/PLCBlock.h> -#include <silecs-communication/interface/core/Context.h> -#include <silecs-communication/interface/utility/SilecsLog.h> - -namespace Silecs -{ - -PLCRecvBlockMode::PLCRecvBlockMode(Block* block) : - PLCAction(block) -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCRecvBlockMode (create): " << block->getName(); -} - -PLCRecvBlockMode::~PLCRecvBlockMode() -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCRecvBlockMode (delete): " << theBlock_->getName(); -} - -PLCRecvDeviceMode::PLCRecvDeviceMode(Block* block) : - PLCAction(block) -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCRecvDeviceMode (create): " << theBlock_->getName(); -} - -PLCRecvDeviceMode::~PLCRecvDeviceMode() -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCRecvDeviceMode (delete): " << theBlock_->getName(); -} - -int PLCRecvBlockMode::execute(Context* pContext) -{ - timeval tod; //Time-of-day for register time-stamping - int errorCode = 0; - - Connection* pConn = theBlock_->getPLC()->getConnection(); - AccessArea area = theBlock_->getAccessArea(); - - try - { - //if transaction is for one device only, pContext contains its reference - if (pContext->isForOneDevice()) - { - //Device context: get block of one device only ==================================== - Device* pDev = pContext->getDevice(); - - //Base attributes of the device within the complete data block containing all devices. - unsigned long usedAddress = theBlock_->getAddress(); - unsigned long usedSize = theBlock_->getMemSize(); - unsigned long usedDeviceOffset = pDev->getInputAddress(area) * usedSize; - unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + usedDeviceOffset; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (theBlock_->withCustomAttributes() == true) - { - usedAddress = theBlock_->getCustomAddress(); - usedSize = theBlock_->getCustomSize(); - usedDeviceOffset = theBlock_->getCustomOffset(); - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << ", device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - } - } - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (theBlock_->getAccessArea()) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //Device context: Extract all the device registers from that block - pDev->importRegisters(theBlock_, pBuffer, tod, pContext); - - LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); - } - //end critical section - } - else - { - //Dynamic resizing of the block is not possible in BLOCK_MODE - if (theBlock_->withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); - - //Cluster/PLC context: get block of all devices in one go ========================= - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << theBlock_->getName() << ", " << deviceCol.size() << " device(s)"; - } - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Get all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Get blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data (full buffer) - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Get all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Get blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data (full buffer) - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Get all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Get blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data (full buffer) - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //PLC context: Extract all registers value of all devices of the PLC from that block - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - - // Only extract if this device actually contains this block, otherwise skip it. - if (!pDev->hasBlock(theBlock_->getName())) - { - continue; - } - unsigned long deviceOffset = pDev->getInputAddress(area) * theBlock_->getMemSize(); - unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; - pDev->importRegisters(theBlock_, pBuffer, tod, pContext); - } - - LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); - } - } - } - catch(const SilecsException& ex) - { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << theBlock_->getName() << " has failed."; - return ex.getCode(); - } - return 0; -} - -int PLCRecvDeviceMode::execute(Context* pContext) -{ - timeval tod; //Time-of-day for register time-stamping - int errorCode = 0; - Connection* pConn = theBlock_->getPLC()->getConnection(); - AccessArea area = theBlock_->getAccessArea(); - - try - { - //if transaction is for one device only, pContext contains its reference - if (pContext->isForOneDevice()) - { - //Device context: get block of one device only ==================================== - Device* pDev = pContext->getDevice(); - - //Set base attributes of the device blocks - unsigned long usedDeviceAddress = pDev->getInputAddress(area); - unsigned long usedBlockAddress = theBlock_->getAddress(); - unsigned long usedSize = theBlock_->getMemSize(); - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (theBlock_->withCustomAttributes() == true) - { - usedDeviceAddress = theBlock_->getCustomAddress(); - usedBlockAddress = theBlock_->getCustomOffset(); - usedSize = theBlock_->getCustomSize(); - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - } - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (theBlock_->getAccessArea()) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //Device context: Extract all the device registers from that block - pDev->importRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), tod, pContext); - - LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); - } - } - else - { - //Dynamic resizing of the block is not possible in multiple access - if (theBlock_->withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - //Cluster/PLC context: get block of all devices one by one ========================= - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - if (!pDev->hasBlock(theBlock_->getName())) - { - continue; - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - } - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(theBlock_->getPLC(), pDev->getInputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(theBlock_->getPLC(), pDev->getInputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(theBlock_->getPLC(), pDev->getInputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Get one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //PLC context: Extract all registers value of the current device of the PLC from that block - pDev->importRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), tod, pContext); - - LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); - } - } - } - } - catch(const SilecsException& ex) - { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed."; - return ex.getCode(); - } - return 0; -} - -} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h deleted file mode 100644 index 766619b..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#ifndef _RECV_PLC_ACTION_H_ -#define _RECV_PLC_ACTION_H_ - -#include <silecs-communication/interface/core/PLCAction.h> - -namespace Silecs -{ -class Action; -class Block; -class Context; - -/*! - * \class PLCRecvBlockMode - * \brief Concrete action responsible to get a data block from the PLC (Block mode configuration) - */ -class PLCRecvBlockMode : public PLCAction -{ - -public: - PLCRecvBlockMode(Block* block); - virtual ~PLCRecvBlockMode(); - - /*! - * \fn execute - * Connect the PLC if necessary and Get data-block from its memory. - * Overwrite the abstract method - * \return 0 if no error occurred. else return a error status from low level library - */ - int execute(Context* pContext); - -private: - -}; - -/*! - * \class PLCRecvDeviceMode - * \brief Concrete action responsible to get a data block from the PLC (Device mode configuration) - */ -class PLCRecvDeviceMode : public PLCAction -{ - -public: - PLCRecvDeviceMode(Block* block); - virtual ~PLCRecvDeviceMode(); - - /*! - * \fn execute - * Connect the PLC if necessary and Get data-block from its memory. - * Overwrite the abstract method - * \return 0 if no error occurred. else return a error status from low level library - */ - int execute(Context* pContext); - -private: - -}; - -} // namespace - -#endif // _RECV_PLC_ACTION_H_ - diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp deleted file mode 100644 index 59dc5e3..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#include <silecs-communication/interface/core/SilecsService.h> -#include <silecs-communication/interface/core/SilecsAction.h> -#include <silecs-communication/interface/core/PLCAction.h> -#include <silecs-communication/interface/core/PLCSendAction.h> -#include <silecs-communication/interface/communication/SilecsConnection.h> -#include <silecs-communication/interface/equipment/SilecsPLC.h> -#include <silecs-communication/interface/equipment/SilecsDevice.h> -#include <silecs-communication/interface/equipment/SilecsBlock.h> -#include <silecs-communication/interface/equipment/PLCBlock.h> -#include <silecs-communication/interface/core/Context.h> -#include <silecs-communication/interface/utility/SilecsLog.h> - -namespace Silecs -{ - -PLCSendBlockMode::PLCSendBlockMode(Block* block) : - PLCAction(block) -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCSendBlockMode (constructor): " << block->getName(); -} - -PLCSendBlockMode::~PLCSendBlockMode() -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCSendBlockMode (destructor): " << theBlock_->getName(); -} - -PLCSendDeviceMode::PLCSendDeviceMode(Block* block) : - PLCAction(block) -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCSendDeviceMode (constructor): " << theBlock_->getName(); -} - -PLCSendDeviceMode::~PLCSendDeviceMode() -{ - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Action PLCSendDeviceMode (destructor): " << theBlock_->getName(); -} - -int PLCSendBlockMode::execute(Context* pContext) -{ - int errorCode = 0; - Connection* pConn = theBlock_->getPLC()->getConnection(); - - try - { - //if transaction is for one device only, pContext contains its reference - if (pContext->isForOneDevice()) - { - //Device context: send block of one device only ==================================== - Device* pDev = pContext->getDevice(); - - //Base attributes of the device within the complete data block containing all devices. - unsigned long usedAddress = theBlock_->getAddress(); - unsigned long usedSize = theBlock_->getMemSize(); - AccessArea area = theBlock_->getAccessArea(); - unsigned long usedDeviceOffset = pDev->getOutputAddress(area) * usedSize; - unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + usedDeviceOffset; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (theBlock_->withCustomAttributes() == true) - { - usedAddress = theBlock_->getCustomAddress(); - usedSize = theBlock_->getCustomSize(); - usedDeviceOffset = theBlock_->getCustomOffset(); - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ BlockMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - - //Device context: Export all the device registers to that block - pDev->exportRegisters(theBlock_, pBuffer, pContext); - } - - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(theBlock_->getPLC(), usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - } - } - - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); - } - } - } - else - { - //Dynamic resizing of the block is not possible in BLOCK_MODE - if (theBlock_->withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); - - //Cluster/PLC context: set block of all devices in one go =========================== - LOG(SEND) << "SendAction (execute/ BlockMode): block: " << theBlock_->getName() << ", " << deviceCol.size() << " device(s)"; - - //PLC context: Export all registers value of all devices of the PLC to that block - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - AccessArea area = theBlock_->getAccessArea(); - unsigned long deviceOffset = pDev->getOutputAddress(area) * theBlock_->getMemSize(); - unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; - pDev->exportRegisters(theBlock_, pBuffer, pContext); - } - } - - switch (theBlock_->getAccessArea()) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Set all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Set blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data (full buffer) - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Set all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Set blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data (full buffer) - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(theBlock_->getPLC(), theBlock_->getAddress(), //Base address (or DBn) of the block - 0, //Set all devices from the first one - ((PLCBlock*)theBlock_)->getBufferSize(), //Set blocks of all devices (full buffer size) - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data (full buffer) - ); - break; - } - } - - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); - } - } - } - } - catch(const SilecsException& ex) - { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << theBlock_->getName() << " has failed"; - return ex.getCode(); - } - return errorCode; -} - -int PLCSendDeviceMode::execute(Context* pContext) -{ - Connection* pConn = theBlock_->getPLC()->getConnection(); - int errorCode = 0; - try - { - //if transaction is for one device only, pContext contains its reference - if (pContext->isForOneDevice()) - { - //Device context: set block of one device only ==================================== - Device* pDev = pContext->getDevice(); - - //Set base attributes of the device blocks - AccessArea area = theBlock_->getAccessArea(); - unsigned long usedDeviceAddress = pDev->getOutputAddress(area); - unsigned long usedBlockAddress = theBlock_->getAddress(); - unsigned long usedSize = theBlock_->getMemSize(); - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (theBlock_->withCustomAttributes() == true) - { - usedDeviceAddress = theBlock_->getCustomAddress(); - usedBlockAddress = theBlock_->getCustomOffset(); - usedSize = theBlock_->getCustomSize(); - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - - //Device context: Export all the device registers to that block - pDev->exportRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), pContext); - } - - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(theBlock_->getPLC(), usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - } - } - - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); - } - } - } - else - { - //Dynamic resizing of the block is not possible in multiple access - if (theBlock_->withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - //Cluster/PLC context: set block of all devices one by one ========================= - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = theBlock_->getPLC()->getDeviceMap(); - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - if (!pDev->hasBlock(theBlock_->getName())) - { - continue; - } - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen(theBlock_->getPLC())) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); - - //PLC context: Export all registers value of the current device of the PLC to that block - pDev->exportRegisters(theBlock_, (unsigned char*)theBlock_->getBuffer(), pContext); - } - - AccessArea area = theBlock_->getAccessArea(); - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(theBlock_->getPLC(), pDev->getOutputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(theBlock_->getPLC(), pDev->getOutputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(theBlock_->getPLC(), pDev->getOutputAddress(area), //Base address (or DBn) of the device - theBlock_->getAddress(), //Block data address within the device - theBlock_->getMemSize(), //Set one device-block only - (unsigned char*)theBlock_->getBuffer() //Buffer which contain the data - ); - break; - } - } - - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << theBlock_->getName(); - } - } - } - } - } - catch(const SilecsException& ex) - { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "SendAction (execute/ DeviceMode) failed"; - return ex.getCode(); - } - return errorCode; -} - -} // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h deleted file mode 100644 index 43b2aff..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#ifndef _PLC_SEND_ACTION_H_ -#define _PLC_SEND_ACTION_H_ - -#include <silecs-communication/interface/core/PLCAction.h> - -namespace Silecs -{ -class Action; -class Block; -class Context; - -/*! - * \class PLCSendBlockMode - * \brief Concrete action responsible to send a data block to the PLC (Block mode configuration) - */ -class PLCSendBlockMode : public PLCAction -{ - -public: - PLCSendBlockMode(Block* block); - virtual ~PLCSendBlockMode(); - - /*! - * \fn execute - * Connect the PLC if necessary and send data-block to its memory. - * Overwrite the abstract method - * \return 0 if no error occurred. else return a error status from low level library - */ - int execute(Context* pContext); - -private: - -}; - -/*! - * \class PLCSendDeviceMode - * \brief Concrete action responsible to send a data block to the PLC (Device mode configuration) - */ -class PLCSendDeviceMode : public PLCAction -{ - -public: - PLCSendDeviceMode(Block* block); - virtual ~PLCSendDeviceMode(); - - /*! - * \fn execute - * Connect the PLC if necessary and Get data-block to its memory. - * Overwrite the abstract method - * \return 0 if no error occurred. else return a error status from low level library - */ - int execute(Context* pContext); - -private: - -}; - -} // namespace - -#endif // _PLC_SEND_ACTION_H_ - diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp index f705595..120255a 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp @@ -17,12 +17,12 @@ Contributors: #include <silecs-communication/interface/equipment/SilecsBlock.h> #include <silecs-communication/interface/equipment/SilecsRegister.h> #include <silecs-communication/interface/core/SilecsAction.h> -#include <silecs-communication/interface/core/PLCRecvAction.h> -#include <silecs-communication/interface/core/PLCSendAction.h> #include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/StringUtilities.h> #include <silecs-communication/interface/equipment/PLCBlock.h> +#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> namespace Silecs { @@ -32,7 +32,7 @@ PLCBlock::PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessTy { // Create buffer for the block exchanges bufferSize_ = memSize_; //size of one block type (including alignements) - if (getPLC()->getProtocolModeID() == BlockMode) + if (thePLC_->getProtocolModeID() == BlockMode) { //BlockMode ==> access all devices in once unsigned int devicesWithBlock = getPLC()->getNrDevicesWithBlock(blockNode.getAttribute("name")); bufferSize_ *= devicesWithBlock; @@ -48,38 +48,713 @@ PLCBlock::~PLCBlock() pBuffer_ = NULL; } -InputBlock::InputBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) : - PLCBlock(thePLC, blockNode, accessType) +int PLCBlock::recvBlockMode(Context* context) { - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Block (create): " << name_ << ", plc: " << getPLC()->getName() << ", access: Input" << ", address: " << address_ << ", mem-size: " << memSize_ << ", buffer-size: " << bufferSize_; + timeval tod; //Time-of-day for register time-stamping + int errorCode = 0; - // Creates receive task which relies on the block exchange - if (getPLC()->getProtocolModeID() == BlockMode) - pAction_ = new PLCRecvBlockMode(this); - else - pAction_ = new PLCRecvDeviceMode(this); + Connection* pConn = thePLC_->getConnection(); + AccessArea area = accessArea_; + + try + { + //if transaction is for one device only, context contains its reference + if (context->isForOneDevice()) + { + //Device context: get block of one device only ==================================== + Device* pDev = context->getDevice(); + + //Base attributes of the device within the complete data block containing all devices. + unsigned long usedAddress = address_; + unsigned long usedSize = memSize_; + unsigned long usedDeviceOffset = pDev->getInputAddress(area) * usedSize; + unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) + { + usedAddress = customAddress_; + usedSize = customSize_; + usedDeviceOffset = customOffset_; + } + + if (RECV & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << ", device: " << pDev->getLabel() << ", block: " << name_; + } + } + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + //begin critical section + std::lock_guard<std::mutex> lock(bufferMux_); + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = pConn->readDIO(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Get one device-block only + pBuffer //Buffer to store the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->readAIO(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Get one device-block only + pBuffer //Buffer to store the data + ); + break; + } + case AccessArea::Memory: + default: + { + errorCode = pConn->readMemory(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Get one device-block only + pBuffer //Buffer to store the data + ); + break; + } + } + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //Device context: Extract all the device registers from that block + pDev->importRegisters(this, pBuffer, tod, context); + + LOG_DELAY(RECV) << "done for block: " << name_; + } + //end critical section + } + else + { + //Dynamic resizing of the block is not possible in BLOCK_MODE + if (withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = thePLC_->getDeviceMap(); + + //Cluster/PLC context: get block of all devices in one go ========================= + if (RECV & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << name_ << ", " << deviceCol.size() << " device(s)"; + } + } + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + //begin critical section + std::lock_guard<std::mutex> lock(bufferMux_); + switch (area) + { + case AccessArea::Digital: + errorCode = pConn->readDIO(thePLC_, address_, //Base address (or DBn) of the block + 0, //Get all devices from the first one + bufferSize_, //Get blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->readAIO(thePLC_, address_, //Base address (or DBn) of the block + 0, //Get all devices from the first one + bufferSize_, //Get blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) + ); + break; + } + case AccessArea::Memory: + default: + { + errorCode = pConn->readMemory(thePLC_, address_, //Base address (or DBn) of the block + 0, //Get all devices from the first one + bufferSize_, //Get blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) + ); + break; + } + } + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of all devices of the PLC from that block + for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + + // Only extract if this device actually contains this block, otherwise skip it. + if (!pDev->hasBlock(name_)) + { + continue; + } + unsigned long deviceOffset = pDev->getInputAddress(area) * memSize_; + unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset; + pDev->importRegisters(this, pBuffer, tod, context); + } + + LOG_DELAY(RECV) << "done for block: " << name_; + } + } + } + catch(const SilecsException& ex) + { + LOG(ERROR) << ex.what(); + LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << name_ << " has failed."; + return ex.getCode(); + } + return 0; } -InputBlock::~InputBlock() +int PLCBlock::recvDeviceMode(Context* context) { + timeval tod; //Time-of-day for register time-stamping + int errorCode = 0; + Connection* pConn = thePLC_->getConnection(); + + try + { + //if transaction is for one device only, context contains its reference + if (context->isForOneDevice()) + { + //Device context: get block of one device only ==================================== + Device* pDev = context->getDevice(); + + //Set base attributes of the device blocks + unsigned long usedDeviceAddress = pDev->getInputAddress(accessArea_); + unsigned long usedBlockAddress = address_; + unsigned long usedSize = memSize_; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) + { + usedDeviceAddress = customAddress_; + usedBlockAddress = customOffset_; + usedSize = customSize_; + } + + if (RECV & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; + } + } + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + //begin critical section + std::lock_guard<std::mutex> lock(bufferMux_); + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = pConn->readDIO(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->readAIO(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + } + case AccessArea::Memory: + default: + { + errorCode = pConn->readMemory(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + } + } + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //Device context: Extract all the device registers from that block + pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context); + + LOG_DELAY(RECV) << "done for block: " << name_; + } + } + else + { + //Dynamic resizing of the block is not possible in multiple access + if (withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + //Cluster/PLC context: get block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = thePLC_->getDeviceMap(); + for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + if (!pDev->hasBlock(name_)) + { + continue; + } + + if (RECV & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; + } + } + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + //begin critical section + std::lock_guard<std::mutex> lock(bufferMux_); + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = pConn->readDIO(thePLC_, pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->readAIO(thePLC_, pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + } + case AccessArea::Memory: + default: + { + errorCode = pConn->readMemory(thePLC_, pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Get one device-block only + (unsigned char*)pBuffer_ //Buffer to store the data + ); + break; + } + } + + if (pConn->isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of the current device of the PLC from that block + pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context); + + LOG_DELAY(RECV) << "done for block: " << name_; + } + } + } + } + catch(const SilecsException& ex) + { + LOG(ERROR) << ex.what(); + LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed."; + return ex.getCode(); + } + return 0; } -OutputBlock::OutputBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) : - PLCBlock(thePLC, blockNode, accessType) +int PLCBlock::sendBlockMode(Context* context) { - if (DEBUG & Log::topics_) - LOG(ALLOC) << "Block (create): " << name_ << ", plc: " << getPLC()->getName() << ", access: Output" << ", address: " << address_ << ", mem-size: " << memSize_ << ", buffer-size: " << bufferSize_; + int errorCode = 0; + Connection* pConn = thePLC_->getConnection(); + + try + { + //if transaction is for one device only, context contains its reference + if (context->isForOneDevice()) + { + //Device context: send block of one device only ==================================== + Device* pDev = context->getDevice(); + + //Base attributes of the device within the complete data block containing all devices. + unsigned long usedAddress = address_; + unsigned long usedSize = memSize_; + AccessArea area = accessArea_; + unsigned long usedDeviceOffset = pDev->getOutputAddress(area) * usedSize; + unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) + { + usedAddress = customAddress_; + usedSize = customSize_; + usedDeviceOffset = customOffset_; + } - // Creates send task which relies on the block exchange - if (getPLC()->getProtocolModeID() == BlockMode) - pAction_ = new PLCSendBlockMode(this); + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + { //critical section + std::lock_guard<std::mutex> lock(bufferMux_); + if (pConn->isEnabled()) + { + LOG(SEND) << "SendAction (execute/ BlockMode): device: " << pDev->getLabel() << ", block: " << name_; + + //Device context: Export all the device registers to that block + pDev->exportRegisters(this, pBuffer, context); + } + + switch (area) + { + case AccessArea::Digital: + errorCode = pConn->writeDIO(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Set one device-block only + pBuffer //Buffer which contain the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->writeAIO(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Set one device-block only + pBuffer //Buffer which contain the data + ); + break; + } + case AccessArea::Memory: + default: + errorCode = pConn->writeMemory(thePLC_, usedAddress, //Base address (or DBn) of the block + usedDeviceOffset, //Device data address within the block + usedSize, //Set one device-block only + pBuffer //Buffer which contain the data + ); + break; + } + } + + if (SEND & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(SEND).getLogDelay() << "done for block: " << name_; + } + } + } + else + { + //Dynamic resizing of the block is not possible in BLOCK_MODE + if (withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + { //critical section + std::lock_guard<std::mutex> lock(bufferMux_); + if (pConn->isEnabled()) + { + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = thePLC_->getDeviceMap(); + + //Cluster/PLC context: set block of all devices in one go =========================== + LOG(SEND) << "SendAction (execute/ BlockMode): block: " << name_ << ", " << deviceCol.size() << " device(s)"; + + //PLC context: Export all registers value of all devices of the PLC to that block + for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + AccessArea area = accessArea_; + unsigned long deviceOffset = pDev->getOutputAddress(area) * memSize_; + unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset; + pDev->exportRegisters(this, pBuffer, context); + } + } + + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = pConn->writeDIO(thePLC_, address_, //Base address (or DBn) of the block + 0, //Set all devices from the first one + bufferSize_, //Set blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->writeAIO(thePLC_, address_, //Base address (or DBn) of the block + 0, //Set all devices from the first one + bufferSize_, //Set blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) + ); + break; + } + case AccessArea::Memory: + default: + errorCode = pConn->writeMemory(thePLC_, address_, //Base address (or DBn) of the block + 0, //Set all devices from the first one + bufferSize_, //Set blocks of all devices (full buffer size) + (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) + ); + break; + } + } + + if (SEND & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(SEND).getLogDelay() << "done for block: " << name_; + } + } + } + } + catch(const SilecsException& ex) + { + LOG(ERROR) << ex.what(); + LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << name_ << " has failed"; + return ex.getCode(); + } + return errorCode; +} + +int PLCBlock::sendDeviceMode(Context* context) +{ + Connection* pConn = thePLC_->getConnection(); + int errorCode = 0; + try + { + //if transaction is for one device only, context contains its reference + if (context->isForOneDevice()) + { + //Device context: set block of one device only ==================================== + Device* pDev = context->getDevice(); + + //Set base attributes of the device blocks + AccessArea area = accessArea_; + unsigned long usedDeviceAddress = pDev->getOutputAddress(area); + unsigned long usedBlockAddress = address_; + unsigned long usedSize = memSize_; + + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) + { + usedDeviceAddress = customAddress_; + usedBlockAddress = customOffset_; + usedSize = customSize_; + } + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + { //critical section + std::lock_guard<std::mutex> lock(bufferMux_); + if (pConn->isEnabled()) + { + LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; + + //Device context: Export all the device registers to that block + pDev->exportRegisters(this, (unsigned char*)pBuffer_, context); + } + + switch (area) + { + case AccessArea::Digital: + errorCode = pConn->writeDIO(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->writeAIO(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + } + case AccessArea::Memory: + default: + errorCode = pConn->writeMemory(thePLC_, usedDeviceAddress, //Base address (or DBn) of the device + usedBlockAddress, //Block data address within the device + usedSize, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + } + } + + if (SEND & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(SEND).getLogDelay() << "done for block: " << name_; + } + } + } + else + { + //Dynamic resizing of the block is not possible in multiple access + if (withCustomAttributes() == true) + throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); + + //Cluster/PLC context: set block of all devices one by one ========================= + deviceVectorType::iterator pDeviceIter; + deviceVectorType& deviceCol = thePLC_->getDeviceMap(); + for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + { + Device* pDev = pDeviceIter->second; + if (!pDev->hasBlock(name_)) + { + continue; + } + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!pConn->doOpen(thePLC_)) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + { //critical section + std::lock_guard<std::mutex> lock(bufferMux_); + if (pConn->isEnabled()) + { + LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; + + //PLC context: Export all registers value of the current device of the PLC to that block + pDev->exportRegisters(this, (unsigned char*)pBuffer_, context); + } + + AccessArea area = accessArea_; + switch (area) + { + case AccessArea::Digital: + errorCode = pConn->writeDIO(thePLC_, pDev->getOutputAddress(area), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + case AccessArea::Analog: + { + errorCode = pConn->writeAIO(thePLC_, pDev->getOutputAddress(area), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + } + case AccessArea::Memory: + default: + errorCode = pConn->writeMemory(thePLC_, pDev->getOutputAddress(area), //Base address (or DBn) of the device + address_, //Block data address within the device + memSize_, //Set one device-block only + (unsigned char*)pBuffer_ //Buffer which contain the data + ); + break; + } + } + + if (SEND & Log::topics_) + { + if (pConn->isEnabled()) + { + Log(SEND).getLogDelay() << "done for block: " << name_; + } + } + } + } + } + catch(const SilecsException& ex) + { + LOG(ERROR) << ex.what(); + LOG(ERROR) << "SendAction (execute/ DeviceMode) failed"; + return ex.getCode(); + } + return errorCode; +} + +int PLCBlock::send(Context* context) +{ + if (accessType_ == AccessType::Acquisition) + { + throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH); + } + + if (thePLC_->getProtocolModeID() == BlockMode) + { + return sendBlockMode(context); + } else - pAction_ = new PLCSendDeviceMode(this); + { + return sendDeviceMode(context); + } } -OutputBlock::~OutputBlock() +int PLCBlock::receive(Context* context) { + if (accessType_ == AccessType::Command) + { + throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH); + } + + if (thePLC_->getProtocolModeID() == BlockMode) + { + return recvBlockMode(context); + } + else + { + return recvDeviceMode(context); + } } } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h index fa7be69..ebf452b 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h @@ -20,50 +20,33 @@ Contributors: namespace Silecs { +class Context; + class PLCBlock : public Block { public: PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); - ~PLCBlock(); + virtual ~PLCBlock(); - unsigned long getBufferSize() const - { - return bufferSize_; - } + int send(Context* context) override; + int receive(Context* context) override; protected: friend class Device; + int recvBlockMode(Context* context); + int recvDeviceMode(Context* context); + int sendBlockMode(Context* context); + int sendDeviceMode(Context* context); + /// Send/Receive data size (size of block * nb of device) unsigned long bufferSize_; -}; - -/*! ----------------------------------------------------------------------- - * \class InputBlock - * \brief This is a specific Block for Acquisition data (from PLC to client) - */ -class InputBlock : public PLCBlock -{ - -public: - InputBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); - virtual ~InputBlock(); - -}; - -/*! ----------------------------------------------------------------------- - * \class OutputBlock - * \brief This is a specific Block for Settings (from client to PLC) - */ -class OutputBlock : public PLCBlock -{ - -public: - OutputBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); - virtual ~OutputBlock(); - +private: + //The frame buffer update (import/export registers) and related read/write data must be done + //in a critical section (the same buffer is used to send/recv data to all devices). + std::mutex bufferMux_; }; } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp index df65ac0..10e521c 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp @@ -43,9 +43,6 @@ Block::Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) : resetCustomAttributes(); //by default custom-size of the block is the maximum size - /*In case of InOut block we will instantiate 2 different blocks (input/output) - * and the accessType is given by the caller. - */ accessType_ = accessType; } @@ -53,9 +50,6 @@ Block::~Block() { if (DEBUG & Log::topics_) LOG(ALLOC) << "Block (delete): " << name_; - - if (pAction_ != NULL) - delete pAction_; } AccessType Block::whichAccessType(std::string type) @@ -134,11 +128,6 @@ void Block::setCustomAttributes(const unsigned long customAddress, const unsigne LOG(DEBUG) << "Set custom attributes of block: " << name_ << ", memSize: " << memSize_ << ", customSize: " << customSize << ", customAddress: " << customAddress << ", customOffset: " << customOffset; } -Action* Block::getAction() const -{ - return pAction_; -} - void Block::resetCustomAttributes() { customAttributes_ = false; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h index 1f89ee8..722a74a 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h @@ -38,6 +38,9 @@ public: Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); virtual ~Block(); + virtual int receive(Context* context) = 0; + virtual int send(Context* context) = 0; + /*! * \fn whichAccessType * \return the enumeration value of the given access-type string @@ -80,20 +83,6 @@ public: { return (accessArea_); } - unsigned long getAddress() const - { - return address_; - } - unsigned long getMemSize() const - { - return memSize_; - } - void* getBuffer() - { - return pBuffer_; - } - - Action* getAction() const; /// @cond void setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); @@ -102,18 +91,6 @@ public: { return customAttributes_; } - unsigned long getCustomAddress() const - { - return customAddress_; - } - unsigned long getCustomOffset() const - { - return customOffset_; - } - unsigned long getCustomSize() const - { - return customSize_; - } /// @endcond protected: @@ -153,9 +130,6 @@ protected: unsigned long address_; - /// Related PLC task to this data-block - Action* pAction_; - // Send/Receive data buffer void *pBuffer_; }; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp index e9a9884..2ec9ed1 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp @@ -97,9 +97,9 @@ bool Cluster::getAddressByHostName(const std::string hostName, std::string& IPAd return false; } -Block* Cluster::getBlock(const std::string blockName, AccessType accessType) +Block* Cluster::getBlock(const std::string blockName) { // Retrieve the block from the first PLC (same for each of them) - return plcMap_.begin()->second->getBlock(blockName, accessType); + return plcMap_.begin()->second->getBlock(blockName); } std::string Cluster::getBlockList(AccessType accessType) diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h index aaf3d6d..aa68187 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h @@ -142,9 +142,9 @@ private: /*! * \fn getBlock - * \brief returns one instance of the requested block checking its access-type + * \brief returns instance of the requested block */ - Block* getBlock(const std::string blockName, AccessType accessType = AccessType::Setting); + Block* getBlock(const std::string blockName); /// Store the current FEC name std::string hostName_; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp index de342e1..d324d6d 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp @@ -119,7 +119,7 @@ int Device::recv(const std::string& blockName) Context context(this, false); //Execute the receive action for the required device (from the current thread) - return getBlock(blockName, AccessType::Acquisition)->getAction()->execute(&context); + return getBlock(blockName)->receive(&context); } int Device::send(const std::string& blockName) @@ -132,7 +132,7 @@ int Device::send(const std::string& blockName) Context context(this, false); //Execute the receive action for the required device (from the current thread) - return getBlock(blockName, AccessType::Command)->getAction()->execute(&context); + return getBlock(blockName)->send(&context); } std::string Device::getLabel() const @@ -203,7 +203,7 @@ void Device::instantiateRegisters(const std::string& blockName, AccessType acces blockRegisterMap_.insert(std::make_pair(blockName, registerCol)); } -Block* Device::getBlock(const std::string& blockName, AccessType accessType) +Block* Device::getBlock(const std::string& blockName) { if (!hasBlock(blockName)) { @@ -211,7 +211,7 @@ Block* Device::getBlock(const std::string& blockName, AccessType accessType) errorMessage << "Block not found! The block '" << blockName << "' does not exist on the device '" << label_ << "'."; throw SilecsException(__FILE__, __LINE__, errorMessage.str()); } - return thePLC_->getBlock(blockName, accessType); + return thePLC_->getBlock(blockName); } bool Device::hasBlock(const std::string& blockName) diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h index 4c7d6c0..2eb7916 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h @@ -107,10 +107,7 @@ private: friend class PLC; friend class Register; friend class PLCRegister; - friend class PLCRecvBlockMode; - friend class PLCRecvDeviceMode; - friend class PLCSendBlockMode; - friend class PLCSendDeviceMode; + friend class PLCBlock; friend class Context; friend class CNVRegister; @@ -148,7 +145,7 @@ private: * \fn getBlock * \brief returns one instance of the requested block checking its access-type */ - Block* getBlock(const std::string& blockName, AccessType accessType = AccessType::Setting); + Block* getBlock(const std::string& blockName); bool hasBlock(const std::string& blockName); diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp index 6419f53..b8e8a98 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp @@ -377,26 +377,26 @@ int PLC::recv(const std::string& blockName) { //Synchronous data receive //Execute the receive action for all the PLC devices (from the current thread) - return getBlock(blockName, AccessType::Acquisition)->getAction()->execute(allDevicesTransaction_); + return getBlock(blockName)->receive(allDevicesTransaction_); } int PLC::send(const std::string& blockName) { //Synchronous data send //Execute the send action for all the PLC devices (from the current thread) - return getBlock(blockName, AccessType::Command)->getAction()->execute(allDevicesTransaction_); + return getBlock(blockName)->send(allDevicesTransaction_); } std::future<int> PLC::recvAsync(const std::string& blockName) { //Schedule task using asynchronous call - return std::async(std::launch::async, &Action::execute, getBlock(blockName, AccessType::Acquisition)->getAction(), allDevicesTransaction_); + return std::async(std::launch::async, &Block::receive, getBlock(blockName), allDevicesTransaction_); } std::future<int> PLC::sendAsync(const std::string& blockName) { //Schedule task using asynchronous call - return std::async(std::launch::async, &Action::execute, getBlock(blockName, AccessType::Command)->getAction(), allDevicesTransaction_); + return std::async(std::launch::async, &Block::send, getBlock(blockName), allDevicesTransaction_); } void PLC::extractDatabase() @@ -490,36 +490,18 @@ void PLC::extractDatabase() AccessType accessType = Block::whichAccessType( (*blockIter).getName()); LOG((DIAG)) << "The block '" << blockName << " of type '" << (*blockIter).getName() << "' will be created."; - Block* pBlock = 0; - // Instantiate Input blocks ------------------------------------------------------ - if (accessType == AccessType::Acquisition || accessType == AccessType::Setting) - { //Instantiate the block, forcing it to Acquisition access for Setting case - - if (brandID_ == Ni) + if (brandID_ == Ni) + { #ifdef NI_SUPPORT_ENABLED - pBlock = new CNVInputBlock(this, (*pBlockElCol)[i], accessType); + // TODO: Implement blocks in the same way as done for PLCBlock. + throw SilecsException(__FILE__, __LINE__, "CNV Blocks not implemented"); #else - throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); + throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); #endif - else - pBlock = new InputBlock(this, *blockIter, AccessType::Acquisition); - blockCol_.push_back(pBlock); // FIXME: Currently a block is instatiated twice if it is READ+WRITE - } - // Instantiate Output blocks ------------------------------------------------------ - if (accessType == AccessType::Command || accessType == AccessType::Setting) - { //Instantiate the block, forcing it to Command access for Setting case - if (brandID_ == Ni) -#ifdef NI_SUPPORT_ENABLED - pBlock = new CNVOutputBlock(this, (*pBlockElCol)[i], accessType); -#else - throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); -#endif - else - pBlock = new OutputBlock(this, *blockIter, AccessType::Command); - blockCol_.push_back(pBlock); // FIXME: Currently a block is instatiated twice if it is READ+WRITE - } + Block* pBlock = new PLCBlock(this, *blockIter, accessType); + blockCol_.push_back(pBlock); //Force BusController type (with SilecsHeader check), if there is at least one Memory block defined if (pBlock->getAccessArea() == AccessArea::Memory) @@ -574,15 +556,15 @@ Connection* PLC::getConnection() return plcConn_; } -Block* PLC::getBlock(const std::string& blockName, AccessType accessType) const +Block* PLC::getBlock(const std::string& blockName) const { for (auto block = blockCol_.begin(); block != blockCol_.end(); block++) { - if ( (*block)->getName() == blockName && (*block)->getAccessType() == accessType) + if ( (*block)->getName() == blockName) return *block; } std::ostringstream error; - error << "The block '" << blockName << "' was not found for the access type: '" << Block::whichAccessType(accessType) << "'"; + error << "The block '" << blockName << "' was not found."; throw SilecsException(__FILE__, __LINE__, error.str()); } @@ -723,24 +705,24 @@ void PLC::setReadBlockAttributes(const std::string& blockName, const unsigned lo { //Set the custom offset/size of the referred Input block if any. //Will throw an exception if that block-name does not exist. - getBlock(blockName, AccessType::Acquisition)->setCustomAttributes(customAddress, customOffset, customSize); + getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize); } void PLC::resetReadBlockAttributes(const std::string& blockName) { - getBlock(blockName, AccessType::Acquisition)->resetCustomAttributes(); + getBlock(blockName)->resetCustomAttributes(); } void PLC::setWriteBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) { //Set the custom address/offset/size of the referred Output block if any. //Will throw an exception if that block-name does not exist. - getBlock(blockName, AccessType::Command)->setCustomAttributes(customAddress, customOffset, customSize); + getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize); } void PLC::resetWriteBlockAttributes(const std::string& blockName) { - getBlock(blockName, AccessType::Command)->resetCustomAttributes(); + getBlock(blockName)->resetCustomAttributes(); } } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h index 3ba2a76..062606c 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h @@ -297,9 +297,9 @@ public: /*! * \fn getBlock - * \brief returns one instance of the requested block checking its access-type + * \brief returns instance of the requested block */ - Block* getBlock(const std::string& blockName, AccessType accessType) const; + Block* getBlock(const std::string& blockName) const; /*! * \brief Used to Enable the Client/PLC connection and connect the PLC immediately if needed (connectNow=true). -- GitLab