Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impl #63 #98

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ set(SOURCE_FILES
cip/connectionManager/ForwardOpenResponse.cpp
cip/connectionManager/NetworkConnectionParametersBuilder.cpp

cip/segments/ANSISegment.cpp
cip/segments/DataSegment.cpp
cip/segments/ISegment.cpp
cip/segments/LogicalSegment.cpp
cip/segments/MemberIDSegment.cpp

cip/CipRevision.cpp
cip/EPath.cpp
cip/MessageRouterRequest.cpp
Expand Down
69 changes: 64 additions & 5 deletions src/cip/EPath.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
//
// Created by Aleksey Timin on 11/16/19.
//
#include <stdexcept>

#include "utils/Buffer.h"
#include "utils/Logger.h"
#include "EPath.h"

namespace eipScanner {
namespace cip {
using segments::ISegment;
using utils::Buffer;
using utils::Logger;
using utils::LogLevel;

enum class EPathSegmentTypes : CipUsint {
CLASS_8_BITS = 0x20,
Expand All @@ -22,34 +26,60 @@ namespace cip {
: _classId{0}
, _objectId{0}
, _attributeId{0}
, _size{0}{
, _size{0}
, _segments{} {

}

EPath::EPath(CipUint classId)
: _classId{classId}
, _objectId{0}
, _attributeId{0}
, _size{1} {
, _size{1}
, _segments{} {

}

EPath::EPath(CipUint classId, CipUint objectId)
: _classId{classId}
, _objectId{objectId}
, _attributeId{0}
, _size{2} {
, _size{2}
, _segments{} {

}

EPath::EPath(CipUint classId, CipUint objectId, CipUint attributeId)
: _classId{classId}
, _objectId{objectId}
, _attributeId{attributeId}
, _size{3} {
, _size{3}
, _segments{} {

}

EPath::EPath(const std::vector<ISegment::SPtr> &segments)
: _classId{0}
, _objectId{0}
, _attributeId{0}
, _size{0}
, _segments{segments} {

}

std::vector<uint8_t> EPath::packPaddedPath(bool use_8_bit_path_segments) const {
if (!_segments.empty()) {

Buffer buffer;

// Append all encoded segment data together.
for (ISegment::SPtr segment : _segments) {
buffer << segment->data();
}

return buffer.data();
}

if (use_8_bit_path_segments)
{
Buffer buffer(_size*2);
Expand Down Expand Up @@ -103,6 +133,16 @@ namespace cip {
}

CipUsint EPath::getSizeInWords(bool use_8_bit_path_segments) const {
if (!_segments.empty()) {
CipUsint size = 0;

for (ISegment::SPtr segment : _segments) {
size += segment->size();
}

return size / 2;
}

if (use_8_bit_path_segments) {
return _size;
}
Expand All @@ -112,6 +152,19 @@ namespace cip {
}

std::string EPath::toString() const {
if (!_segments.empty()) {
std::stringstream stream;
stream << "[ ";

for (ISegment::SPtr segment : _segments) {
stream << "[header=0x" << std::hex << int(segment->getSegmentHeader()) << std::dec;
stream << ";value=" << segment->toString() << "]";
}

stream << " ]";
return stream.str();
}

std::string msg = "[classId=" + std::to_string(_classId);
if (_size > 1) {
msg += " objectId=" + std::to_string(_objectId);
Expand All @@ -125,6 +178,12 @@ namespace cip {
}

void EPath::expandPaddedPath(const std::vector<uint8_t> &data) {
if (!_segments.empty()) {
Logger(LogLevel::WARNING) << "EPath already contains a collection of segments!"
"Not expanding data!";
return;
}

Buffer buffer(data);

_classId = 0;
Expand Down
63 changes: 61 additions & 2 deletions src/cip/EPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
#ifndef EIPSCANNER_CIP_EPATH_H
#define EIPSCANNER_CIP_EPATH_H

#include <vector>
#include <string>
#include <cstdint>
#include <string>
#include <vector>

#include "Types.h"
#include "segments/ISegment.h"

namespace eipScanner {
namespace cip {
Expand All @@ -19,22 +20,80 @@ namespace cip {
explicit EPath(CipUint classId);
EPath(CipUint classId, CipUint objectId);
EPath(CipUint classId, CipUint objectId, CipUint attributeId);

/**
* @brief Constructs an EPath based on a collection of segments
* @param segments Ordered collection of segments which the EPath should
* consist of
*/
EPath(const std::vector<segments::ISegment::SPtr> &segments);

/**
* @brief packPaddedPath Either encodes the class/object/attribute id
* values to the corresponding logical segments, or asks all segments in
* the segment collection to encode themselves
* @param use_8_bit_path_segments True if using 8bit logical format to
* encode the data, false if using 16bit logical format. Only has effect
* on the class/object/attribute id the EPath was constructed with
* @return Encoded EPath as contiguous sequence of bytes
*/
std::vector<uint8_t> packPaddedPath(bool use_8_bit_path_segments=false) const;

/**
* @brief expandPaddedPath If the EPath was default-constructed, this
* functions allows to fill the EPath with class/object/attribute id
* values, encoded in a user-specified format. However, if the EPath was
* constructed with a collection of segments, this function does nothing
* @param data Class/object/attribute id logical segments encoded in a
* user-specified format
*/
void expandPaddedPath(const std::vector<uint8_t>& data);

CipUint getClassId() const;
CipUint getObjectId() const;
CipUint getAttributeId() const;

/**
* @brief Calculates the total size of the encoded EPath in 16bit words.
* Depending on how the EPath was constructed, either calculates the size
* of the class/object/attribute id logical segments, or asks all segments
* in the collection of segments to measure themselves
* @param use_8_bit_path_segments True if the class/object/attribute id
* logical segments should be counted with an 8bit logical format, false
* if these should be counted as 16bit logical format. Has no effect when
* the EPath was constructed with a collection of segments
* @return The total size of the encoded EPath in 16bit words
*/
CipUsint getSizeInWords(bool use_8_bit_path_segments=false) const;

/**
* @brief Constructs a string representation of the EPath. Depending on
* whether or not the EPath was constructed with a collection of segments
* or a class/object/attribute id, it either constructs a string of the
* EPath with class/object/attribute id values or a representation of
* every segment
* @return String representation of the EPath with class/object/attribute
* id values or string representations of the segments
*/
std::string toString() const;

/**
* @brief Compares the EPath for equality to the other EPath, however,
* it only checks for the class/object/attribute id values. In case of an
* EPath with a segment collection, always returns true
* @param other The EPath to compare this EPath with
* @return True if EPath was constructed with segment collection, independent
* of the equality of those segments OR the class/object/attribute id
* values all match, false if these don't
*/
bool operator==(const EPath& other) const;

private:
CipUint _classId;
CipUint _objectId;
CipUint _attributeId;
CipUsint _size;
std::vector<segments::ISegment::SPtr> _segments;
};
}
}
Expand Down
74 changes: 74 additions & 0 deletions src/cip/segments/ANSISegment.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// Created by Johannes Kauffmann on 08/06/21.
//

#include "ANSISegment.h"

#include <cassert>
#include <vector>

#include "utils/Buffer.h"

namespace eipScanner {
namespace cip {
namespace segments {

using segments::DataSegment;
using utils::Buffer;

ANSISegment::ANSISegment(const std::vector<uint8_t>& data) : DataSegment({})
{
Buffer buffer;

// Stitch header together from the segment type and segment subtype.
CipUsint header = getSegmentHeader();

// Add the header, symbol size and data.
buffer << header << static_cast<CipUsint>(data.size()) << data;

// Add optional padding if the size is of odd length.
if (data.size() % 2 != 0) {
buffer << static_cast<CipUsint>(0x00);
}

_data = buffer.data();

assert(_data.size() >= 2);
}

std::vector<uint8_t> ANSISegment::data() const
{
return _data;
}

uint8_t ANSISegment::size() const
{
return _data.size();
}

uint8_t ANSISegment::getSegmentHeader() const
{
return static_cast<CipUsint>(SegmentType::DATA_SEGMENT)
| static_cast<CipUsint>(SubType::ANSI_EXTENDED_SYMBOL_SEGMENT);
}

std::string ANSISegment::toString() const
{
// Check for empty segment data.
if (_data.size() == 2) {
return {};
}

// Check for possible padding.
int paddingSize = 0;
if (_data.back() == 0x00) {
paddingSize++;
}

// Construct a string without the header and optional padding
return std::string( _data.begin() + 2, _data.end() - paddingSize);
}

}
}
}
59 changes: 59 additions & 0 deletions src/cip/segments/ANSISegment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Created by Johannes Kauffmann on 08/06/21.
//

#ifndef EIPSCANNER_CIP_SEGMENTS_ANSISEGMENT_H
#define EIPSCANNER_CIP_SEGMENTS_ANSISEGMENT_H

#include <memory>

#include "cip/CipString.h"
#include "DataSegment.h"

namespace eipScanner {
namespace cip {
namespace segments {

class ANSISegment final : public DataSegment {
public:

/**
* @brief Constructs a CIP DataSegment of type ANSI Extended Symbol Segment
* and encodes the data with header, symbol length, data and possible padding
* @param data The segment data, excluding details such as length or padding
*/
ANSISegment(const std::vector<uint8_t>& data);

/**
* @brief Gets the total encoded segment data
* @return The encoded segment data
*/
std::vector<uint8_t> data() const override;

/**
* @brief Gets the total size of the encoded segment in bytes
* @return The size of the segment in bytes
*/
uint8_t size() const override;

/**
* @brief Calculates the segment header byte for this ANSI Extended Symbol
* Segment
* @return The segment header for this ANSI Extended Symbol Segment
*/
uint8_t getSegmentHeader() const override;

/**
* @brief Constructs a string representation of the data value of this
* ANSI Extended Symbol Segment
* @return The string representation of the data of this segment
*/
std::string toString() const override;

};

}
}
}

#endif // EIPSCANNER_CIP_SEGMENTS_ANSISEGMENT_H
17 changes: 17 additions & 0 deletions src/cip/segments/DataSegment.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Created by Johannes Kauffmann on 08/06/21.
//

#include "DataSegment.h"

namespace eipScanner {
namespace cip {
namespace segments {

DataSegment::DataSegment(const std::vector<uint8_t> &data)
: ISegment(data) {
}

}
}
}
Loading