map/das-dn/third_party/AdsLib/AdsDevice.cpp
2024-12-13 20:11:21 +08:00

299 lines
9.2 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 <error.h>
#include <string.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;
}
}
AdsDevice::~AdsDevice()
{
if (m_Connected == true)
{
DisconnectTarget(*m_NetId.get());
m_Connected = false;
}
}
void AdsDevice::DisconnectDevice()
{
if (m_Connected == true)
{
DisconnectTarget(*m_NetId.get());
m_Connected = false;
}
}
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,
&notificationAttributes,
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] = {ADSSTATE::ADSSTATE_MAXSTATES, ADSSTATE::ADSSTATE_MAXSTATES};
if(m_Connected == true){
auto error = AdsSyncReadStateReqEx(GetLocalPort(), &m_Addr, &state[0], &state[1]);
if (error) {
LOG_ERROR("AdsDevice can not read device state. \n" << error << strerror(errno));
//throw AdsException(error);
return {static_cast<ADSSTATE>(state[0]), static_cast<ADSSTATE>(state[1])};
}
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);
}
}
}