From e24e76d7004ebeebc7bea053cf91cd212255867d Mon Sep 17 00:00:00 2001 From: aschwinn <al.schwinn@gsi.de> Date: Wed, 26 Jul 2017 09:28:21 +0200 Subject: [PATCH] [SIL-279] RIO support: Upgrade the silecs-communication library --- .../interface/communication/MBConnection.cpp | 3 ++- .../interface/core/SilecsService.h | 9 ++++++- .../interface/equipment/PLCRegister.cpp | 2 +- .../interface/equipment/SilecsBlock.cpp | 27 +++++++++++++++++++ .../interface/equipment/SilecsBlock.h | 14 ++++++++++ .../interface/equipment/SilecsDevice.cpp | 10 ++++--- .../interface/equipment/SilecsDevice.h | 2 +- .../interface/equipment/SilecsPLC.cpp | 23 +++++++++------- .../interface/equipment/SilecsPLC.h | 23 +++++++++++----- .../interface/equipment/SilecsRegister.cpp | 12 ++++++++- .../interface/equipment/SilecsRegister.h | 27 +++++++++++++++++++ .../interface/utility/SilecsException.cpp | 12 ++++++--- .../interface/utility/SilecsException.h | 3 ++- .../src/silecs-diagnostic/main.cpp | 1 + 14 files changed, 139 insertions(+), 29 deletions(-) diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp index 6b694e4..e99ee89 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp @@ -44,7 +44,8 @@ namespace Silecs modbus_set_response_timeout(writeCtx_ , &response_timeout); */ - //modbus_set_debug(*ctx, TRUE); + modbus_set_slave(readCtx_, 1); + //modbus_set_debug(readCtx_, TRUE); } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h index b2efc12..d8eb008 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h @@ -33,7 +33,14 @@ namespace Silecs Input, InOut } AccessType; - /// @endcond READ-ONLY / WRITE-ONLY / READ-WRITE + + // Register and Block access types + typedef enum + { + Memory, Digital, Analog + } AccessArea; + /// @endcond + /*! * \brief Defines the category of the SILECS Exception. diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp index 7339f5a..69a32c5 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp @@ -63,7 +63,7 @@ namespace Silecs void *pl = &l; void *pul = &ul; - if ( (getPLC()->getModel() == "BC9020") && (getFormat() == Silecs::Float32) ) + if ( (getPLC()->getModelID() == BC9xxx) && (getFormat() == Silecs::Float32) ) { //Particular case for BC9020 PLC: swap only bytes together (not the words) *((uint16_t *)pul) = _swaps(*((uint16_t *)pl)); *((uint16_t *)pul+1) = _swaps(*((uint16_t *)pl+1)); 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 44667bf..292cf26 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp @@ -37,6 +37,10 @@ namespace Silecs StringUtilities::fromString(size_,blockNode.getAttribute("size")); StringUtilities::fromString(memSize_,blockNode.getAttribute("mem-size")); StringUtilities::fromString(address_,blockNode.getAttribute("address")); + if( blockNode.hasAttribute("ioType") ) // only IO-Blocks have this attribute + accessArea_ = Block::whichAccessArea(blockNode.getAttribute("ioType")); + else + accessArea_ = Memory; resetCustomAttributes(); //by default custom-size of the block is the maximum size @@ -60,6 +64,8 @@ namespace Silecs if (type == "Acquisition-Block") return Input; else if (type == "Command-Block") return Output; else if (type == "Setting-Block") return InOut; + else if (type == "Setting-IO-Block") return InOut; + else if (type == "Acquisition-IO-Block") return Input; else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_ACCESS_TYPE, type); } @@ -75,6 +81,27 @@ namespace Silecs } } + AccessArea Block::whichAccessArea(std::string area) + { + StringUtilities::toLower(area); + if (area == "memory") return Memory; + else if (area == "digital-io") return Digital; + else if (area == "analog-io") return Analog; + else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_ACCESS_AREA, area); + } + + + std::string Block::whichAccessArea(AccessArea area) + { + switch(area) + { + case Memory: return "MEMORY"; break; + case Digital: return "DIGITAL-IO"; break; + case Analog: return "ANALOG-IO"; break; + default: throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_ACCESS_AREA, StringUtilities::toString(area)); + } + } + void Block::setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) { //user wants to limit the size of data to be sent/receive - check that it is lower than design allocation size 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 a0cdfb6..acd015f 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h @@ -49,12 +49,23 @@ namespace Silecs static AccessType whichAccessType(std::string type); static std::string whichAccessType(AccessType type); + /*! + * \fn whichAccessArea + * \return the enumeration value of the given access-area string + */ + static AccessArea whichAccessArea(std::string area); + static std::string whichAccessArea(AccessArea area); + + inline bool hasInputAccess() { return (accessType_ != Output); } + inline bool hasOutputAccess() { return (accessType_ != Input); } + inline bool isReadable() { return (accessType_ != Output); } inline bool isWritable() { return (accessType_ != Input); } inline PLC* getPLC() { return thePLC_; } inline std::string& getName() { return name_; } inline AccessType getAccessType() { return (accessType_); } + inline AccessArea getAccessArea() { return (accessArea_); } inline unsigned long& getAddress() { return address_; } inline unsigned long& getMemSize() { return memSize_; } inline Task<WrapperAction>* getTask() { return pTask_; } @@ -81,6 +92,9 @@ namespace Silecs /// Block access-type: Input, Output or InOut AccessType accessType_; + /// Block access-type: Memory, Digital or Analog + AccessArea accessArea_; + /// Block size unsigned long size_; 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 0888525..1840df0 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp @@ -47,8 +47,11 @@ namespace Silecs std::string blockName = blockIter->getAttribute("name"); LOG(ALLOC) << "Adding Block to Device: " << blockName; AccessType accessType = Block::whichAccessType(blockIter->name_); + AccessArea accessArea = Memory; + if( blockIter->hasAttribute("ioType") ) // only IO-Blocks have this attribute + accessArea = Block::whichAccessArea(blockIter->getAttribute("ioType")); std::vector< boost::shared_ptr<ElementXML> > registerNodes = blockIter->childList_; - instantiateRegisters(blockName, accessType, registerNodes); + instantiateRegisters(blockName, accessType, accessArea, registerNodes); } } @@ -172,7 +175,7 @@ namespace Silecs } - void Device::instantiateRegisters(std::string blockName, AccessType accessType, std::vector< boost::shared_ptr<ElementXML> >& registerNodes) + void Device::instantiateRegisters(std::string blockName, AccessType accessType, AccessArea accessArea, std::vector< boost::shared_ptr<ElementXML> >& registerNodes) { std::vector<Register*> registerCol; @@ -183,7 +186,8 @@ namespace Silecs { std::string registerName = (*registerIter)->getAttribute("name"); Register* pReg = instantiateRegister(*registerIter); - pReg->setAccessType(accessType); + pReg->setAccessArea(accessArea); + pReg->setAccessType(accessType); pReg->setBlockName(blockName); registerCol.push_back(pReg); registerCol_.push_back(std::make_pair(registerName, pReg)); 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 6c100e7..7bd8f97 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h @@ -131,7 +131,7 @@ namespace Silecs Register* instantiateRegister(const boost::shared_ptr<ElementXML>& registerNode); - void instantiateRegisters(std::string blockName, AccessType accessType, std::vector< boost::shared_ptr<ElementXML> >& registerNodes); + void instantiateRegisters(std::string blockName, AccessType accessType, AccessArea accessArea, std::vector< boost::shared_ptr<ElementXML> >& registerNodes); /*! * \fn getBlock 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 0c49b45..b84af33 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp @@ -126,8 +126,7 @@ namespace Silecs // Thus, even if the PLC is off and rejects the first connection to upload the Header (see updateHeader), // we will automatically attempt to reconnect later at the next PLC accesses (send/recv) ... again and again. plcConn_->enable(this, connectNow); - - if( compareChecksums ) + if( getTypeID() != BusCoupler && compareChecksums ) { /* PLC memory could have change during a disconnection time (downloading or other). The Header registers must be reloaded for consistency checking. @@ -145,7 +144,8 @@ namespace Silecs } //Warn ACET service that a new connection is established (except for SilecsHeader) - if (theHeader_ != NULL) { + if (theHeader_ != NULL) + { TRACE("info") << "Connection setup: ClassName=" << theCluster_->getClassName() << ", " << "ClassVersion=" << theCluster_->getClassVersion() << ", " << "Owner=" << localOwner_ << ", " << @@ -379,6 +379,7 @@ namespace Silecs model_ = mappingNode.getAttribute("plc-model"); StringUtilities::fromString(baseAddr_,mappingNode.getAttribute("address") ); usedMem_ = mappingNode.getAttribute("used-mem"); + typeID_ = whichPLCType(model_); brandID_ = whichPLCBrand(brand_); modelID_ = whichPLCModel(model_); systemID_ = whichPLCSystem(system_); @@ -552,9 +553,14 @@ namespace Silecs throw SilecsException(__FILE__, __LINE__, error.str()); } - blockVectorType& PLC::getBlockCol() { return blockCol_; } + PLCType PLC::whichPLCType(std::string model) + { + StringUtilities::toLower(model); + if (model.find("bk9") == 0) return BusCoupler; + return BusController; + } PLCBrand PLC::whichPLCBrand(std::string brand) { @@ -580,8 +586,9 @@ namespace Silecs else if (model == "premium") return Premium; else if (model == "quantum") return Quantum; else if (model == "m340") return M340; - else if (model == "bc9020") return BC9020; - else if (model == "cx9020") return CX9020; + else if (model.find("bc9") == 0) return BC9xxx; + else if (model.find("cx9") == 0) return CX9xxx; + else if (model.find("bk9") == 0) return BK9xxx; else if (model == "rabbit_rcm_4010") return RCM4010; else if (model == "rabbit_rcm_2000") return RCM2000; else if (model == "compact_rio") return CompactRIO; @@ -594,7 +601,7 @@ namespace Silecs PLCSystem PLC::whichPLCSystem(std::string system) { - StringUtilities::toLower(system); + StringUtilities::toLower(system); if (system == "step-7") return Step7; else if (system == "tia-portal") return TiaPortal; else if (system == "snap7 linux32") return ServerS7; @@ -606,7 +613,6 @@ namespace Silecs else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_SYSTEM, system); } - ProtocolType PLC::whichProtocolType(std::string system) { StringUtilities::toLower(system); @@ -621,7 +627,6 @@ namespace Silecs else throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_SYSTEM, system); } - ProtocolMode PLC::whichProtocolMode(std::string mode) { StringUtilities::toLower(mode); 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 174fbe9..b3387d2 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h @@ -36,6 +36,12 @@ namespace Silecs typedef std::vector<Block*> blockVectorType; typedef std::map<std::string, Connection*> connMapType; + // PLC type, brand, system, protocol type and mode + typedef enum + { + BusController, BusCoupler + } PLCType; + // PLC brand, system, protocol type and mode typedef enum { @@ -46,9 +52,8 @@ namespace Silecs { ET200S, S7300, S7400, S71200, S71500, S7VIRTUAL, - Premium, Quantum, - M340, - BC9020, CX9020, + Premium, Quantum, M340, + BC9xxx, CX9xxx, BK9xxx, RCM4010, RCM2000, CompactRIO, PXIRT, PXIWindows, PCWindows, OtherSupportCNV @@ -367,6 +372,7 @@ namespace Silecs friend class InputBlock; friend class OutputBlock; friend class PLCRegister; + friend class TwinCATRegister; friend class PLCRecvBlockMode; friend class PLCRecvDeviceMode; friend class PLCSendBlockMode; @@ -385,6 +391,7 @@ namespace Silecs PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, string parameterFile = ""); virtual ~PLC(); + inline PLCType& getTypeID() { return typeID_; } inline PLCBrand& getBrandID() { return brandID_; } inline PLCModel& getModelID() { return modelID_; } inline PLCSystem& getSystemID() { return systemID_; } @@ -424,6 +431,7 @@ namespace Silecs * \fn whichPLC, whichProtocol... * \return the enumeration value of the given Protocol type/mode string */ + static PLCType whichPLCType(std::string model); //BusController, BusCoupler static PLCBrand whichPLCBrand(std::string brand); //SIEMENS, SCHNEIDER, BECKHOFF, ... static PLCModel whichPLCModel(std::string model); //S7-400, S7-300, ... static PLCSystem whichPLCSystem(std::string system); //STEP-7, UNITY, TWINCAT, ... @@ -460,13 +468,14 @@ namespace Silecs /// PLC attributes std::string name_; std::string IPaddr_; - std::string domain_; //TST, ADE, PSB, CPS, .. - std::string brand_; //SIEMENS, SCHNEIDER, .. - std::string system_; //STEP-7, UNITY, TWINCAT, .. - std::string model_; //SIMATIC S7-300, Premium, .. + std::string domain_; //TST, ADE, PSB, CPS, .. + std::string brand_; //SIEMENS, SCHNEIDER, .. + std::string system_; //STEP-7, UNITY, TWINCAT, .. + std::string model_; //SIMATIC S7-300, Premium, .. std::string protocolMode_; //Device, Block std::string protocolType_; //MODBUS-TCP, S7-TCP, .. + PLCType typeID_; //BusController (with CPU), BusCoupler (pure IO) PLCBrand brandID_; //Siemens, Schneider, ... enumeration PLCModel modelID_; //S7-400, S7-300, ... enumeration PLCSystem systemID_; //Step7, Unity, TwinCat, ... enumeration diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp index 5b4bf90..3929c08 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp @@ -383,6 +383,12 @@ namespace Silecs double* Register::getRefFloat64Array2D(uint32_t& dim1, uint32_t& dim2) { return getRefArray2D<double>(Float64, dim1, dim2); } // SET methods ============================================================= + + void Register::setAccessArea(AccessArea accessArea) + { + accessArea_ = accessArea; + } + void Register::setAccessType(AccessType accessType) { accessType_ = accessType; @@ -637,10 +643,11 @@ namespace Silecs // ......................................................................... std::string Register::getName() { return name_; } + AccessArea Register::getAccessArea() { return accessArea_; } unsigned long Register::getDimension(uint16_t whichDim) { return ((whichDim == 2) ? dimension2_ : dimension1_); } uint32_t Register::getDimension1() { return dimension1_; } uint32_t Register::getDimension2() { return dimension2_; } - uint32_t Register::getLength() {return length_; }; + uint32_t Register::getLength() {return length_; } FormatType Register::getFormat() { return format_; } std::string Register::getBlockName() { return blockName_; } std::string Register::getFormatAsString() { return FormatTypeString[format_]; } @@ -648,6 +655,9 @@ namespace Silecs bool Register::isReadable() { return (accessType_ != Output); } bool Register::isWritable() { return (accessType_ != Input); } + bool Register::isIORegister() { return (accessArea_ != Memory); } + bool Register::isMemoryRegister() { return (accessArea_ == Memory); } + bool Register::isVolatile(){ return isVolatile_; } bool Register::isScalar() { return ((dimension1_ == 1) && (dimension2_ == 1)); } bool Register::isSingleArray() { return ((dimension1_ > 1) && (dimension2_ == 1)); } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h index c730b4d..da18094 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h @@ -107,6 +107,12 @@ namespace Silecs */ std::string getName(); + /*! + * \brief Returns the register access area (same as the related block as defined in the Class design) + * \return Register area: Memory, Digital, Analog + */ + AccessArea getAccessArea(); + /*! * \brief Returns the format of the register data * \return value from the FormatType enumeration @@ -150,6 +156,18 @@ namespace Silecs bool isWritable(); + /*! + * \brief A register can be Memory or IO peripheral register. + * \return true if the register is an IO register (Digital, Analog) + */ + bool isIORegister(); + + /*! + * \brief A register can be Memory or IO peripheral register. + * \return true if the register is a Memory register + */ + bool isMemoryRegister(); + /*! * \brief A register that has not persistent or constant value is Volatile. * Its value is not initialized at the system start-up. @@ -1594,6 +1612,12 @@ namespace Silecs */ void setAccessType(AccessType accessType); + /*! + * \brief Set access area. + * \param accessArea Memory, Digital or Analog + */ + void setAccessArea(AccessArea accessArea); + inline void setBlockName(const std::string blockName) { blockName_ = blockName; } /*! @@ -1652,6 +1676,9 @@ namespace Silecs /// Register access-type: Input, Ouput or InOut (following its related block) AccessType accessType_; + /// Register access-area: Memory, Digital or Analog (following its related block) + AccessArea accessArea_; + /// Enum format: char, uchar, short, ushort, long, ulong, float, double FormatType format_; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp index 8274e22..82d0508 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.cpp @@ -143,10 +143,14 @@ namespace Silecs errCategory_ = DATA_FAULT; errMessage_ = "Register Design has a wrong data format: "; break; - case DATA_UNKNOWN_ACCESS_TYPE: - errCategory_ = DATA_FAULT; - errMessage_ = "Block Design has a wrong access-type: "; - break; + case DATA_UNKNOWN_ACCESS_TYPE: + errCategory_ = DATA_FAULT; + errMessage_ = "Block Design has a wrong access type: "; + break; + case DATA_UNKNOWN_ACCESS_AREA: + errCategory_ = DATA_FAULT; + errMessage_ = "Block Design has a wrong access area: "; + break; case DATA_UNKNOWN_PLC_MANUFACTURER: errCategory_ = DATA_FAULT; errMessage_ = "Controller Deployment has a wrong manufacturer: "; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h index 1cc455c..5aaaa65 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/SilecsException.h @@ -94,7 +94,8 @@ namespace Silecs DIAG_PLC_REPORT_NOT_SUPPORTED, CNV_INTERNAL_ERROR, UNEXPECTED_ERROR, - UNKNOWN_ERROR + UNKNOWN_ERROR, + DATA_UNKNOWN_ACCESS_AREA } ErrorCode; /*! diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp index f9b9106..036ade5 100755 --- a/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/main.cpp @@ -19,6 +19,7 @@ #include <silecs-diagnostic/diagnostictoolmainview.h> #include <silecs-diagnostic/loginhandler.h> #include <silecs-diagnostic/silecsmodule.h> +#include <silecs-communication/interface/utility/XMLParser.h> silecsModule *mysilecs; -- GitLab