From 8fe61103e22478fc219aed9354eb8aaed5fa606f Mon Sep 17 00:00:00 2001 From: andreucm Date: Mon, 9 Oct 2017 21:24:38 +0200 Subject: [PATCH 1/4] Commented some cout lines to clean execution terminal --- src/session.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/session.cpp b/src/session.cpp index 08ede99..b384715 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -60,8 +60,7 @@ Session::Session(shared_ptr socket, shared_ptr io_socket, boost::random::uniform_int_distribution<> dist(0, 0xFFFF); next_connection_id_ = gen(); next_connection_sn_ = dist(gen); - cout << "Generated starting connection ID " << next_connection_id_ - << " and SN " << next_connection_sn_ << endl;; + //cout << "Generated starting connection ID " << next_connection_id_ << " and SN " << next_connection_sn_ << endl;; } Session::~Session() @@ -81,12 +80,12 @@ Session::~Session() void Session::open(string hostname, string port, string io_port) { - cout << "Resolving hostname and connecting socket" << endl; + //cout << "Resolving hostname and connecting socket" << endl; socket_->open(hostname, port); io_socket_->open(hostname, io_port); // create the registration message - cout << "Creating and sending the registration message" << endl; + //cout << "Creating and sending the registration message" << endl; shared_ptr reg_data = make_shared(); EncapPacket reg_msg(EIP_CMD_REGISTER_SESSION, 0, reg_data); @@ -149,7 +148,7 @@ void Session::open(string hostname, string port, string io_port) } session_id_ = response.getHeader().session_handle; - cout << "Successfully opened session ID " << session_id_ << endl; + //cout << "Successfully opened session ID " << session_id_ << endl; } void Session::close() @@ -170,12 +169,12 @@ void Session::close() EncapPacket Session::sendCommand(EncapPacket& req) { - cout << "Sending Command" << endl; + //cout << "Sending Command" << endl; socket_->send(req); - cout << "Waiting for response" << endl; + //cout << "Waiting for response" << endl; size_t n = socket_->receive(buffer(recv_buffer_)); - cout << "Received response of " << n << " bytes" << endl; + //cout << "Received response of " << n << " bytes" << endl; BufferReader reader(buffer(recv_buffer_, n)); EncapPacket result; @@ -247,7 +246,7 @@ void Session::setSingleAttributeSerializable(EIP_USINT class_id, RRDataResponse Session::sendRRDataCommand(EIP_USINT service, const Path& path, shared_ptr data) { - cout << "Creating RR Data Request" << endl; + //cout << "Creating RR Data Request" << endl; shared_ptr req_data = make_shared (service, path, data); EncapPacket encap_pkt(EIP_CMD_SEND_RR_DATA, session_id_, req_data); From 00d24c5d363601a5434013484869abda7b038a49 Mon Sep 17 00:00:00 2001 From: andreucm Date: Fri, 10 Nov 2017 14:12:20 +0100 Subject: [PATCH 2/4] Allow 16-bit long attribute ID at getSingleAttribute(): - Add corresponding methods at Path class to allow paths with 16-bit long attribute id's. - Add corresponding methods at Session class to allow paths with 16-bit long attribute id's. - Tested successfully with an Ethernet/IP adapter device with attributes id's greater than 255. Main reference: - "CIP Common Specification" Volume1, Release 1.0. ControlNet International and Open DeviceNet Vendor Association. June 2001 (Appendix C, page C-7) --- include/odva_ethernetip/path.h | 9 +++++++ include/odva_ethernetip/session.h | 9 +++++++ src/path.cpp | 40 +++++++++++++++++++++++++++++++ src/session.cpp | 11 +++++++++ 4 files changed, 69 insertions(+) diff --git a/include/odva_ethernetip/path.h b/include/odva_ethernetip/path.h index b51f59a..53d6095 100644 --- a/include/odva_ethernetip/path.h +++ b/include/odva_ethernetip/path.h @@ -69,6 +69,8 @@ class Path */ Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, bool pad_after_length = false); + Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_UINT attribute_id, + bool pad_after_length = false); /** * Shortcut to construct a path to the given logical class instance @@ -107,6 +109,7 @@ class Path * @param attribute_id ID Number of attribute to add to path */ void addLogicalAttribute(EIP_USINT attribute_id); + void addLogicalAttribute(EIP_UINT attribute_id); /** * Add a logical connection point segment @@ -166,6 +169,11 @@ class Path throw std::logic_error("Not implemented"); } + /** + * Prints path bytes at std output + */ + void print() const; + private: bool pad_after_length_; vector path_buf_; @@ -176,6 +184,7 @@ class Path * @param data Data to add to path */ void addSegment(EIP_USINT type, EIP_USINT data); + void addSegment(EIP_USINT type, EIP_UINT data); }; } // namespace eip diff --git a/include/odva_ethernetip/session.h b/include/odva_ethernetip/session.h index 4963c64..0dc442d 100644 --- a/include/odva_ethernetip/session.h +++ b/include/odva_ethernetip/session.h @@ -105,6 +105,8 @@ class Session */ void getSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, Serializable& result); + void getSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, + EIP_UINT attribute_id, Serializable& result); /** * Shortcut to get a single attribute as a primitive type @@ -120,6 +122,13 @@ class Session getSingleAttributeSerializable(class_id, instance_id, attribute_id, data); return data.data; } + template + T getSingleAttribute(EIP_USINT class_id, EIP_USINT instance_id, EIP_UINT attribute_id, T v) + { + SerializablePrimitive data; + getSingleAttributeSerializable(class_id, instance_id, attribute_id, data); + return data.data; + } /** * Set a single attribute from the given class / instance / attribute path diff --git a/src/path.cpp b/src/path.cpp index 2607aa3..06c5118 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -27,6 +27,10 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #include +#include +#include +#include + namespace eip { Path::Path(bool pad_after_length) : pad_after_length_(pad_after_length) @@ -41,13 +45,26 @@ Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, addLogicalClass(class_id); addLogicalInstance(instance_id); addLogicalAttribute(attribute_id); + //this->print(); } +Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_UINT attribute_id, + bool pad_after_length) : pad_after_length_(pad_after_length) +{ + path_buf_.reserve(7); + addLogicalClass(class_id); + addLogicalInstance(instance_id); + addLogicalAttribute(attribute_id); + //this->print(); +} + + Path::Path(EIP_USINT class_id, EIP_USINT instance_id) : pad_after_length_(false) { path_buf_.reserve(4); addLogicalClass(class_id); addLogicalInstance(instance_id); + //this->print(); } void Path::addSegment(EIP_USINT type, EIP_USINT data) @@ -56,6 +73,13 @@ void Path::addSegment(EIP_USINT type, EIP_USINT data) path_buf_.push_back(data); } +void Path::addSegment(EIP_USINT type, EIP_UINT data) +{ + path_buf_.push_back(type); + path_buf_.push_back( (EIP_USINT)(data&0xff) ); + path_buf_.push_back( (EIP_USINT)((data&0xff00)>>8) ); +} + void Path::addLogicalClass(EIP_USINT class_id) { addSegment(0x20, class_id); @@ -71,6 +95,11 @@ void Path::addLogicalAttribute(EIP_USINT attribute_id) addSegment(0x30, attribute_id); } +void Path::addLogicalAttribute(EIP_UINT attribute_id) +{ + addSegment(0x31, attribute_id); +} + void Path::addLogicalConnectionPoint(EIP_USINT connection_id) { addSegment(0x2C, connection_id); @@ -94,4 +123,15 @@ Writer& Path::serialize(Writer& writer, bool pad_after_length) const return writer; } +void Path::print() const +{ + std::cout << "PATH: "; + for (unsigned int ii=0; ii< path_buf_.size(); ii++) + { + std::cout << std::hex << std::setfill('0') << std::setw(2) << (unsigned short int)path_buf_.at(ii); + if ( (ii+1)%2 == 0 ) std::cout << " "; + } + std::cout << std::dec << std::endl; +} + } // namespace eip diff --git a/src/session.cpp b/src/session.cpp index b384715..dd3f2e3 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -236,6 +236,17 @@ void Session::getSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT insta resp_data.getResponseDataAs(result); } +void Session::getSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, + EIP_UINT attribute_id, Serializable& result) +{ + shared_ptr no_data; + RRDataResponse resp_data = sendRRDataCommand(0x0E, + Path(class_id, instance_id, attribute_id), no_data); + + resp_data.getResponseDataAs(result); +} + + void Session::setSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, shared_ptr data) { From 61dad8cf1e6b683f6c5370ab15500e1185b0db02 Mon Sep 17 00:00:00 2001 From: andreucm Date: Mon, 13 Nov 2017 19:44:21 +0100 Subject: [PATCH 3/4] Allow 16-bit long attribute ID at setSingleAttribute(): - Follows the work from previous commit to allow attribute id's with 16 bits - Add corresponding methods at Session class to allow paths with 16-bit long attribute id's. - Not yet tested with a device. Main reference: - "CIP Common Specification" Volume1, Release 1.0. ControlNet International and Open DeviceNet Vendor Association. June 2001 (Appendix C, page C-7) --- include/odva_ethernetip/session.h | 10 ++++++++++ src/session.cpp | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/include/odva_ethernetip/session.h b/include/odva_ethernetip/session.h index 0dc442d..45aeb5c 100644 --- a/include/odva_ethernetip/session.h +++ b/include/odva_ethernetip/session.h @@ -139,6 +139,8 @@ class Session */ void setSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, shared_ptr data); + void setSingleAttributeSerializable(EIP_USINT class_id, EIP_USINT instance_id, + EIP_UINT attribute_id, shared_ptr data); /** * Shortcut to set a single attribute from a primitive type @@ -155,6 +157,14 @@ class Session make_shared< SerializablePrimitive > (v); setSingleAttributeSerializable(class_id, instance_id, attribute_id, data); } + template + void setSingleAttribute(EIP_USINT class_id, EIP_USINT instance_id, + EIP_UINT attribute_id, T v) + { + shared_ptr< SerializablePrimitive > data = + make_shared< SerializablePrimitive > (v); + setSingleAttributeSerializable(class_id, instance_id, attribute_id, data); + } /** * Create an Ethernet/IP Connection for sending implicit messages diff --git a/src/session.cpp b/src/session.cpp index dd3f2e3..6c7d4a5 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -253,6 +253,12 @@ void Session::setSingleAttributeSerializable(EIP_USINT class_id, RRDataResponse resp_data = sendRRDataCommand(0x10, Path(class_id, instance_id, attribute_id), data); } +void Session::setSingleAttributeSerializable(EIP_USINT class_id, + EIP_USINT instance_id, EIP_UINT attribute_id, shared_ptr data) +{ + RRDataResponse resp_data = sendRRDataCommand(0x10, + Path(class_id, instance_id, attribute_id), data); +} RRDataResponse Session::sendRRDataCommand(EIP_USINT service, const Path& path, shared_ptr data) From 1801f701e331ce102dfb288553180e71cfd5caf8 Mon Sep 17 00:00:00 2001 From: andreucm Date: Wed, 7 Feb 2018 01:06:34 +0100 Subject: [PATCH 4/4] Reimplements the print functionality at Path class (formerly Path::print()) by overloading the operator << to a given ostream. --- include/odva_ethernetip/path.h | 18 ++++++++++++++++-- src/path.cpp | 18 ------------------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/include/odva_ethernetip/path.h b/include/odva_ethernetip/path.h index 53d6095..abc63b9 100644 --- a/include/odva_ethernetip/path.h +++ b/include/odva_ethernetip/path.h @@ -27,6 +27,8 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #define ODVA_ETHERNETIP_PATH_H #include +#include +#include #include "odva_ethernetip/eip_types.h" #include "odva_ethernetip/serialization/reader.h" @@ -170,9 +172,21 @@ class Path } /** - * Prints path bytes at std output + * Prints path bytes to a given output stream */ - void print() const; + friend std::ostream& operator<<(std::ostream& os, const Path& p) + { + os << "PATH: "; + os.setf(std::ios_base::hex , std::ios_base::basefield); + for (unsigned int ii=0; ii< p.path_buf_.size(); ii++) + { + os << std::setw(2) << std::setfill('0') << (unsigned short int)p.path_buf_.at(ii); + if ( (ii+1)%2 == 0 ) os << " "; + } + os << std::endl; + os.setf(std::ios_base::dec , std::ios_base::basefield); + return os; + } private: bool pad_after_length_; diff --git a/src/path.cpp b/src/path.cpp index 06c5118..068b5c3 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -27,10 +27,6 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI #include -#include -#include -#include - namespace eip { Path::Path(bool pad_after_length) : pad_after_length_(pad_after_length) @@ -45,7 +41,6 @@ Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, addLogicalClass(class_id); addLogicalInstance(instance_id); addLogicalAttribute(attribute_id); - //this->print(); } Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_UINT attribute_id, @@ -55,7 +50,6 @@ Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_UINT attribute_id, addLogicalClass(class_id); addLogicalInstance(instance_id); addLogicalAttribute(attribute_id); - //this->print(); } @@ -64,7 +58,6 @@ Path::Path(EIP_USINT class_id, EIP_USINT instance_id) : pad_after_length_(false) path_buf_.reserve(4); addLogicalClass(class_id); addLogicalInstance(instance_id); - //this->print(); } void Path::addSegment(EIP_USINT type, EIP_USINT data) @@ -123,15 +116,4 @@ Writer& Path::serialize(Writer& writer, bool pad_after_length) const return writer; } -void Path::print() const -{ - std::cout << "PATH: "; - for (unsigned int ii=0; ii< path_buf_.size(); ii++) - { - std::cout << std::hex << std::setfill('0') << std::setw(2) << (unsigned short int)path_buf_.at(ii); - if ( (ii+1)%2 == 0 ) std::cout << " "; - } - std::cout << std::dec << std::endl; -} - } // namespace eip