// 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 #include #include 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); return {new uint32_t {0xffffffff}, {[](uint32_t){ return 0; }}}; } 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] = {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(state[0]), static_cast(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(state[0]), static_cast(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::max()) { return ADSERR_DEVICE_INVALIDSIZE; } return AdsSyncReadReqEx2(*m_LocalPort, &m_Addr, group, offset, static_cast(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::max()) { return ADSERR_DEVICE_INVALIDSIZE; } if (writeLength > std::numeric_limits::max()) { return ADSERR_DEVICE_INVALIDSIZE; } return AdsSyncReadWriteReqEx2(GetLocalPort(), &m_Addr, indexGroup, indexOffset, static_cast(readLength), readData, static_cast(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::max()) { return ADSERR_DEVICE_INVALIDSIZE; } return AdsSyncWriteReqEx(GetLocalPort(), &m_Addr, group, offset, static_cast(length), buffer); } } }