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

Allow std::function as callback for AdsNotification #204

Draft
wants to merge 2 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
46 changes: 41 additions & 5 deletions AdsLib/AdsDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
#include "AdsException.h"
#include "AdsLib.h"
#include <limits>
#include "Log.h"

std::mutex AdsDevice::m_CallbackMutex;
uint32_t AdsDevice::m_NextCallbackHandle = 0x80000000;
std::unordered_map<uint32_t, PAdsNotificationFuncExFunc> AdsDevice::m_FuncCallbacks;

static AmsNetId* AddRoute(AmsNetId ams, const char* ip)
{
Expand All @@ -23,8 +28,9 @@ AdsDevice::AdsDevice(const std::string& ipV4, AmsNetId netId, uint16_t port)
m_LocalPort(new long { AdsPortOpenEx() }, {AdsPortCloseEx})
{}

long AdsDevice::DeleteNotificationHandle(uint32_t handle) const
long AdsDevice::DeleteNotificationHandle(uint32_t handle, uint32_t hUser) const
{
AdsDevice::DeleteFuncCallback(hUser);
if (handle) {
return AdsSyncDelDeviceNotificationReqEx(GetLocalPort(), &m_Addr, handle);
}
Expand All @@ -41,6 +47,7 @@ long AdsDevice::DeleteSymbolHandle(uint32_t handle) const
return WriteReqEx(ADSIGRP_SYM_RELEASEHND, 0, sizeof(handle), &handle);
}


DeviceInfo AdsDevice::GetDeviceInfo() const
{
DeviceInfo info;
Expand Down Expand Up @@ -83,22 +90,23 @@ AdsHandle AdsDevice::GetHandle(const std::string& symbolName) const
AdsHandle AdsDevice::GetHandle(const uint32_t indexGroup,
const uint32_t indexOffset,
const AdsNotificationAttrib& notificationAttributes,
PAdsNotificationFuncEx callback,
const uint32_t hUser) const
PAdsNotificationFuncExFunc callback) const
{
uint32_t handle = 0;
uint32_t hUser = AdsDevice::AddFuncCallback(callback);
auto error = AdsSyncAddDeviceNotificationReqEx(
*m_LocalPort, &m_Addr,
indexGroup, indexOffset,
&notificationAttributes,
callback,
&AdsDevice::CallFuncCallback,
hUser,
&handle);
if (error || !handle) {
AdsDevice::DeleteFuncCallback(hUser);
throw AdsException(error);
}
handle = bhf::ads::letoh(handle);
return {new uint32_t {handle}, {std::bind(&AdsDevice::DeleteNotificationHandle, this, std::placeholders::_1)}};
return {new uint32_t {handle}, {std::bind(&AdsDevice::DeleteNotificationHandle, this, std::placeholders::_1, hUser)}};
}

long AdsDevice::GetLocalPort() const
Expand Down Expand Up @@ -214,3 +222,31 @@ long AdsDevice::WriteReqEx(uint32_t group, uint32_t offset, size_t length, const
}
return AdsSyncWriteReqEx(GetLocalPort(), &m_Addr, group, offset, static_cast<uint32_t>(length), buffer);
}

uint32_t AdsDevice::AddFuncCallback(PAdsNotificationFuncExFunc callback)
{
std::lock_guard<decltype(m_CallbackMutex)> lock(m_CallbackMutex);
m_FuncCallbacks.insert(std::make_pair(m_NextCallbackHandle, callback));
return m_NextCallbackHandle++;
}

void AdsDevice::DeleteFuncCallback(uint32_t handle)
{
std::lock_guard<decltype(m_CallbackMutex)> lock(m_CallbackMutex);
if(m_FuncCallbacks.erase(handle) == 0)
{
LOG_WARN("Handle " << handle << " has already been deleted.");
}
}

void AdsDevice::CallFuncCallback(CONST AmsAddr* pAddr, const AdsNotificationHeader* pNotification, uint32_t hUser)
{
std::lock_guard<decltype(m_CallbackMutex)> lock(m_CallbackMutex);
auto it = m_FuncCallbacks.find(hUser);
if(it == m_FuncCallbacks.end())
{
LOG_WARN("Callback for handle " << hUser << " not found.");
return;
}
it->second(pAddr, pNotification);
}
16 changes: 13 additions & 3 deletions AdsLib/AdsDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <cstdint>
#include <functional>
#include <memory>
#include <unordered_map>
#include <mutex>

/**
* @brief Maximum size for device name.
Expand Down Expand Up @@ -52,6 +54,8 @@ using AdsResource = std::unique_ptr<T, ResourceDeleter<T> >;

using AdsHandle = AdsResource<uint32_t>;

typedef std::function<void (const AmsAddr* pAddr, const AdsNotificationHeader* pNotification)> PAdsNotificationFuncExFunc;

struct AdsDevice {
AdsDevice(const std::string& ipV4, AmsNetId netId, uint16_t port);

Expand All @@ -67,8 +71,7 @@ struct AdsDevice {
AdsHandle GetHandle(uint32_t indexGroup,
uint32_t indexOffset,
const AdsNotificationAttrib& notificationAttributes,
PAdsNotificationFuncEx callback,
uint32_t hUser) const;
PAdsNotificationFuncExFunc callback) const;

/** Get handle to access files */
AdsHandle OpenFile(const std::string& filename, uint32_t flags) const;
Expand Down Expand Up @@ -96,6 +99,13 @@ struct AdsDevice {
private:
AdsResource<const long> m_LocalPort;
long CloseFile(uint32_t handle) const;
long DeleteNotificationHandle(uint32_t handle) const;
long DeleteNotificationHandle(uint32_t handle, uint32_t hUser) const;
long DeleteSymbolHandle(uint32_t handle) const;

static std::mutex m_CallbackMutex;
static uint32_t m_NextCallbackHandle;
static std::unordered_map<uint32_t, PAdsNotificationFuncExFunc> m_FuncCallbacks;
static uint32_t AddFuncCallback(PAdsNotificationFuncExFunc callback);
static void DeleteFuncCallback(uint32_t handle);
static void CallFuncCallback(const AmsAddr* pAddr, const AdsNotificationHeader* pNotification, uint32_t hUser);
};
35 changes: 31 additions & 4 deletions AdsLib/AdsNotificationOOI.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ struct AdsNotification {
uint32_t hUser)
: m_Symbol(route.GetHandle(symbolName)),
m_Notification(route.GetHandle(ADSIGRP_SYM_VALBYHND, *m_Symbol, notificationAttributes,
reinterpret_cast<PAdsNotificationFuncEx>(callback), hUser))
[hUser, callback](const AmsAddr* pAddr, const AdsNotificationHeader* pNotification){
callback(pAddr, pNotification, hUser);
}))
{}

AdsNotification(const AdsDevice& route,
const std::string& symbolName,
const AdsNotificationAttrib& notificationAttributes,
PAdsNotificationFuncExFunc callback)
: m_Symbol(route.GetHandle(symbolName)),
m_Notification(route.GetHandle(ADSIGRP_SYM_VALBYHND, *m_Symbol, notificationAttributes,
callback))
{}

AdsNotification(const AdsDevice& route,
Expand All @@ -29,7 +40,9 @@ struct AdsNotification {
uint32_t hUser)
: m_Symbol(route.GetHandle(symbolName)),
m_Notification(route.GetHandle(ADSIGRP_SYM_VALBYHND, *m_Symbol, notificationAttributes,
reinterpret_cast<PAdsNotificationFuncEx>(callback), hUser))
[hUser, callback](const AmsAddr* pAddr, const AdsNotificationHeader* pNotification){
callback(const_cast<AmsAddr*>(pAddr), const_cast<AdsNotificationHeader*>(pNotification), hUser);
}))
{}

AdsNotification(const AdsDevice& route,
Expand All @@ -40,7 +53,19 @@ struct AdsNotification {
uint32_t hUser)
: m_Symbol{route.GetHandle(indexOffset)},
m_Notification(route.GetHandle(indexGroup, indexOffset, notificationAttributes,
reinterpret_cast<PAdsNotificationFuncEx>(callback), hUser))
[hUser, callback](const AmsAddr* pAddr, const AdsNotificationHeader* pNotification){
callback(pAddr, pNotification, hUser);
}))
{}

AdsNotification(const AdsDevice& route,
uint32_t indexGroup,
uint32_t indexOffset,
const AdsNotificationAttrib& notificationAttributes,
PAdsNotificationFuncExFunc callback)
: m_Symbol{route.GetHandle(indexOffset)},
m_Notification(route.GetHandle(indexGroup, indexOffset, notificationAttributes,
callback))
{}

AdsNotification(const AdsDevice& route,
Expand All @@ -51,7 +76,9 @@ struct AdsNotification {
uint32_t hUser)
: m_Symbol{route.GetHandle(indexOffset)},
m_Notification(route.GetHandle(indexGroup, indexOffset, notificationAttributes,
reinterpret_cast<PAdsNotificationFuncEx>(callback), hUser))
[hUser, callback](const AmsAddr* pAddr, const AdsNotificationHeader* pNotification){
callback(const_cast<AmsAddr*>(pAddr), const_cast<AdsNotificationHeader*>(pNotification), hUser);
}))
{}

private:
Expand Down
9 changes: 8 additions & 1 deletion AdsLib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ set(SOURCES
RTimeAccess.cpp
Sockets.cpp

RegistryAccess.cpp
SymbolAccess.cpp

bhf/ParameterList.cpp

standalone/AdsLib.cpp
standalone/AmsConnection.cpp
standalone/AmsNetId.cpp
Expand All @@ -19,8 +24,10 @@ set(SOURCES
)

add_library(ads ${SOURCES})
add_library(ads::ads ALIAS ads)

target_include_directories(ads PUBLIC .)
target_include_directories(ads PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/ads>)

if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_link_libraries(ads PUBLIC wsock32)
Expand Down
2 changes: 2 additions & 0 deletions AdsTool/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_executable(AdsTool main.cpp)
target_link_libraries(AdsTool PUBLIC ads::ads)
49 changes: 49 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,54 @@ add_definitions(-DCONFIG_DEFAULT_LOGLEVEL=1)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

add_subdirectory(AdsLib)
add_subdirectory(AdsTool)
add_subdirectory(AdsLibTest)
add_subdirectory(example)


# Install library
include(GenerateExportHeader)
set(ADSLIB_VERSION 0.0.20)

set_property(TARGET ads PROPERTY VERSION ${ADSLIB_VERSION})
set_property(TARGET ads PROPERTY SOVERSION 3)


# export library (either static or shared depending on BUILD_SHARED_LIBS)
install(TARGETS ads AdsTool
EXPORT adsTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/AdsLib/ DESTINATION include/ads/
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h")


set(cmake_configfile_install lib/cmake/ads)
set(target_install_dest_name "${cmake_configfile_install}/adsTargets.cmake")

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/adsConfigVersion.cmake"
VERSION ${ADSLIB_VERSION}
COMPATIBILITY AnyNewerVersion
)

configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/adsConfig.cmake"
INSTALL_DESTINATION "${cmake_configfile_install}"
PATH_VARS target_install_dest_name)

install(EXPORT adsTargets
FILE adsTargets.cmake
NAMESPACE ads::
DESTINATION "${cmake_configfile_install}"
EXPORT_LINK_INTERFACE_LIBRARIES)

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/adsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/adsConfigVersion.cmake"
DESTINATION "${cmake_configfile_install}")

3 changes: 3 additions & 0 deletions cmake/Config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@PACKAGE_INIT@

include ("@PACKAGE_target_install_dest_name@")