279 lines
8.7 KiB
C++
279 lines
8.7 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/**
|
|
Copyright (c) 2016 - 2022 Beckhoff Automation GmbH & Co. KG
|
|
*/
|
|
|
|
#include "AdsDevice.h"
|
|
#include "AdsException.h"
|
|
#include "AdsLib.h"
|
|
#include "Log.h"
|
|
#include <limits>
|
|
|
|
namespace Beckhoff
|
|
{
|
|
namespace Ads
|
|
{
|
|
static AmsNetId* Connect(AmsNetId ams, const char* ip)
|
|
{
|
|
const auto error = ConnectTarget(ams, ip);
|
|
if (error) {
|
|
if(error == ROUTERERR_PORTALREADYINUSE){
|
|
LOG_INFO("Connection["<<ip<<"] has been built.");
|
|
return new AmsNetId { ams };
|
|
}
|
|
|
|
return new AmsNetId { 0, 0, 0, 0, 1, 1 };
|
|
}
|
|
return new AmsNetId { ams };
|
|
}
|
|
|
|
AdsDevice::AdsDevice(const std::string& ipV4, AmsNetId amsNetId, uint16_t port)
|
|
: m_NetId(Connect(amsNetId, ipV4.c_str()), {[](AmsNetId ams){DisconnectTarget(ams); return 0; }}),
|
|
m_Addr({amsNetId, port}),
|
|
m_LocalPort(new long { OpenLocalPort() }, { CloseLocalPort }),
|
|
m_Connected(false)
|
|
{
|
|
if(*m_NetId.get() == amsNetId) {
|
|
m_Connected = true;
|
|
}
|
|
}
|
|
|
|
long AdsDevice::DeleteNotificationHandle(uint32_t handle) const
|
|
{
|
|
if (handle) {
|
|
return AdsSyncDelDeviceNotificationReqEx(GetLocalPort(), &m_Addr, handle);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
long AdsDevice::CloseFile(uint32_t handle) const
|
|
{
|
|
return ReadWriteReqEx2(SYSTEMSERVICE_FCLOSE, handle, 0, nullptr, 0, nullptr, nullptr);
|
|
}
|
|
|
|
long AdsDevice::DeleteSymbolHandle(uint32_t handle) const
|
|
{
|
|
if(handle){
|
|
return WriteReqEx(ADSIGRP_SYM_RELEASEHND, 0, sizeof(handle), &handle);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
AdsDeviceInfo AdsDevice::GetDeviceInfo() const
|
|
{
|
|
AdsDeviceInfo info;
|
|
if(m_Connected == true){
|
|
auto error = AdsSyncReadDeviceInfoReqEx(GetLocalPort(),
|
|
&m_Addr,
|
|
&info.name[0],
|
|
&info.version);
|
|
|
|
if (error) {
|
|
LOG_ERROR("AdsDevice can not read device info.");
|
|
//throw AdsException(error);
|
|
}
|
|
}
|
|
return info;
|
|
}
|
|
|
|
AdsHandle AdsDevice::GetHandle(const uint32_t offset) const
|
|
{
|
|
uint32_t handle = offset;
|
|
if(m_Connected == false){
|
|
handle = 0;
|
|
LOG_WARN("AdsDevice GetHandle is failed.");
|
|
}
|
|
return {new uint32_t {offset}, {[](uint32_t){ return 0; }}};
|
|
}
|
|
|
|
AdsHandle AdsDevice::GetHandle(const std::string& symbolName) const
|
|
{
|
|
if(m_Connected == true)
|
|
{
|
|
uint32_t handle = 0;
|
|
uint32_t bytesRead = 0;
|
|
uint32_t error = ReadWriteReqEx2(
|
|
ADSIGRP_SYM_HNDBYNAME, 0,
|
|
sizeof(handle), &handle,
|
|
symbolName.size(),
|
|
symbolName.c_str(),
|
|
&bytesRead
|
|
);
|
|
|
|
if (error || (sizeof(handle) != bytesRead)) {
|
|
LOG_ERROR("AdsDevice GetSymbolHandle is failed: "<<symbolName<<".");
|
|
//throw AdsException(error);
|
|
}else{
|
|
handle = Beckhoff::letoh(handle);
|
|
return {new uint32_t {handle}, {std::bind(&AdsDevice::DeleteSymbolHandle, this, std::placeholders::_1)}};
|
|
}
|
|
}
|
|
return {new uint32_t {0}, {[](uint32_t){ return 0; }}};
|
|
}
|
|
|
|
AdsHandle AdsDevice::GetHandle(const uint32_t indexGroup,
|
|
const uint32_t indexOffset,
|
|
const AdsNotificationAttrib& notificationAttributes,
|
|
PAdsNotificationFuncEx callback,
|
|
const uint32_t hUser) const
|
|
{
|
|
if(m_Connected == true){
|
|
uint32_t handle = 0;
|
|
auto error = AdsSyncAddDeviceNotificationReqEx(
|
|
*m_LocalPort, &m_Addr,
|
|
indexGroup, indexOffset,
|
|
¬ificationAttributes,
|
|
callback,
|
|
hUser,
|
|
&handle);
|
|
if (error || !handle) {
|
|
LOG_WARN("AdsDevice GetNotificationHandle is failed.");
|
|
//throw AdsException(error);
|
|
}else{
|
|
handle = Beckhoff::letoh(handle);
|
|
return {new uint32_t {handle}, {std::bind(&AdsDevice::DeleteNotificationHandle, this, std::placeholders::_1)}};
|
|
}
|
|
}
|
|
return {new uint32_t {0}, {[](uint32_t){ return 0; }}};
|
|
}
|
|
|
|
long AdsDevice::GetLocalPort() const
|
|
{
|
|
return *m_LocalPort;
|
|
}
|
|
|
|
AdsDeviceState AdsDevice::GetState() const
|
|
{
|
|
uint16_t state[2];
|
|
if(m_Connected == true){
|
|
auto error = AdsSyncReadStateReqEx(GetLocalPort(), &m_Addr, &state[0], &state[1]);
|
|
if (error) {
|
|
LOG_ERROR("AdsDevice can not read device state.");
|
|
//throw AdsException(error);
|
|
}
|
|
|
|
for (auto i : state) {
|
|
if (i >= ADSSTATE::ADSSTATE_MAXSTATES) {
|
|
//throw std::out_of_range("Unknown ADSSTATE(" + std::to_string(i) + ')');
|
|
LOG_ERROR("AdsDevice unkown device state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
return {static_cast<ADSSTATE>(state[0]), static_cast<ADSSTATE>(state[1])};
|
|
}
|
|
|
|
void AdsDevice::SetState(const ADSSTATE AdsState, const ADSSTATE DeviceState) const
|
|
{
|
|
if(m_Connected == true){
|
|
auto error = AdsSyncWriteControlReqEx(GetLocalPort(),
|
|
&m_Addr,
|
|
AdsState,
|
|
DeviceState,
|
|
0, nullptr);
|
|
|
|
if (error) {
|
|
//throw AdsException(error);
|
|
LOG_ERROR("AdsDevice set device state failed.");
|
|
}
|
|
}
|
|
}
|
|
|
|
void AdsDevice::SetTimeout(const uint32_t timeout) const
|
|
{
|
|
if(m_Connected == true){
|
|
const auto error = AdsSyncSetTimeoutEx(GetLocalPort(), timeout);
|
|
if (error) {
|
|
//throw AdsException(error);
|
|
LOG_ERROR("AdsDevice set timeout failed.");
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t AdsDevice::GetTimeout() const
|
|
{
|
|
uint32_t timeout = 0;
|
|
if(m_Connected == true){
|
|
const auto error = AdsSyncGetTimeoutEx(GetLocalPort(), &timeout);
|
|
if (error) {
|
|
//throw AdsException(error);
|
|
LOG_ERROR("AdsDevice get timeout failed.");
|
|
}
|
|
}
|
|
return timeout;
|
|
}
|
|
|
|
AdsHandle AdsDevice::OpenFile(const std::string& filename, const uint32_t flags) const
|
|
{
|
|
if(m_Connected == true){
|
|
uint32_t bytesRead = 0;
|
|
uint32_t handle = 0;
|
|
const auto error = ReadWriteReqEx2(SYSTEMSERVICE_FOPEN,
|
|
flags,
|
|
sizeof(handle),
|
|
&handle,
|
|
filename.length(),
|
|
filename.c_str(),
|
|
&bytesRead);
|
|
|
|
if (error) {
|
|
//throw AdsException(error);
|
|
LOG_ERROR("AdsDevice open file failed.");
|
|
}else{
|
|
handle = Beckhoff::letoh(handle);
|
|
return {new uint32_t {handle}, {std::bind(&AdsDevice::CloseFile, this, std::placeholders::_1)}};
|
|
}
|
|
}
|
|
return {new uint32_t {0}, {[](uint32_t){ return 0; }}};
|
|
}
|
|
|
|
long AdsDevice::ReadReqEx2(uint32_t group, uint32_t offset, size_t length, void* buffer, uint32_t* bytesRead) const
|
|
{
|
|
if(m_Connected == false)
|
|
return ROUTERERR_HOSTDENY;
|
|
|
|
if (length > std::numeric_limits<uint32_t>::max()) {
|
|
return ADSERR_DEVICE_INVALIDSIZE;
|
|
}
|
|
return AdsSyncReadReqEx2(*m_LocalPort, &m_Addr, group, offset, static_cast<uint32_t>(length), buffer, bytesRead);
|
|
}
|
|
|
|
long AdsDevice::ReadWriteReqEx2(uint32_t indexGroup,
|
|
uint32_t indexOffset,
|
|
size_t readLength,
|
|
void* readData,
|
|
size_t writeLength,
|
|
const void* writeData,
|
|
uint32_t* bytesRead) const
|
|
{
|
|
if(m_Connected == false)
|
|
return ROUTERERR_HOSTDENY;
|
|
|
|
if (readLength > std::numeric_limits<uint32_t>::max()) {
|
|
return ADSERR_DEVICE_INVALIDSIZE;
|
|
}
|
|
if (writeLength > std::numeric_limits<uint32_t>::max()) {
|
|
return ADSERR_DEVICE_INVALIDSIZE;
|
|
}
|
|
return AdsSyncReadWriteReqEx2(GetLocalPort(),
|
|
&m_Addr,
|
|
indexGroup, indexOffset,
|
|
static_cast<uint32_t>(readLength), readData,
|
|
static_cast<uint32_t>(writeLength), writeData,
|
|
bytesRead
|
|
);
|
|
}
|
|
|
|
long AdsDevice::WriteReqEx(uint32_t group, uint32_t offset, size_t length, const void* buffer) const
|
|
{
|
|
if(m_Connected == false)
|
|
return ROUTERERR_HOSTDENY;
|
|
|
|
if (length > std::numeric_limits<uint32_t>::max()) {
|
|
return ADSERR_DEVICE_INVALIDSIZE;
|
|
}
|
|
return AdsSyncWriteReqEx(GetLocalPort(), &m_Addr, group, offset, static_cast<uint32_t>(length), buffer);
|
|
}
|
|
}
|
|
}
|