Skip to content

Commit

Permalink
Merge pull request #33 from Eske/yaskawa_example
Browse files Browse the repository at this point in the history
Adding Objects and Example for reading and writing Assembly Objects o…
  • Loading branch information
jadamroth authored Sep 29, 2020
2 parents 09aea43 + 92d94d5 commit 8080537
Show file tree
Hide file tree
Showing 9 changed files with 624 additions and 1 deletion.
5 changes: 4 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ target_link_libraries(implicit_messaging EIPScanner)
add_executable(parameter_object_example ParameterObjectExample.cpp)
target_link_libraries(parameter_object_example EIPScanner)
add_executable(discovery_example DiscoveryManagerExample.cpp)
target_link_libraries(discovery_example EIPScanner)
target_link_libraries(discovery_example EIPScanner)

add_executable(yaskawa_assembly_object_example vendors/yaskawa/mp3300iec/Yaskawa_AssemblyObjectExample.cpp)
target_link_libraries(yaskawa_assembly_object_example EIPScanner)
197 changes: 197 additions & 0 deletions examples/vendors/yaskawa/mp3300iec/Yaskawa_AssemblyObjectExample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include "cip/Types.h"
#include <functional>
#include <sstream>
#include <fstream>
#include <cip/connectionManager/NetworkConnectionParams.h>
#include "ConnectionManager.h"
#include <DiscoveryManager.h>
#include "FileObject.h"
#include "fileObject/FileObjectState.h"
#include "IdentityObject.h"
#include "IOConnection.h"
#include "ParameterObject.h"
#include "SessionInfo.h"
#include "utils/Logger.h"
#include "utils/Buffer.h"

#include "vendor/yaskawa/mp3300iec/Yaskawa_EPath.h"
#include "vendor/yaskawa/mp3300iec/Yaskawa_MessageRouter.h"
#include "vendor/yaskawa/mp3300iec/Yaskawa_MessageRouterRequest.h"

using namespace eipScanner::cip;
using eipScanner::ConnectionManager;
using eipScanner::DiscoveryManager;
using eipScanner::IdentityObject;
using eipScanner::IOConnection;
using eipScanner::Yaskawa_MessageRouter;
using eipScanner::ParameterObject;
using eipScanner::SessionInfo;
using eipScanner::utils::Buffer;
using eipScanner::utils::Logger;
using eipScanner::utils::LogLevel;
using eipScanner::cip::connectionManager::ConnectionParameters;
using eipScanner::cip::connectionManager::NetworkConnectionParams;

#define YASKAWA_IP_ADDR "192.168.1.2"
#define YASKAWA_PORT 0xAF12
#define YASKAWA_VENDOR_ID 0x2c

#define ASSEMBLY_OBJECT 0x04

#define YASKAWA_INPUT_ASSEMBLY_111 0x6F
#define YASKAWA_OUTPUT_ASSEMBLY_101 0x65

#define ASSEMBLY_INSTANCE_SIZE 128

#define DATA_OFFSET 100

/*
* fillVector - Function to fill up a vector of bytes.
* data_offset: Offset to the first byte you want to start writing
* assembly_instance_size: Size of the instance in bytes
*
* Returns a vector of bytes
*/
std::vector<uint8_t> fillVector(int data_offset, int assembly_instance_size)
{
std::vector<uint8_t> data;

for (int i = 0; i < assembly_instance_size; i++)
{
if (i < data_offset)
data.push_back(0x00);
else
data.push_back(0xDE);
}

return data;
}

/*
* readBuffer - Function to read a buffer into bytes
* buffer: Buffer filled with the response
* assembly_instance_size: Size of the instance in bytes
*
* Returns a vector of bytes
*/
std::vector<uint8_t> readBuffer(Buffer buffer, int assembly_instance_size)
{
uint8_t byte;
std::vector<uint8_t> data;

for (int i = 0; i < assembly_instance_size; i++)
{
buffer >> byte;
data.push_back(byte);
}

return data;
}

/*
* writeAssemblyObject - Writes the Assembly Instance Provided (Please note that the entire instance will be written.)
* si: SessionInfo object holding the connection Information
* assembly_instance: Integer declaring which instance to be written
* data: Vector of Bytes to be written to the Assembly Instance
*
* Returns true if successful.
*/
bool writeAssemblyObject(std::shared_ptr<eipScanner::SessionInfo> si, int assembly_instance, std::vector<uint8_t> data)
{
Yaskawa_MessageRouter messageRouter;

auto response = messageRouter.sendRequest(si
, ServiceCodes::SET_ATTRIBUTE_SINGLE
, Yaskawa_EPath(ASSEMBLY_OBJECT, assembly_instance, 0x03)
, data);

if (response.getGeneralStatusCode() != GeneralStatusCodes::SUCCESS) {
Logger(LogLevel::ERROR) << "Failed to write assembly object";
logGeneralAndAdditionalStatus(response);
return 0;
}

Logger(LogLevel::INFO) << "The device has written successfully.";
return 1;
}

/*
* readAssemblyObject - Reads the Assembly Instance Provided (Please note that the entire instance will be read.)
* si: SessionInfo object holding the connection Information
* assembly_instance: Integer declaring which instance to be read
*
* Returns a vector of bytes that contains the response or nothing if there was an error
*/
std::vector<uint8_t> readAssemblyObject(std::shared_ptr<eipScanner::SessionInfo> si, int assembly_instance)
{
Yaskawa_MessageRouter messageRouter;
std::vector<uint8_t> data_read;
uint8_t firstByte;
int num_bytes;

auto response = messageRouter.sendRequest(si
, ServiceCodes::GET_ATTRIBUTE_SINGLE
, Yaskawa_EPath(ASSEMBLY_OBJECT, assembly_instance, 0x03));

if (response.getGeneralStatusCode() != GeneralStatusCodes::SUCCESS) {
Logger(LogLevel::ERROR) << "Failed to read parameters";
logGeneralAndAdditionalStatus(response);
return data_read;
}

Buffer buffer(response.getData());

num_bytes = 4 * sizeof (buffer);
data_read = readBuffer(buffer, num_bytes);
firstByte = data_read[0];

// converting the byte to uint16_t to properly print with the Logger
Logger(LogLevel::INFO) << "The device has " << num_bytes << " bytes. The first byte contains: " << (uint16_t)firstByte;

return data_read;
}

// Test to read and write assembly objects on the adapter
int main() {

Logger::setLogLevel(LogLevel::DEBUG);
std::vector<uint8_t> data_read;
bool success;

// Connect to the adapter with the given ip address and port number
auto si = std::make_shared<SessionInfo>(YASKAWA_IP_ADDR, YASKAWA_PORT);

// Data to be written -- In this example we just fill it with junk
std::vector<uint8_t> data_write = fillVector(0x00, ASSEMBLY_INSTANCE_SIZE);

// Assembly Object - Perform a read on the output assembly, and then a read and a write on the input assembly
data_read = readAssemblyObject(si, YASKAWA_OUTPUT_ASSEMBLY_101);
data_read = readAssemblyObject(si, YASKAWA_INPUT_ASSEMBLY_111);
success = writeAssemblyObject(si, YASKAWA_INPUT_ASSEMBLY_111, data_write);

return 0;
}

#if 0
// Test to confirm you are connected to a Yaskawa Device
int main() {

Logger::setLogLevel(LogLevel::DEBUG);

DiscoveryManager discoveryManager(YASKAWA_IP_ADDR, YASKAWA_PORT, std::chrono::seconds(1));
auto devices = discoveryManager.discover();

for (auto& device : devices) {
if (device.identityObject.getVendorId() == YASKAWA_VENDOR_ID)
{
Logger(LogLevel::INFO) << "Discovered YASKAWA device: "
<< device.identityObject.getProductName()
<< " with address " << device.socketAddress.toString();
}
}


return 0;
}
#endif

3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ set(SOURCE_FILES
vendor/ra/powerFlex525/DPIFaultObject.cpp
vendor/ra/powerFlex525/DPIFaultCode.cpp
vendor/ra/powerFlex525/DPIFaultParameter.cpp
vendor/yaskawa/mp3300iec/Yaskawa_EPath.cpp
vendor/yaskawa/mp3300iec/Yaskawa_MessageRouter.cpp
vendor/yaskawa/mp3300iec/Yaskawa_MessageRouterRequest.cpp

BaseObject.cpp
ConnectionManager.cpp
Expand Down
165 changes: 165 additions & 0 deletions src/vendor/yaskawa/mp3300iec/Yaskawa_EPath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#include <stdexcept>
#include "utils/Buffer.h"
#include "Yaskawa_EPath.h"

namespace eipScanner {
namespace cip {
using utils::Buffer;

enum class EPathSegmentTypes : CipUsint {
CLASS_8_BITS = 0x20,
CLASS_16_BITS = 0x21,
INSTANCE_8_BITS = 0x24,
INSTANCE_16_BITS = 0x25,
ATTRIBUTE_8_BITS = 0x30,
ATTRIBUTE_16_BITS = 0x31,
};

Yaskawa_EPath::Yaskawa_EPath()
: _classId{0}
, _objectId{0}
, _attributeId{0}
, _size{0}{

}
Yaskawa_EPath::Yaskawa_EPath(CipUsint classId)
: _classId{classId}
, _objectId{0}
, _attributeId{0}
, _size{1} {

}

Yaskawa_EPath::Yaskawa_EPath(CipUsint classId, CipUsint objectId)
: _classId{classId}
, _objectId{objectId}
, _attributeId{0}
, _size{2} {

}

Yaskawa_EPath::Yaskawa_EPath(CipUsint classId, CipUsint objectId, CipUsint attributeId)
: _classId{classId}
, _objectId{objectId}
, _attributeId{attributeId}
, _size{3} {
}

std::vector<uint8_t> Yaskawa_EPath::packPaddedPath() const {
Buffer buffer(_size*2);

auto classSegment = static_cast<CipUsint>(EPathSegmentTypes::CLASS_8_BITS);
buffer << classSegment << _classId;

if (_size > 1) {
auto instanceSegment = static_cast<CipUsint>(EPathSegmentTypes::INSTANCE_8_BITS);
buffer << instanceSegment << _objectId;

if (_size > 2) {
auto attributeSegment = static_cast<CipUsint>(EPathSegmentTypes::ATTRIBUTE_8_BITS);
buffer << attributeSegment << _attributeId;
}
}

return buffer.data();
}


CipUsint Yaskawa_EPath::getClassId() const {
return _classId;
}

CipUsint Yaskawa_EPath::getObjectId() const {
return _objectId;
}

CipUsint Yaskawa_EPath::getAttributeId() const {
return _attributeId;
}

CipUsint Yaskawa_EPath::getSizeInWords() const {
return _size;
}

std::string Yaskawa_EPath::toString() const {
std::string msg = "[classId=" + std::to_string(_classId);
if (_size > 1) {
msg += " objectId=" + std::to_string(_objectId);
if (_size > 2) {
msg += " attributeId=" + std::to_string(_attributeId);
}
}

msg += "]";
return msg;
}

void Yaskawa_EPath::expandPaddedPath(const std::vector<uint8_t> &data) {
Buffer buffer(data);

_classId = 0;
_objectId = 0;
_attributeId = 0;
_size = 0;

for (int i = 0; i < data.size() && !buffer.empty(); ++i) {
EPathSegmentTypes segmentType;
CipUsint ignore = 0;
CipUsint byte;
CipUint word;
buffer >> reinterpret_cast<CipUsint&>(segmentType);
switch (segmentType) {
case EPathSegmentTypes::CLASS_8_BITS:
buffer >> byte;
_classId = byte;
break;
case EPathSegmentTypes::CLASS_16_BITS:
buffer >> ignore >> word;
_classId = word;
break;
case EPathSegmentTypes::INSTANCE_8_BITS:
buffer >> byte;
_objectId = byte;
break;
case EPathSegmentTypes::INSTANCE_16_BITS:
buffer >> ignore >> word;
_objectId = word;
break;
case EPathSegmentTypes::ATTRIBUTE_8_BITS:
buffer >> byte;
_attributeId = byte;
break;
case EPathSegmentTypes::ATTRIBUTE_16_BITS:
buffer >> ignore >> word;
_attributeId = word;
break;
default:
throw std::runtime_error("Unknown EPATH segment =" + std::to_string(static_cast<int>(segmentType)));
}
}

if (!buffer.isValid()) {
throw std::runtime_error("Wrong EPATH format");
}

if (_classId > 0) {
_size++;

if (_objectId > 0) {
_size++;

if (_attributeId > 0) {
_size++;
}
}
}
}

bool Yaskawa_EPath::operator==(const Yaskawa_EPath &other) const {
return _size == other._size
&&_classId == other._classId
&& _objectId == other._objectId
&& _attributeId == other._attributeId;
}
}
}
Loading

0 comments on commit 8080537

Please sign in to comment.