diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp index 143a805dcbf6615657a3156c0f7b225a8d8f0803..5e3e73ab69ef945495197ea460100768ebf936c4 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.cpp @@ -24,7 +24,6 @@ #include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/StringUtilities.h> -#include <silecs-communication/protocol/core/silecs.h> namespace Silecs { @@ -98,6 +97,17 @@ namespace Silecs return errorCode; } + int CNVConnection::readMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return readData(thePLC, address, offset, size, pBuffer); + } + int CNVConnection::writeMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return writeData(thePLC, address, offset, size, pBuffer); + } + int CNVConnection::readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) {return 0;} + int CNVConnection::writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) {return 0;} + bool CNVConnection::open(PLC* thePLC) { //Controller is reachable at this stage (ping done from doOpen) diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h index e161ceafe14a5bfdd54e408e64cfa23886158f51..bb3fa70c0222868064c0490b7a86595c4782f44c 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/CNVConnection.h @@ -78,6 +78,10 @@ namespace Silecs unsigned long offset, unsigned long size, unsigned char* buffer){return -1;}; + int readMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); private: // Subscriber @@ -100,6 +104,8 @@ namespace Silecs */ bool close(PLC* thePLC); + bool checkError(PLC* thePLC, int err, bool retry){ return false; } + }; } // namespace 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 ccceca4bafe1849e9d57b06140f22063ad016bec..ed4960f1a1e4e01595ee1c7434bdac9bc193c516 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp @@ -19,7 +19,6 @@ #include <silecs-communication/interface/equipment/SilecsPLC.h> #include <silecs-communication/interface/communication/MBConnection.h> #include <silecs-communication/interface/utility/SilecsException.h> -#include <silecs-communication/protocol/modbus/iemdb.h> //Modbus max data size definition (byte counting) #define MAX_WRITE_DATA_SIZE MODBUS_MAX_WRITE_REGISTERS*2 @@ -27,9 +26,8 @@ namespace Silecs { - - MBConnection::MBConnection(PLC* thePLC) : Connection(thePLC) - { + MBConnection::MBConnection(PLC* thePLC) : Connection(thePLC) + { LOG(ALLOC) << "MBConnection (create): " << thePLC->getName(); //Connection use IP address to limit the naming-server accesses @@ -37,170 +35,215 @@ namespace Silecs writeCtx_ = modbus_new_tcp((char *) thePLC->getIPAddress().c_str(), MODBUS_TCP_DEFAULT_PORT /*=502*/); /*TODO: To be adjusted with the next stable libmodbus release (>3.1.1) - which will fix the current timeout response time issue (see libmodbus forum). + which will fix the current timeout response time issue (see libmodbus forum). - Define Modbus response timeout - struct timeval response_timeout; - response_timeout.tv_sec = 0; - response_timeout.tv_usec = 10000; + Define Modbus response timeout + struct timeval response_timeout; + response_timeout.tv_sec = 0; + response_timeout.tv_usec = 10000; - modbus_set_response_timeout(readCtx_ , &response_timeout); - modbus_set_response_timeout(writeCtx_ , &response_timeout); - */ + modbus_set_response_timeout(readCtx_ , &response_timeout); + modbus_set_response_timeout(writeCtx_ , &response_timeout); + */ modbus_set_slave(readCtx_, 1); //modbus_set_debug(readCtx_, TRUE); - } - + } - MBConnection::~MBConnection() - { - //Close the connection before removing resources - //disable(); must be done before removing resource + MBConnection::~MBConnection() + { + //Close the connection before removing resources + //disable(); must be done before removing resource modbus_free(writeCtx_); modbus_free(readCtx_); - } + } - - bool MBConnection::open(PLC* thePLC) - { + bool MBConnection::open(PLC* thePLC) + { int readErr = modbus_connect(readCtx_); int writeErr = modbus_connect(writeCtx_); return ((readErr != -1) && (writeErr != -1)); - } - + } - bool MBConnection::close(PLC* thePLC) - { + bool MBConnection::close(PLC* thePLC) + { modbus_close(readCtx_); modbus_close(writeCtx_); return true; - } - - - int MBConnection::readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) - { - //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! - if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); - - /* . There is one read-channel per PLC connection. It must be protected against concurrent access. - * . The write-channel is independent and can be accessed in parallel. - * . The global action (open,close,etc.) must be protected from any concurrent access. - * Attention! - * Mutexes are defined with recursive option. It allows doOpen method re-calling readData - * method by executing register synchronization if required. - */ - - //(re)connect the PLC if needed and (re)synchronize the retentive registers - if (doOpen(thePLC)) - { - //connection is established then acquire data - Lock lock(readMux_); - //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) - unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; - - //DATA topic makes sense with RECV one - if (RECV & Log::topics_) LOG(DATA) << "Read data, address: %MW" << addr << ", byte-size: " << size; - - int err = mbReadData(readCtx_, addr, (unsigned short)size, pBuffer); - if(error) - throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error))); - } - return 0; - } - - - int MBConnection::writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) - { - //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! - if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); - - /* . There is one read-channel per PLC connection. It must be protected against concurrent access. - * . The write-channel is independent and can be accessed in parallel. - * . The global action (open,close,etc.) must be protected from any concurrent access. - * Attention! - * Mutexes are defined with recursive option. It allows doOpen method re-calling sendData - * method by executing register synchronization if required. - */ - - //(re)connect the PLC if needed and (re)synchronize the retentive registers - if (doOpen(thePLC)) - { - //connection is established then send data - - Lock lock(writeMux_); - //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) - unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; - - //DATA topic makes sense with SEND one - if (SEND & Log::topics_) LOG(DATA) << "Write data, address: %MW" << addr << ", byte-size: " << size; - - int error = mbWriteData(writeCtx_, (unsigned short)addr, (unsigned short)size, pBuffer); - if(error) - throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error))); - } - return 0; - } - - /*----------------------------------------------------------*/ - int MBConnection::mbWriteData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data) - { - uint16_t *srcp = (uint16_t*)data; - int word_count, byte_count; - - while(count) - { - word_count = (count > MAX_WRITE_DATA_SIZE) ? MAX_WRITE_DATA_SIZE/2 : (count/2)+(count%2); - byte_count = (word_count * 2); - - if (modbus_write_registers(ctx, start_addr, word_count, srcp) != word_count) - { - return errno; - } - - //srcp += byte_count-(count%2); - srcp += word_count; - start_addr += word_count; - count -= (byte_count - (count%2)); - } - - return 0; - } - - /*----------------------------------------------------------*/ - int MBConnection::mbReadData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data) - { - uint16_t *destp = (uint16_t*)data; - int word_count, byte_count; - - while(count) { - - if (count > MAX_READ_DATA_SIZE) - { - /*'word_count' is a word counter*/ - word_count = MAX_READ_DATA_SIZE/2; - } - else - { - /*'word_count' is a word counter*/ - word_count = (count/2) + (count%2); - } - - byte_count = (word_count * 2); - - if (modbus_read_registers(ctx, start_addr, word_count, destp) != word_count) - { - return errno; - } - - //destp += (byte_count-(count%2)); - destp += word_count; - start_addr += word_count; - count -= (byte_count - (count%2)); - } - - return 0; - } + } + + int MBConnection::readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + int rc = 0; + + //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! + if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); + + /* . There is one read-channel per PLC connection. It must be protected against concurrent access. + * . The write-channel is independent and can be accessed in parallel. + * . The global action (open,close,etc.) must be protected from any concurrent access. + * Attention! + * Mutexes are defined with recursive option. It allows doOpen method re-calling readData + * method by executing register synchronization if required. + */ + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then acquire data + readLock(); + //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) + unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; + + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << "Read data, address: %MW" << addr << ", byte-size: " << size; + + rc = mbReadData(readCtx_, addr, (unsigned short)size, pBuffer); + checkError(thePLC, rc, false);// close the connection, will try again at the next access + readUnlock(); + } + return rc; + } + + int MBConnection::writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + int rc = 0; + + //Schneider uses 16bit alignment memory. Block address is expressed in bytes, must be an even value! + if (address % 2) throw SilecsException(__FILE__, __LINE__, PARAM_INCORRECT_BLOCK_ADDRESS, StringUtilities::toString(address)); + + /* . There is one read-channel per PLC connection. It must be protected against concurrent access. + * . The write-channel is independent and can be accessed in parallel. + * . The global action (open,close,etc.) must be protected from any concurrent access. + * Attention! + * Mutexes are defined with recursive option. It allows doOpen method re-calling sendData + * method by executing register synchronization if required. + */ + + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then send data + writeLock(); + //Schneider uses 16bit alignment memory. Block address is expressed in bytes (==> /2) + unsigned short addr = ((unsigned short)address + (unsigned short)offset)/2; + + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << "Write data, address: %MW" << addr << ", byte-size: " << size; + + rc = mbWriteData(writeCtx_, (unsigned short)addr, (unsigned short)size, pBuffer); + checkError(thePLC, rc, false);// close the connection, will try again at the next access + writeUnlock(); + } + return rc; + } + + int MBConnection::readMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return readData(thePLC, address, offset, size, pBuffer); + } + + int MBConnection::writeMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return writeData(thePLC, address, offset, size, pBuffer); + } + + int MBConnection::readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return readData(thePLC, address, offset, size, pBuffer); + } + + int MBConnection::writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) + { + return writeData(thePLC, address, offset, size, pBuffer); + } + + /*----------------------------------------------------------*/ + int MBConnection::mbWriteData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data) + { + uint16_t *srcp = (uint16_t*)data; + int word_count, byte_count; + int rc; + + while(count) + { + word_count = (count > MAX_WRITE_DATA_SIZE) ? MAX_WRITE_DATA_SIZE/2 : (count/2)+(count%2); + byte_count = (word_count * 2); + + if ((rc = modbus_write_registers(ctx, start_addr, word_count, srcp)) != word_count) + { + return rc; + } + + //srcp += byte_count-(count%2); + srcp += word_count; + start_addr += word_count; + count -= (byte_count - (count%2)); + } + + return rc; + } + + /*----------------------------------------------------------*/ + int MBConnection::mbReadData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data) + { + uint16_t *destp = (uint16_t*)data; + int word_count, byte_count; + int rc; + + while(count) + { + + if (count > MAX_READ_DATA_SIZE) + { + /*'word_count' is a word counter*/ + word_count = MAX_READ_DATA_SIZE/2; + } + else + { + /*'word_count' is a word counter*/ + word_count = (count/2) + (count%2); + } + + byte_count = (word_count * 2); + + if ((rc = modbus_read_registers(ctx, start_addr, word_count, destp)) != word_count) + { + return rc; + } + + //destp += (byte_count-(count%2)); + destp += word_count; + start_addr += word_count; + count -= (byte_count - (count%2)); + } + + return rc; + } + +//------------------------------------------------------------------------------------------------------------------- + bool MBConnection::checkError(PLC* thePLC, int rc, bool retry) + { + + if (rc == -1) + { + LOG(COMM) << "Transaction failure with PLC: " << thePLC->getName() << " " << modbus_strerror(errno); + + if (retry) + { + LOG(COMM) << "Try to reconnect the PLC: " << thePLC->getName(); + if (reOpen(thePLC)) + { // can repeat the request after the connection was successfully reopened + return true; + } + // reconnection has failed again, just close the connection + LOG(COMM) << "Unable to reconnect the PLC: " << thePLC->getName(); + } + // no retry, we just want to close (use default case) + doClose(thePLC, /*withLock =*/true); + } + return false; + } } // namespace #endif //MODBUS_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h index 0cfc8de1fd3000af914ac843785b7623ccd5ffe1..46317ec6a920a7e32b86a4b5b32e48c98e7630f0 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.h @@ -21,32 +21,36 @@ namespace Silecs { - class PLC; - - /*! - * \class MBConnection - * \brief Plc-communication object for specific Modbus protocol - */ - class MBConnection : public Connection - { - - public: - MBConnection(PLC* thePLC); - virtual ~MBConnection(); - - int readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); - int writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); - - private: + class PLC; + class Connection; + + /*! + * \class MBConnection + * \brief Plc-communication object for specific Modbus protocol + */ + class MBConnection : public Connection + { + + public: + MBConnection(PLC* thePLC); + virtual ~MBConnection(); + + int readMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeMemory(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + + private: modbus_t* readCtx_; modbus_t* writeCtx_; - bool open(PLC* thePLC); - bool close(PLC* thePLC); - int mbWriteData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); - int mbReadData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); - bool checkError(PLC* thePLC, int err, bool retry); - - }; + bool open(PLC* thePLC); + bool close(PLC* thePLC); + int readData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int mbWriteData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); + int mbReadData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); + bool checkError(PLC* thePLC, int err, bool retry); + }; } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBHardware.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBHardware.h index c436c29f784da54177421450997625e4a3610b17..402f6447f9ea01976a62d00e7d1e8eb4759552cf 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBHardware.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBHardware.h @@ -16,7 +16,7 @@ #ifndef _MBHARDWARE_H_ #define _MBHARDWARE_H_ -#include <silecs-communication/protocol/core/ietype.h> +#include <silecs-communication/interface/communication/ietype.h> #include <modbus.h> /*----------------------------------------------------------*/ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp index 02859a615c71b92b8135d179e44e17d4e3bf7976..065bdc619ce39392c1d7bdbfc25d3bc474bbd316 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp @@ -20,7 +20,7 @@ #include <silecs-communication/interface/equipment/SilecsPLC.h> #include <silecs-communication/interface/communication/SNAP7Connection.h> #include <silecs-communication/interface/utility/SilecsException.h> -#include <silecs-communication/protocol/core/silecs.h> +#include <silecs-communication/interface/utility/Mutex.h> namespace Silecs { @@ -239,6 +239,75 @@ int SNAP7Connection::writeData(PLC* thePLC, unsigned long DBn, unsigned long off return err; } + +int SNAP7Connection::readMemory(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer) +{ + int err = 0; + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then acquire data + Lock lock(readMux_); + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << "Read data, DBn: " << DBn << ", ofs: " << offset << ", byte-size: " << size; + + err = Cli_DBRead(recvClient_, (int)DBn, (int)offset, (int)size, (void *)pBuffer); + checkError(thePLC, err, false); // close the connection, will try again at the next access + } + return err; +} +int SNAP7Connection::writeMemory(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer) +{ + int err = 0; + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then send data + Lock lock(writeMux_); + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << "Write data, DBn: " << DBn << ", ofs: " << offset << ", byte-size: " << size; + + err = Cli_DBWrite(sendClient_, (int)DBn, (int)offset, (int)size, (void *)pBuffer); + checkError(thePLC, err, false); // close the connection, will try again at the next access + } + return err; +} + +int SNAP7Connection::readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) +{ + int err = 0; + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then acquire data + Lock lock(readMux_); + //DATA topic makes sense with RECV one + if (RECV & Log::topics_) LOG(DATA) << "Read data, address: " << address << ", ofs: " << offset << ", byte-size: " << size; + + err = Cli_EBRead(recvClient_, (int)address, (int)size, (void *)pBuffer); + checkError(thePLC, err, false); // close the connection, will try again at the next access + } + return err; +} + +int SNAP7Connection::writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) +{ + int err = 0; + //(re)connect the PLC if needed and (re)synchronize the retentive registers + if (doOpen(thePLC)) + { + //connection is established then send data + Lock lock(writeMux_); + //DATA topic makes sense with SEND one + if (SEND & Log::topics_) LOG(DATA) << "Write data, address: " << address << ", ofs: " << offset << ", byte-size: " << size; + + Cli_ConnectTo(sendClient_, "10.11.34.77", 0, 2); + err = Cli_ABWrite(sendClient_, (int)address, (int)size, (void *)pBuffer); + checkError(thePLC, err, false); // close the connection, will try again at the next access + } + return err; +} + //------------------------------------------------------------------------------------------------------------------- bool SNAP7Connection::checkError(PLC* thePLC, int err, bool retry) { diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h index ea2b9ced9a258af7c7ccf4588f0a5d1f664a0e84..d09d02fa3bfde7cd9d5197b819a45822bdf7650b 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.h @@ -43,6 +43,10 @@ namespace Silecs int readData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); int writeData(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int readMemory(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeMemory(PLC* thePLC, unsigned long DBn, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int readInput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int writeOutput(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); //Extension Silecs methods int coldRestart(PLC* thePLC); diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Hardware.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Hardware.h index 87336b642d015f787a2d188b5537cfc645f3e26d..4db42be4b9940b4f5746146afa4411d1361c7f85 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Hardware.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Hardware.h @@ -15,7 +15,7 @@ #ifndef _SNAP7HARDWARE_H_ #define _SNAP7HARDWARE_H_ -#include <silecs-communication/protocol/core/ietype.h> +#include <silecs-communication/interface/communication/ietype.h> /*----------------------------------------------------------*/ /* Time funtion diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp index 7c4eaabf368e8578107feb73c154492b15aeba31..7d560e3c79e6073c15e243197ecbbb230d7bdd07 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.cpp @@ -20,7 +20,7 @@ #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/communication/SilecsConnection.h> #include <silecs-communication/interface/equipment/SilecsPLC.h> -#include <silecs-communication/protocol/core/silecs.h> +#include <silecs-communication/interface/communication/ietype.h> namespace Silecs { @@ -297,38 +297,6 @@ namespace Silecs return -1; } - - //------------------------------------------------------------------------------------------------------------------- - bool Connection::checkError(PLC* thePLC, int err, bool retry) - { - if (err < 0) - { - LOG(COMM) << "Transaction failure with PLC: " << thePLC->getName() << ". SILECS[" << err << "]: " << IeGetErrorMessage(err); - - switch(err) - { - case IE_TIMEOUT_ERROR: - case IE_EPIPE_ERROR: - case IE_DISCONNECT_ERROR: - if (retry) - { - LOG(COMM) << "Try to reconnect the PLC: " << thePLC->getName(); - if (reOpen(thePLC)) - { // can repeat the request after the connection was successfully reopened - return true; - } - // reconnection has failed again, just close the connection - LOG(COMM) << "Unable to reconnect the PLC: " << thePLC->getName(); - } - // else { // no retry, we just want to close (use default case) - default: - doClose(thePLC, /*withLock =*/true); - } - } - return false; // no particular error - } - - //------------------------------------------------------------------------------------------------------------------------------------------------ void Connection::updateStatus(PLC* thePLC) { @@ -414,20 +382,6 @@ namespace Silecs #define _DISABLE_SIGPIPE sigpipeHandler = signal(SIGPIPE, SIG_IGN) #define _ENABLE_SIGPIPE signal(SIGPIPE, sigpipeHandler) - /*----------------------------------------------------------*/ - /* This is a function used to connect an host on a port. - * 'ip' is the ip address string - * 'port' is the port number (102 for rfc1006 server) - * 'dst' is the TSAP destination string (exp: "TCP-1") - * 'src' is the TSAP source string (exp: "TCP-1") - * 'ts' timeout in second (1s minimum) - * return a socket descriptor or <0 on error - * (see constant error) - * - * Details: - * intermediate connect_nonb() function is used to perform a non-blockant connection. - * intermediate rfcPing() function is used to check if PLC is ON - */ int connect_nonb(int sockfd, struct sockaddr *saptr, socklen_t salen, int nsec) { int flags, n, error; @@ -542,14 +496,20 @@ namespace Silecs } /*..........................................................*/ - int ping(char *hostName, char *plcIP) + int Connection::ping(char *hostName, char *plcIP) { struct in_addr addr; struct hostent *hp; char *ipstr = plcIP; + std::string errorMsg; + std::ostringstream os; if ((hostName == NULL) && (plcIP == NULL)) - return(IE_PARAM_ERROR); + { + os << errorMsg << "Bad parameter(s) value/format"; + LOG(COMM) << os.str(); + return -1; + } // use hostName reference in priority else plcIP if (hostName) @@ -563,7 +523,11 @@ namespace Silecs } if (ipstr == NULL) - return(IE_HOST_UNKNOWN_ERROR); + { + os << errorMsg << "PLC hostname unknown"; + LOG(COMM) << os.str(); + return -1; + } /*trying to connect PLC (1 second max)*/ return (rfcPing(ipstr, 1)); diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h index c87cf3adf5259e7fe0710cb7c7b734f6696a528c..62c19c7c939f0ea99a2c2fc519ebcacf04b046b4 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h @@ -35,23 +35,6 @@ namespace Silecs typedef int ChannelID; //pointer is 32bits word #endif - class Lock - { - - public: - - Lock(Mutex* mutex): mutex_(mutex) - { - mutex_->lock(); - } - - ~Lock() - { - mutex_->unlock(); - } - Mutex* mutex_; - }; - class Connection { @@ -71,6 +54,29 @@ namespace Silecs unsigned long size, unsigned char* buffer) = 0; + virtual int readMemory(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; + + virtual int writeMemory(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; + + virtual int readInput(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; + + virtual int writeOutput(PLC* thePLC, + unsigned long address, + unsigned long offset, + unsigned long size, + unsigned char* buffer) = 0; /*! * \fn enable/disable * \brief The client can suspend the data transmission by disabling the connection if required. @@ -116,16 +122,11 @@ namespace Silecs /*! * \fn checkError - * \brief This method attempts to reconnect the PLC in case of "expected" transaction failure. - * If the returned value is true the request must be repeated. - * The retry flag defines whether the transaction will be repeated or not - * IE_CONNECT_ERROR - TCP/IP connect() failed: IeOpen() (PLC is off or the max. number of open connection is reached) - * Retry required: - * IE_DISCONNECT_ERROR - Explicit/unexpected disconnect request (when the connection has been unactive for some time) - * IE_EPIPE_ERROR - TCP/IP send/recv failed (when one of the channel (get/set) has been unactive for some time or PLC is off) - * IE_TIMEOUT_ERROR - PLC is connected but does not reply (In mean time the PLC gets off or data is lost) + * \brief This method attempts to reconnect the PLC in case of "expected" transaction failure. + * If the returned value is true the request must be repeated. + * The retry flag defines whether the transaction will be repeated or not */ - virtual bool checkError(PLC* thePLC, int err, bool retry); + virtual bool checkError(PLC* thePLC, int err, bool retry) = 0; /*! * \fn updatePLCStatus @@ -163,7 +164,21 @@ namespace Silecs /* ping function is a function used to check * if PLC is ON (~ping) before trying to connect it. */ - static int ping(char *hostName, char *plcIP); + /*----------------------------------------------------------*/ + /* This is a function used to connect an host on a port. + * 'ip' is the ip address string + * 'port' is the port number (102 for rfc1006 server) + * 'dst' is the TSAP destination string (exp: "TCP-1") + * 'src' is the TSAP source string (exp: "TCP-1") + * 'ts' timeout in second (1s minimum) + * return a socket descriptor or <0 on error + * (see constant error) + * + * Details: + * intermediate connect_nonb() function is used to perform a non-blockant connection. + * intermediate rfcPing() function is used to check if PLC is ON + */ + int ping(char *hostName, char *plcIP); // Communication Diagnostic & Monitoring static bool isAlive_; // PLC has repliyed to the ping: true/false diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/ietype.h similarity index 82% rename from silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h rename to silecs-communication-cpp/src/silecs-communication/interface/communication/ietype.h index 6d07415e9e7dd02861deb7055664797685caefbb..d7d75ca09fad78a5c2b4efbdc8384471474d304b 100644 --- a/silecs-communication-cpp/src/silecs-communication/protocol/core/ietype.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/ietype.h @@ -13,36 +13,37 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. - /* + * Tab stop value: 2 (number of space used in place of tabs) + * * Revision : v1.0 * Date : 08/2003 - F.Locci * Objet : original version for SCHNEIDER and SIMATIC PLCs - * Action : + * Action : * * Revision : v1.1 * Date : 10/2003 - F.Locci * Objet : original version for SCHNEIDER and SIMATIC PLCs - * Action : + * Action : * * Revision : v1.2 * Date : 10/2005 - F.Locci - * Objet : Allow absolute offset for eveyr protocol - * Action : To prevent interface modification we use + * Objet : Allow absolute offset for eveyr protocol + * Action : To prevent interface modification we use * : following convention: - * : . negative constant to use relative offset (BLK_..) - * : . positive value to use absolute offset + * : . negative constant to use relative offset (BLK_..) + * : . positive value to use absolute offset * * Revision : v1.3 * Date : 03/2007 - F.Locci * Objet : Increase receive buffer size (MAX_DATA_REP_..) to 64kb - * Action : Increase cosntant from 21504 to 64kb to fulfill some + * Action : Increase cosntant from 21504 to 64kb to fulfill some * : specific user requirement (BOFISOP class) - adjust timeout * * Revision : v1.4 * Date : 04/2007 - F.Locci - * Objet : Prevent SIEMENS PLC disconnection - * Action : Provide Keep-Alive transaction to be called periodically + * Objet : Prevent SIEMENS PLC disconnection + * Action : Provide Keep-Alive transaction to be called periodically * */ @@ -50,7 +51,7 @@ #define _IETYPE_H_ /* ---------------------------------------------------------*/ -/* INCLUDE FILES */ +/* INCLUDE FILES */ /* ---------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> @@ -80,20 +81,20 @@ allow large command for fetch/write & modbus protocol. */ /*v1.1 modif. (previous one, still valid) - DATA_CMD_DEFER_SIZE: 8192 --> 4096 (RFC) to support deferred - mode with S7-300 PLC. This modification was necessary to avoid + DATA_CMD_DEFER_SIZE: 8192 --> 4096 (RFC) to support deferred + mode with S7-300 PLC. This modification was necessary to avoid S7-341 ethernet coupler crashing when receiving to big command defer frame. Size = 8192 had been choosen for S7-400 ISOLDE project but is too - large for S7-300 memory. - Attention! This v1.1 modification double the number of + large for S7-300 memory. + Attention! This v1.1 modification double the number of deferred transation with pisobeam if we recompile 'plcgenrt' process with this new version (normally we woudln't have to do it) */ -#define MAX_RFC_CMD_DEFER_SIZE 4096 /*byte - see PLC code */ -#define MAX_FEW_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ -#define MAX_MDB_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ -#define MAX_S7_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_RFC_CMD_DEFER_SIZE 4096 /*byte - see PLC code */ +#define MAX_FEW_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_MDB_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ +#define MAX_S7_CMD_DEFER_SIZE 16384 /*byte - no constraint on PLC side */ #define MAX_DATA_CMD_DEFER_SIZE 16384 /*byte - MUST BE the max 3 above constants*/ #define MAX_DATA_REP_DEFER_SIZE 65536 /*v1.3, byte - see PLC code*/ @@ -102,13 +103,13 @@ /* error constant */ // silecs internal error ................................... // don't forget to modify IeGetErrorMessage(..) function -#define RFC_SYS_ERROR (int)-1 -#define RFC_PARAM_ERROR (int)-2 -#define RFC_CONNECT_ERROR (int)-3 -#define RFC_DISCONNECT_ERROR (int)-4 -#define RFC_TIMEOUT_ERROR (int)-5 -#define RFC_EPIPE_ERROR (int)-6 -#define RFC_FRAME_ERROR (int)-7 +#define RFC_SYS_ERROR (int)-1 +#define RFC_PARAM_ERROR (int)-2 +#define RFC_CONNECT_ERROR (int)-3 +#define RFC_DISCONNECT_ERROR (int)-4 +#define RFC_TIMEOUT_ERROR (int)-5 +#define RFC_EPIPE_ERROR (int)-6 +#define RFC_FRAME_ERROR (int)-7 #define IE_SYS_ERROR RFC_SYS_ERROR #define IE_PARAM_ERROR RFC_PARAM_ERROR @@ -136,11 +137,11 @@ #define IE_KEEP_ALIVE_IOCTL_ERROR (int)-207 // PLC keep-alive transaction failed /* protocol parameters */ -#define MAX_CONNECT_TIMEOUT 2 /*s */ -#define MAX_DATA_TIMEOUT 12 /*s v1.3*/ +#define MAX_CONNECT_TIMEOUT 2 /*s */ +#define MAX_DATA_TIMEOUT 12 /*s v1.3*/ /* ---------------------------------------------------------*/ -/* MACRO DEFINITIONS */ +/* MACRO DEFINITIONS */ /* ---------------------------------------------------------*/ // Used to convert DT PLC format to/from DSC time format diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp index 57b425983494f0c96636d0c8f26704db3af60e74..175dc5540eef003fb1481e3c0be27f626e46d12a 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVRecvAction.cpp @@ -81,22 +81,22 @@ namespace Silecs } } - bufferLock(); + { //critical section + Lock lock(bufferMux_); - // read data from the buffer subscriber - CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); - errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); + // read data from the buffer subscriber + CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); + errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); + 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_, &buffer, tod, pContext); + //Device context: Extract all the device registers from that block + pDev->importRegisters(theBlock_, &buffer, tod, pContext); + } } - bufferUnlock(); - //Deleting Null Data object raised a CNV exception if (errorCode != CNVEmptyDataError) errChk(CNVDisposeData(buffer)); @@ -117,22 +117,21 @@ namespace Silecs } } - bufferLock(); - - // read data from the buffer subscriber - CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); - errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); + { //critical section + Lock lock(bufferMux_); + // read data from the buffer subscriber + CNVBufferedSubscriber* handle = ((CNVInputBlock*)theBlock_)->getHandle(pDev->getLabel()); + errorCode = ((CNVConnection*)pConn)->readData(theBlock_->getPLC(), handle,&buffer); - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); + 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_, &buffer, tod, pContext); + //PLC context: Extract all registers value of the current device of the PLC from that block + pDev->importRegisters(theBlock_, &buffer, tod, pContext); + } } - bufferUnlock(); - //Deleting Null Data object raised a CNV exception if (errorCode != CNVEmptyDataError) errChk(CNVDisposeData(buffer)); @@ -142,8 +141,6 @@ namespace Silecs } catch (const SilecsException& ex) { - bufferUnlock(); - errorCode = ex.getCode(); } } //doOpen diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp index 3e22bc39e9ce70bdab9947ce9ca3967be380d4bd..7b6c53b48a7ff31f3ff7ce87694800d94d61cd87 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/CNVSendAction.cpp @@ -74,25 +74,24 @@ namespace Silecs pBuffer = (CNVData*)theBlock_->getBuffer(); - bufferLock(); - - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device: " << pDev->getLabel(); - - //Device context: Export all the device registers to that block - pDev->exportRegisters(theBlock_, pBuffer, pContext); - } + { //critical section + Lock lock(bufferMux_); + if (pConn->isEnabled()) + { + LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device: " << pDev->getLabel(); - // compute the block address - std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" - +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" - + pDev->getLabel()+"\\"+theBlock_->getName(); + //Device context: Export all the device registers to that block + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } - // call CNV write - ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + // compute the block address + std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" + +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" + + pDev->getLabel()+"\\"+theBlock_->getName(); - bufferUnlock(); + // call CNV write + ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + } if (SEND & Log::topics_) { @@ -113,24 +112,23 @@ namespace Silecs pBuffer = (CNVData*)theBlock_->getBuffer(); - bufferLock(); + { //critical section + Lock lock(bufferMux_); + if (pConn->isEnabled()) + { LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device:" << pDev->getLabel(); - if (pConn->isEnabled()) - { LOG(SEND) << "SendAction (execute/ DeviceMode): " << theBlock_->getName() << ", device:" << pDev->getLabel(); - - //PLC context: Export all registers value of the current device of the PLC to that block - pDev->exportRegisters(theBlock_, pBuffer, pContext); - } - - // compute the block address - std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" - +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" - + pDev->getLabel()+"\\"+theBlock_->getName(); + //PLC context: Export all registers value of the current device of the PLC to that block + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } - // call CNV write - ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + // compute the block address + std::string blockAddress = "\\\\"+pDev->getPLC()->getName()+"\\'" + +pDev->getPLC()->theCluster_->getClassName()+"-"+pDev->getPLC()->theCluster_->getClassVersion()+"'\\" + + pDev->getLabel()+"\\"+theBlock_->getName(); - bufferUnlock(); + // call CNV write + ((CNVConnection*)pConn)->writeData(theBlock_->getPLC(), blockAddress.c_str(),*pBuffer); + } if (SEND & Log::topics_) { if (pConn->isEnabled()) @@ -142,8 +140,6 @@ namespace Silecs } catch (const SilecsException& ex) { - bufferUnlock(); - //LOG(DEBUG) << "CNV SendAction (execute/ DeviceMode) failed: "<< ex.getMessage(); //errorCode = ex.getCode(); LOG(DEBUG) << "CNV SendAction (execute/ DeviceMode) failed"; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h index b3fa2806dd7415a89a54c30571a8831bfd8def14..95d874506abde701cf493aa6c5d682b27c13715d 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCAction.h @@ -50,10 +50,6 @@ namespace Silecs protected: //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). - inline void bufferLock() { bufferMux_->lock(); } - inline void bufferUnlock() { bufferMux_->unlock(); } - - private: Mutex* bufferMux_; }; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp index 3bf18c7efb1e5399165c3dc3d9d7f6c7531fa5ab..8b34eecf8eb3d00a0a602dba2c0bcb96c533d4f5 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCRecvAction.cpp @@ -23,7 +23,6 @@ #include <silecs-communication/interface/equipment/PLCBlock.h> #include <silecs-communication/interface/core/Context.h> #include <silecs-communication/interface/utility/SilecsLog.h> -#include <silecs-communication/protocol/core/silecs.h> namespace Silecs { @@ -83,15 +82,43 @@ namespace Silecs } } - bufferLock(); - - errorCode = pConn->readData( - 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 - ); + //begin critical section + Lock lock(bufferMux_); + switch (theBlock_->getAccessArea()) { + case Memory: { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->readInput( + 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; + } + default: + { + errorCode = pConn->readData( + 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 @@ -102,9 +129,7 @@ namespace Silecs LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); } - - bufferUnlock(); - + //end critical section } else { @@ -123,15 +148,43 @@ namespace Silecs } } - bufferLock(); - - errorCode = pConn->readData( - 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) - ); + //begin critical section + Lock lock(bufferMux_); + switch (theBlock_->getAccessArea()) { + case Memory: { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->readInput( + 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; + } + default: + { + errorCode = pConn->readData( + 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 @@ -148,16 +201,12 @@ namespace Silecs LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); } - - bufferUnlock(); - } } catch (const SilecsException& ex) { - bufferUnlock(); LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << theBlock_->getName() << " has failed"; + LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << theBlock_->getName() << " has failed."; return ex.getCode(); } return 0; @@ -195,15 +244,43 @@ namespace Silecs } } - bufferLock(); - - errorCode = pConn->readData( - 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 - ); + //begin critical section + Lock lock(bufferMux_); + switch (theBlock_->getAccessArea()) { + case Memory: { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->readInput( + 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; + } + default: + { + errorCode = pConn->readData( + 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 @@ -214,9 +291,6 @@ namespace Silecs LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); } - - bufferUnlock(); - } else { @@ -240,16 +314,42 @@ namespace Silecs { Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << theBlock_->getName(); } } - - bufferLock(); - - errorCode = pConn->readData( - theBlock_->getPLC(), - pDev->getAddress(), //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 - ); + //begin critical section + Lock lock(bufferMux_); + switch (theBlock_->getAccessArea()) { + case Memory: { + errorCode = pConn->readMemory( + theBlock_->getPLC(), + pDev->getAddress(), //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 Digital: + case Analog: + { + errorCode = pConn->readInput( + theBlock_->getPLC(), + pDev->getAddress(), //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 + ); + + } default: + { + errorCode = pConn->readData( + theBlock_->getPLC(), + pDev->getAddress(), //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 @@ -260,17 +360,13 @@ namespace Silecs LOG_DELAY(RECV) << "done for block: " << theBlock_->getName(); } - - bufferUnlock(); - } } } catch (const SilecsException& ex) { - bufferUnlock(); LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed"; + LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed."; return ex.getCode(); } return 0; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp index 2c9a9f93807fed82a24920dc2f931c7afd6a6650..a1cad4081cac0c5e7ba45c1dad2096de6dc8ea7f 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/PLCSendAction.cpp @@ -24,7 +24,6 @@ #include <silecs-communication/interface/equipment/PLCBlock.h> #include <silecs-communication/interface/core/Context.h> #include <silecs-communication/interface/utility/SilecsLog.h> -#include <silecs-communication/protocol/core/silecs.h> namespace Silecs { @@ -75,24 +74,50 @@ namespace Silecs usedDeviceOffset = theBlock_->getCustomOffset(); } - bufferLock(); - - 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); - } - - errorCode = pConn->writeData( - 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 - ); - - bufferUnlock(); + { //critical section + Lock 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 (theBlock_->getAccessArea()) { + case Memory: + { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->writeOutput( + 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; + } + default: + errorCode = pConn->writeData( + 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()) @@ -106,34 +131,60 @@ namespace Silecs if (theBlock_->withCustomAttributes() == true) throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - bufferLock(); - - 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; - unsigned long deviceOffset = pDev->getAddress() * theBlock_->getMemSize(); - unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; - pDev->exportRegisters(theBlock_, pBuffer, pContext); - } - } - - errorCode = pConn->writeData( - 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) - ); - - bufferUnlock(); + {//critical section + Lock 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; + unsigned long deviceOffset = pDev->getAddress() * theBlock_->getMemSize(); + unsigned char* pBuffer = ((unsigned char*)theBlock_->getBuffer()) + deviceOffset; + pDev->exportRegisters(theBlock_, pBuffer, pContext); + } + } + + switch (theBlock_->getAccessArea()) { + case Memory: + { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->writeOutput( + 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; + } + default: + errorCode = pConn->writeData( + 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()) @@ -144,7 +195,6 @@ namespace Silecs } catch (const SilecsException& ex) { - bufferUnlock(); LOG(ERROR) << ex.what(); LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << theBlock_->getName() << " has failed"; return ex.getCode(); @@ -176,24 +226,50 @@ namespace Silecs usedSize = theBlock_->getCustomSize(); } - bufferLock(); - - 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); - } - - errorCode = pConn->writeData( - 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 - ); - - bufferUnlock(); + {//critical section + Lock 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 (theBlock_->getAccessArea()) { + case Memory: + { + 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; + } + case Digital: + case Analog: + { + errorCode = pConn->writeOutput( + 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; + } + default: + errorCode = pConn->writeData( + 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()) @@ -214,24 +290,50 @@ namespace Silecs { Device* pDev = pDeviceIter->second; - bufferLock(); - - 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); - } - - errorCode = pConn->writeData( - theBlock_->getPLC(), - pDev->getAddress(), //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 - ); - - bufferUnlock(); + {//critical section + Lock 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); + } + + switch (theBlock_->getAccessArea()) { + case Memory: + { + errorCode = pConn->writeMemory( + theBlock_->getPLC(), + pDev->getAddress(), //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 Digital: + case Analog: + { + errorCode = pConn->writeOutput( + theBlock_->getPLC(), + pDev->getAddress(), //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; + } + default: + errorCode = pConn->writeData( + theBlock_->getPLC(), + pDev->getAddress(), //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()) @@ -243,7 +345,6 @@ namespace Silecs } catch (const SilecsException& ex) { - bufferUnlock(); LOG(ERROR) << ex.what(); LOG(ERROR) << "SendAction (execute/ DeviceMode) failed"; return ex.getCode(); 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 2c06112a60255c576ae70299b8f22b354b7f2e2d..f576e8b1e414b3e1d97f81bc2d57055c9e8bdc6d 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp @@ -14,8 +14,6 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "PLCRegister.h" -#include <silecs-communication/protocol/core/silecs.h> -#include <silecs-communication/protocol/modbus/iemdb.h> #include <silecs-communication/interface/communication/MBHardware.h> #include <silecs-communication/interface/communication/SNAP7Hardware.h> 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 3929c08c84de2258b6ed144e6c0c2b7523bdd9c6..ec6ff934ed6c7cef010a1415d3ec7e4bfb84a386 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp @@ -21,7 +21,6 @@ #include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/StringUtilities.h> -#include <silecs-communication/protocol/core/silecs.h> #include <arpa/inet.h> #include <math.h> diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h index ecf693deadb7276ec45697861bc7d9400cb82133..7d1f3ad1c02c1f723cd0c50042a9b354524e275f 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Mutex.h @@ -50,6 +50,22 @@ namespace Silecs pthread_mutexattr_t attr_; }; + // For automatic mutex-release on code-block exit ( e.g. if exceptions are used ) + class Lock + { + public: + Lock(Mutex* mutex): mutex_(mutex) + { + mutex_->lock(); + } + + ~Lock() + { + mutex_->unlock(); + } + Mutex* mutex_; + }; + } // namespace #endif /* _MUTEX_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp deleted file mode 100644 index ca0bbabe389cbd6c1c270a5cd5343529a3ec2fdd..0000000000000000000000000000000000000000 --- a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2016 CERN and GSI -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - - -/* - * - * Revision : v1.0 - * Date : 01/2010 - F.Locci - * Objet : Initial version - From previous Silecs-2 - * Action : - */ - -/* - * This library was developped to provide communication between - * Linux/LynxOS active host (client) and a PLC passive server. - * Based on S7 or MODBUS std. protocole, it defines generic - * set and get functions to read and write data into/from PLC - * memory. - * - */ - -/* ---------------------------------------------------------*/ -/* INCLUDE FILES */ -/* ---------------------------------------------------------*/ -#include <fcntl.h> -#include <signal.h> - -#include <silecs-communication/protocol/core/silecs.h> - -/* ---------------------------------------------------------*/ -/* MACRO DEFINITION */ -/* ---------------------------------------------------------*/ - -/*----------------------------------------------------------*/ -/* This function return the string which describes the - * error given by 'error' parameter. - * 'error': error from ie library or PLC server (in) - * return string pointer - * - * Details: - */ -char *IeGetErrorMessage(int err) -{ - int i; - - static struct - { - int ie_code; - char * ie_mes; - } errorMap[] = - { - {IE_SYS_ERROR, "[RFC lib.] function system error"}, //unused - {IE_PARAM_ERROR, "[IE/RFC lib.] bad parameter(s) value/format"}, //used by Silecs - {IE_CONNECT_ERROR, "[RFC lib.] PLC connection failed"}, //unused - {IE_DISCONNECT_ERROR, "[RFC lib.] PLC disconnection requested"}, //unused - {IE_TIMEOUT_ERROR, "[RFC lib.] communication (connect/send/recv) timeout occurred"}, //used by Snap7 - {IE_HOST_UNKNOWN_ERROR, "[IE lib.] PLC hostname unknown"}, //used by Silecs, PlcSendAction and PlcRcvAction - }; - - static int errorMapSize = sizeof(errorMap)/sizeof(errorMap[0]); - - if (err == 0) - return ("No error"); - - for (i=0; i<errorMapSize; i++) - if (errorMap[i].ie_code == err) - return (errorMap[i].ie_mes); - - return ("Unknown IE error"); -} diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h b/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h deleted file mode 100644 index 50a466609940b49ec0f9648cc6b0d749db1d91e6..0000000000000000000000000000000000000000 --- a/silecs-communication-cpp/src/silecs-communication/protocol/core/silecs.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 CERN and GSI -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - -/* - * - * Revision : v1.0 - * Date : 01/2010 - F.Locci - * Objet : Initial version - From previous Silecs-2 - * Action : - */ - -#ifndef _SILECS_H_ -#define _SILECS_H_ - -/* - * This library was developped to provide communication between - * Linux/LynxOS active host (client) and a PLC passive server. - * Based on S7 or MODBUS std. protocole, it defines generic - * set and get functions to read and write data into/from PLC - * memory. - * - */ - -/* ---------------------------------------------------------*/ -/* INCLUDE FILES */ -/* ---------------------------------------------------------*/ -#include "ietype.h" - -/*----------------------------------------------------------*/ -/* This function return the string which describes the - * error given by 'error' parameter. - * 'error': error from ie library or PLC server (in) - * return string pointer - * - * Details: - */ -char *IeGetErrorMessage(int err); - -#endif /* _SILECS_H_ */ diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp deleted file mode 100644 index 7439990ce71b77522195023ab88267183c93e84d..0000000000000000000000000000000000000000 --- a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifdef MODBUS_SUPPORT_ENABLED -#include "iemdb.h" -#include <modbus.h> - -/* ---------------------------------------------------------*/ -/* FUNCTIONS CODE */ -/* ---------------------------------------------------------*/ - -/*----------------------------------------------------------*/ -/* Local functions */ -/* ---------------------------------------------------------*/ - -/* Function to load a struct timeval correctly - * from a double. - */ -static inline struct timespec d_to_timespec(double time) { - struct timespec tmp; - - tmp.tv_sec = time; - tmp.tv_nsec = 1e9*(time - tmp.tv_sec); - return tmp; -} - -/*----------------------------------------------------------*/ -/* Glocal functions */ -/* ---------------------------------------------------------*/ -#endif //MODBUS_SUPPORT_ENABLED diff --git a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h b/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h deleted file mode 100644 index c3822f68a2ee38f03511daadba5c39b00fe08841..0000000000000000000000000000000000000000 --- a/silecs-communication-cpp/src/silecs-communication/protocol/modbus/iemdb.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifdef MODBUS_SUPPORT_ENABLED -#ifndef _IEMDB_H_ -#define _IEMDB_H_ - -#include <silecs-communication/protocol/core/ietype.h> -#include <modbus.h> - -/*----------------------------------------------------------*/ -/* Time funtion - * IeMdbSetTime: Convert time_t epoch date to PLC SCHNEIDER - * format. - * - * Details: - * PLC SCHNEIER format is coded on 8 bytes BCD - * format: - * - * 0 1 2 3 4 5 6 7 - * SC -- HH MN MM DD YY YY - * - * byte 1 is used by gateway to synchronize time setting. - */ -void IeMdbSetTime(unsigned char *dt, time_t epoch); // to PLC - -/*----------------------------------------------------------*/ -/* Time funtion - * IeMdbGetTime: Convert PLC SCHNEIDER format to lynxOS - * time_t format. - * - * Details: - * PLC SCHNEIER format is coded on 8 bytes BCD - * format: - * - * 0 1 2 3 4 5 6 7 - * SC SC/100 HH MN MM DD YY YY - * - */ -double IeMdbGetTime(unsigned char *dt); // from PLC - -/*----------------------------------------------------------*/ -/* This function send a data segment to the PLC using the - * MODBUS protocole. - * 'ctx': write channel id of the MB connection - * 'dataAddr': target address of the data segment within the PLC memory - * 'dataSize': byte size of the data segment to be sent - * 'dataBuffer': buffer of the data to be sent - * return 0 or <0 on error (see constant error) - */ -int IeMBwriteData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); - -/*----------------------------------------------------------*/ -/* This function read a data segment from the PLC using the - * MODBUS protocole. - * 'ctx': read channel id of the MB connection - * 'dataAddr': address of the data segment within the PLC memory - * 'dataSize': byte size of the data segment to be read - * 'dataBuffer': buffer to store the data - * return 0 or <0 on error (see constant error) - */ -int IeMBreadData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer); - -#endif /* _IEMDB_H_ */ -#endif //MODBUS_SUPPORT_ENABLED