diff --git a/include/odva_ethernetip/path.h b/include/odva_ethernetip/path.h index b51f59a..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" @@ -69,6 +71,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 +111,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 +171,23 @@ class Path throw std::logic_error("Not implemented"); } + /** + * Prints path bytes to a given output stream + */ + 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_; vector path_buf_; @@ -176,6 +198,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..45aeb5c 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 @@ -130,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 @@ -146,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/path.cpp b/src/path.cpp index 2607aa3..068b5c3 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -43,6 +43,16 @@ Path::Path(EIP_USINT class_id, EIP_USINT instance_id, EIP_USINT attribute_id, addLogicalAttribute(attribute_id); } +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); +} + + Path::Path(EIP_USINT class_id, EIP_USINT instance_id) : pad_after_length_(false) { path_buf_.reserve(4); @@ -56,6 +66,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 +88,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); diff --git a/src/session.cpp b/src/session.cpp index 08ede99..6c7d4a5 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; @@ -237,17 +236,34 @@ 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) { 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) { - 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);