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

Add support for guard conditions #103

Merged
Merged
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
44 changes: 23 additions & 21 deletions rcldotnet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ set(CSHARP_TARGET_FRAMEWORK "netstandard2.0")

set(CS_SOURCES
Client.cs
GuardCondition.cs
MessageStaticMemberCache.cs
Node.cs
Publisher.cs
RCLdotnet.cs
RCLExceptionHelper.cs
RCLRet.cs
SafeClientHandle.cs
SafeGuardConditionHandle.cs
SafeNodeHandle.cs
SafePublisherHandle.cs
SafeRequestIdHandle.cs
Expand All @@ -62,29 +64,28 @@ add_dotnet_library(${PROJECT_NAME}_assemblies
install_dotnet(${PROJECT_NAME}_assemblies DESTINATION lib/${PROJECT_NAME}/dotnet)
ament_export_assemblies_dll("lib/${PROJECT_NAME}/dotnet/${PROJECT_NAME}_assemblies.dll")

set(_native_sources "rcldotnet;rcldotnet_node;rcldotnet_publisher;rcldotnet_client")
add_library(${PROJECT_NAME}_native SHARED
rcldotnet_client.c
rcldotnet_guard_condition.c
rcldotnet_node.c
rcldotnet_publisher.c
rcldotnet.c
)

foreach(_target_name ${_native_sources})
add_library(${_target_name} SHARED
${_target_name}.c
)
set_target_properties(${_target_name}
PROPERTIES
OUTPUT_NAME ${_target_name}_native)
ament_target_dependencies(${_target_name}
"builtin_interfaces"
"rcl"
"rosidl_generator_c"
"rosidl_typesupport_c"
)
ament_export_libraries(${_target_name}_native)
ament_target_dependencies(${PROJECT_NAME}_native
"builtin_interfaces"
"rcl"
"rosidl_generator_c"
"rosidl_typesupport_c"
)

install(TARGETS ${_target_name}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
endforeach()
ament_export_libraries(${PROJECT_NAME}_native)

install(TARGETS ${PROJECT_NAME}_native
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)

ament_export_dependencies(ament_cmake)
ament_export_dependencies(builtin_interfaces)
Expand Down Expand Up @@ -120,6 +121,7 @@ if(BUILD_TESTING)
${RCLDOTNET_TEST_TARGET_FRAMEWORK}
SOURCES
${CS_SOURCES}
test/test_guard_conditions.cs
test/test_messages.cs
test/test_services.cs
INCLUDE_DLLS
Expand Down
2 changes: 1 addition & 1 deletion rcldotnet/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal delegate RCLRet NativeRCLServiceServerIsAvailableType(
static ClientDelegates()
{
_dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils();
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet_client");
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet");

IntPtr native_rcl_send_request_ptr = _dllLoadUtils.GetProcAddress(nativeLibrary, "native_rcl_send_request");
ClientDelegates.native_rcl_send_request = (NativeRCLSendRequestType)Marshal.GetDelegateForFunctionPointer(
Expand Down
71 changes: 71 additions & 0 deletions rcldotnet/GuardCondition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* Copyright 2022 Stefan Hoffmann <stefan.hoffmann@schiller.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System;
using System.Runtime.InteropServices;
using ROS2.Utils;

namespace ROS2
{
internal static class GuardConditionDelegates
{
internal static readonly DllLoadUtils _dllLoadUtils;

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate RCLRet NativeRCLTriggerGuardConditionType(
SafeGuardConditionHandle guardConditionHandle);

internal static NativeRCLTriggerGuardConditionType native_rcl_trigger_guard_condition = null;

static GuardConditionDelegates()
{
_dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils();
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet");

IntPtr native_rcl_trigger_guard_condition_ptr = _dllLoadUtils.GetProcAddress(nativeLibrary, "native_rcl_trigger_guard_condition");
GuardConditionDelegates.native_rcl_trigger_guard_condition = (NativeRCLTriggerGuardConditionType)Marshal.GetDelegateForFunctionPointer(
native_rcl_trigger_guard_condition_ptr, typeof(NativeRCLTriggerGuardConditionType));
}
}

public sealed class GuardCondition
{
private readonly Action _callback;

internal GuardCondition(SafeGuardConditionHandle handle, Action callback)
{
Handle = handle;
_callback = callback;
}

// GuardCondition does intentionally (for now) not implement IDisposable as this
// needs some extra consideration how the type works after its
// internal handle is disposed.
// By relying on the GC/Finalizer of SafeHandle the handle only gets
// Disposed if the publisher is not live anymore.
internal SafeGuardConditionHandle Handle { get; }

public void Trigger()
{
RCLRet ret = GuardConditionDelegates.native_rcl_trigger_guard_condition(Handle);
RCLExceptionHelper.CheckReturnValue(ret, $"{nameof(GuardConditionDelegates.native_rcl_trigger_guard_condition)}() failed.");
}

internal void TriggerCallback()
{
_callback();
}
}
}
23 changes: 21 additions & 2 deletions rcldotnet/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ internal delegate RCLRet NativeRCLDestroyClientHandleType(
static NodeDelegates()
{
_dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils();
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet_node");
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet");

IntPtr native_rcl_create_publisher_handle_ptr = _dllLoadUtils.GetProcAddress(
nativeLibrary, "native_rcl_create_publisher_handle");
Expand Down Expand Up @@ -137,19 +137,21 @@ static NodeDelegates()

public sealed class Node
{

private readonly IList<Subscription> _subscriptions;

private readonly IList<Service> _services;

private readonly IList<Client> _clients;

private readonly IList<GuardCondition> _guardConditions;

internal Node(SafeNodeHandle handle)
{
Handle = handle;
_subscriptions = new List<Subscription>();
_services = new List<Service>();
_clients = new List<Client>();
_guardConditions = new List<GuardCondition>();
}

public IList<Subscription> Subscriptions => _subscriptions;
Expand All @@ -161,6 +163,8 @@ internal Node(SafeNodeHandle handle)

public IList<Client> Clients => _clients;

public IList<GuardCondition> GuardConditions => _guardConditions;

// Node does intentionaly (for now) not implement IDisposable as this
// needs some extra consideration how the type works after its
// internal handle is disposed.
Expand Down Expand Up @@ -248,5 +252,20 @@ public Client<TService, TRequest, TResponse> CreateClient<TService, TRequest, TR
_clients.Add(client);
return client;
}

public GuardCondition CreateGuardCondition(Action callback)
{
var guardConditionHandle = new SafeGuardConditionHandle();
RCLRet ret = RCLdotnetDelegates.native_rcl_create_guard_condition_handle(ref guardConditionHandle);
if (ret != RCLRet.Ok)
{
guardConditionHandle.Dispose();
throw RCLExceptionHelper.CreateFromReturnValue(ret, $"{nameof(RCLdotnetDelegates.native_rcl_create_guard_condition_handle)}() failed.");
}

var guardCondition = new GuardCondition(guardConditionHandle, callback);
_guardConditions.Add(guardCondition);
return guardCondition;
}
}
}
2 changes: 1 addition & 1 deletion rcldotnet/Publisher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal delegate RCLRet NativeRCLPublishType(
static PublisherDelegates()
{
_dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils();
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet_publisher");
IntPtr nativeLibrary = _dllLoadUtils.LoadLibrary("rcldotnet");

IntPtr native_rcl_publish_ptr = _dllLoadUtils.GetProcAddress(nativeLibrary, "native_rcl_publish");
PublisherDelegates.native_rcl_publish = (NativeRCLPublishType)Marshal.GetDelegateForFunctionPointer(
Expand Down
Loading