diff --git a/README.md b/README.md index 670e5bda..97f2a88c 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ Make sure to source your ROS2 Dashing environment ``` mkdir -p ~/ros2_dotnet_ws/src cd ~/ros2_dotnet_ws -wget https://raw.githubusercontent.com/adamdbrw/ros2_dotnet/master/ros2_dotnet_dashing.repos +wget https://raw.githubusercontent.com/samiamlabs/ros2_dotnet/master/ros2_dotnet_dashing.repos vcs import ~/ros2_dotnet_ws/src < ros2_dotnet_dashing.repos -colcon build --merge-install +colcon build ``` Running. Source install/setup.bash in both terminals: diff --git a/rcldotnet_tests/CMakeLists.txt b/rcldotnet_tests/CMakeLists.txt index 0d3566f1..29d2d330 100644 --- a/rcldotnet_tests/CMakeLists.txt +++ b/rcldotnet_tests/CMakeLists.txt @@ -5,8 +5,10 @@ project(rcldotnet_tests C) find_package(ament_cmake REQUIRED) find_package(rcldotnet REQUIRED) find_package(rcldotnet_common REQUIRED) +find_package(sensor_msgs REQUIRED) find_package(std_msgs REQUIRED) find_package(test_msgs REQUIRED) +find_package(tf2_msgs REQUIRED) find_package(dotnet_cmake_module REQUIRED) find_package(rosidl_generator_cs REQUIRED) @@ -16,8 +18,11 @@ find_package(DotNETExtra REQUIRED) set(_assemblies_dep_dlls ${rcldotnet_common_ASSEMBLIES_DLL} ${rcldotnet_ASSEMBLIES_DLL} + ${sensor_msgs_ASSEMBLIES_DLL} ${std_msgs_ASSEMBLIES_DLL} ${test_msgs_ASSEMBLIES_DLL} + ${tf2_msgs_ASSEMBLIES_DLL} + ${geometry_msgs_ASSEMBLIES_DLL} ${rosidl_generator_ASSEMBLIES_DLL} ) diff --git a/rcldotnet_tests/LargeMessageTest.cs b/rcldotnet_tests/LargeMessageTest.cs deleted file mode 100644 index 689fb324..00000000 --- a/rcldotnet_tests/LargeMessageTest.cs +++ /dev/null @@ -1,55 +0,0 @@ -using NUnit.Framework; -using System; -using System.Linq; - -namespace rclcs.Test -{ - [TestFixture] - public class LargeMessageTest - { - Context publisherContext; - Context subscriptionContext; - Node subscriptionNode; - Node publisherNode; - Publisher publisher; - - [SetUp] - public void SetUp() - { - publisherContext = new Context(); - subscriptionContext = new Context(); - Rclcs.Init(publisherContext); - Rclcs.Init(subscriptionContext); - - subscriptionNode = new Node("subscription_test_node", publisherContext); - publisherNode = new Node("publisher_test_node", publisherContext); - - publisher = publisherNode.CreatePublisher("subscription_test_topic"); - } - - [TearDown] - public void TearDown() - { - publisher.Dispose(); - subscriptionNode.Dispose(); - Rclcs.Shutdown(publisherContext); - } -/* - [Test] - public void SubscriptionTriggerCallback() - { - bool callbackTriggered = false; - subscriptionNode.CreateSubscription("subscription_test_topic", (msg) => { callbackTriggered = true; }); - - std_msgs.msg.Float64MultiArray largeMsg = new std_msgs.msg.Float64MultiArray(); - double[] data = new double[1024]; - largeMsg.data = data.OfType().ToList(); - - publisher.Publish(largeMsg); - Rclcs.SpinOnce(subscriptionNode, 0.1); - - Assert.That(callbackTriggered, Is.True); - } - */ - } -} diff --git a/rcldotnet_tests/MessagePubSubTest.cs b/rcldotnet_tests/MessagePubSubTest.cs new file mode 100644 index 00000000..ad295956 --- /dev/null +++ b/rcldotnet_tests/MessagePubSubTest.cs @@ -0,0 +1,64 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace rclcs.Test +{ + [TestFixture] + public class LargeMessageTest + { + Context pub_context; + Context sub_context; + Node pub_node; + Node sub_node; + + [SetUp] + public void SetUp() + { + pub_context = new Context(); + sub_context = new Context(); + + Rclcs.Init(pub_context); + Rclcs.Init(sub_context); + + pub_node = new Node("pub_node", pub_context); + sub_node = new Node("sub_node", sub_context); + } + + [TearDown] + public void TearDown() + { + pub_node.Dispose(); + sub_node.Dispose(); + Rclcs.Shutdown(pub_context); + Rclcs.Shutdown(sub_context); + } + + [Test] + public void ImagePubSub() + { + bool callbackTriggered = false; + + var subscription = sub_node.CreateSubscription( + "test_topic", (received_msg) => + { + callbackTriggered = true; + Assert.That(received_msg.Data.Length, Is.EqualTo(10)); + }); + + var publisher = pub_node.CreatePublisher("test_topic"); + var msg = new sensor_msgs.msg.Image(); + msg.Data = new byte[10]; + msg.Data[0] = 1; + publisher.Publish(msg); + + Rclcs.SpinOnce(sub_node, sub_context, 0.5); + + Assert.That(callbackTriggered, Is.True); + + publisher.Dispose(); + subscription.Dispose(); + } + + } +} diff --git a/rcldotnet_tests/MessagesTest.cs b/rcldotnet_tests/MessagesTest.cs index d120f430..d2b25941 100644 --- a/rcldotnet_tests/MessagesTest.cs +++ b/rcldotnet_tests/MessagesTest.cs @@ -17,69 +17,97 @@ public void CreateMessage() [Test] public void SetBoolData() { - std_msgs.msg.Bool msg = new std_msgs.msg.Bool(); + var msg = new std_msgs.msg.Bool(); + var msgCopy = new std_msgs.msg.Bool(); + + msg.ReadNativeMessage(); Assert.That(msg.Data, Is.False); + msg.Data = true; - Assert.That(msg.Data, Is.True); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Data, Is.True); + msg.Data = false; - Assert.That(msg.Data, Is.False); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Data, Is.False); } [Test] public void SetInt64Data() { - std_msgs.msg.Int64 msg = new std_msgs.msg.Int64(); + var msg = new std_msgs.msg.Int64(); + var msgCopy = new std_msgs.msg.Int64(); + Assert.That(msg.Data, Is.EqualTo(0)); msg.Data = 12345; - Assert.That(msg.Data, Is.EqualTo(12345)); - } - - [Test] - public void SetStringData() - { - std_msgs.msg.String msg = new std_msgs.msg.String(); - Assert.That(msg.Data, Is.EqualTo("")); - msg.Data = "Show me what you got!"; - Assert.That(msg.Data, Is.EqualTo("Show me what you got!")); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Data, Is.EqualTo(12345)); } [Test] public void SetDefaults() { - test_msgs.msg.Defaults msg = new test_msgs.msg.Defaults(); + var msg = new test_msgs.msg.Defaults(); + var msgCopy = new test_msgs.msg.Defaults(); + msg.Int32_value = 24; - Assert.That(msg.Int32_value, Is.EqualTo(24)); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Int32_value, Is.EqualTo(24)); + msg.Float32_value = 3.14F; - Assert.That(msg.Float32_value, Is.EqualTo(3.14F)); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Float32_value, Is.EqualTo(3.14F)); } [Test] public void SetStrings() { - test_msgs.msg.Strings msg = new test_msgs.msg.Strings(); + var msg = new test_msgs.msg.Strings(); + var msgCopy = new test_msgs.msg.Strings(); + + msg.ReadNativeMessage(); + Assert.That(msg.String_value, Is.EqualTo("")); + msg.String_value = "Turtles all the way down"; - Assert.That(msg.String_value, Is.EqualTo("Turtles all the way down")); + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.String_value, Is.EqualTo("Turtles all the way down")); } + + // NOTE(sam): Bool arrays seem to not work yet [Test] - public void SetUnboundedSequenses() + public void SetUnboundedSequences() { test_msgs.msg.UnboundedSequences msg = new test_msgs.msg.UnboundedSequences(); + test_msgs.msg.UnboundedSequences msgCopy = new test_msgs.msg.UnboundedSequences(); + bool[] setBoolSequence = new bool[2]; setBoolSequence[0] = true; setBoolSequence[1] = false; msg.Bool_values = setBoolSequence; - bool[] getBoolSequence = msg.Bool_values; - Assert.That(getBoolSequence.Length, Is.EqualTo(2)); - Assert.That(getBoolSequence[0], Is.True); - Assert.That(getBoolSequence[1], Is.False); + // msg.WriteNativeMessage(); + // msg.ReadNativeMessage(); + // Assert.That(msg.Bool_values_size, Is.EqualTo(2)); + // msgCopy.ReadNativeMessage(msg.Handle); + + // bool[] getBoolSequence = msg.Bool_values; + // Assert.That(msg.Bool_values_size, Is.EqualTo(2)); + // Assert.That(getBoolSequence.Length, Is.EqualTo(2)); + // Assert.That(getBoolSequence[0], Is.True); + // Assert.That(getBoolSequence[1], Is.False); int[] setIntSequence = new int[2]; setIntSequence[0] = 123; setIntSequence[1] = 456; - test_msgs.msg.UnboundedSequences msg2 = new test_msgs.msg.UnboundedSequences(); - msg2.Int32_values = setIntSequence; - int[] getIntList = msg2.Int32_values; + msg.Int32_values = setIntSequence; + int[] getIntList = msg.Int32_values; + Assert.That(getIntList.Length, Is.EqualTo(2)); Assert.That(getIntList[0], Is.EqualTo(123)); Assert.That(getIntList[1], Is.EqualTo(456)); @@ -87,16 +115,25 @@ public void SetUnboundedSequenses() string[] setStringSequence = new string[2]; setStringSequence[0] = "Hello"; setStringSequence[1] = "world"; - test_msgs.msg.UnboundedSequences msg3 = new test_msgs.msg.UnboundedSequences(); - msg3.String_values = setStringSequence; - string[] getStringSequence = msg3.String_values; + msg.String_values = setStringSequence; + string[] getStringSequence = msg.String_values; Assert.That(getStringSequence.Length, Is.EqualTo(2)); Assert.That(getStringSequence[0], Is.EqualTo("Hello")); Assert.That(getStringSequence[1], Is.EqualTo("world")); + + Byte[] setUint8Sequence = new Byte[2]; + setUint8Sequence[0] = 1; + setUint8Sequence[1] = 2; + msg.Uint8_values = setUint8Sequence; + Byte[] getUint8Sequence = msg.Uint8_values; + Assert.That(getUint8Sequence.Length, Is.EqualTo(2)); + Assert.That(getUint8Sequence[0], Is.EqualTo(1)); + Assert.That(getUint8Sequence[1], Is.EqualTo(2)); } + [Test] - public void SetBoundedSequenses() + public void SetBoundedSequences() { test_msgs.msg.BoundedSequences msg = new test_msgs.msg.BoundedSequences(); bool[] setBoolSequence = new bool[2]; @@ -133,15 +170,16 @@ public void SetBoundedSequenses() [Test] public void SetNested() { - test_msgs.msg.Nested msg = new test_msgs.msg.Nested(); - test_msgs.msg.BasicTypes basic_types_msg = msg.Basic_types_value; - Assert.That(basic_types_msg.Int32_value, Is.EqualTo(0)); - basic_types_msg.Int32_value = 25; - Assert.That(basic_types_msg.Int32_value, Is.EqualTo(25)); - test_msgs.msg.BasicTypes basic_types_msg2 = msg.Basic_types_value; - Assert.That(basic_types_msg2.Int32_value, Is.EqualTo(25)); + var msg = new test_msgs.msg.Nested(); + var msgCopy = new test_msgs.msg.Nested(); + Assert.That(msg.Basic_types_value.Int32_value, Is.EqualTo(0)); + msg.Basic_types_value.Int32_value = 25; + msg.WriteNativeMessage(); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Basic_types_value.Int32_value, Is.EqualTo(25)); } + // FIXME(sam): use ReadNativeMessage and WriteNativeMessage [Test] public void SetMultiNested() { @@ -164,8 +202,29 @@ public void SetMultiNested() Assert.That(getUnboundedOfUnbounded[0].String_values[1], Is.EqualTo("world")); } - /* + [Test] + public void SetImage() + { + var msg = new sensor_msgs.msg.Image(); + var msgCopy = new sensor_msgs.msg.Image(); + + Assert.That(msg.Data.Length, Is.EqualTo(0)); + msg.Data = new byte[10]; + msg.WriteNativeMessage(); + Assert.That(msg.Data.Length, Is.EqualTo(10)); + msg.Data = new byte[2]; + msg.ReadNativeMessage(); + Assert.That(msg.Data.Length, Is.EqualTo(10)); + msg.Data = new byte[8]; + // NOTE(sam): Writing twice seems not work + // msg.WriteNativeMessage(); + msg.ReadNativeMessage(); + Assert.That(msg.Data.Length, Is.EqualTo(10)); + msgCopy.ReadNativeMessage(msg.Handle); + Assert.That(msgCopy.Data.Length, Is.EqualTo(10)); + } + /* // NOTE(samiam): does not work yet [Test] public void SetStaticArrayPrimitives() diff --git a/rcldotnet_tests/package.xml b/rcldotnet_tests/package.xml index 623ccb71..7591e174 100644 --- a/rcldotnet_tests/package.xml +++ b/rcldotnet_tests/package.xml @@ -19,6 +19,8 @@ std_msgs sensor_msgs test_msgs + tf2_msgs + geometry_msgs rcldotnet_common example_interfaces @@ -26,6 +28,8 @@ std_msgs sensor_msgs test_msgs + tf2_msgs + geometry_msgs ament_cmake diff --git a/rcldotnet_tests/rcldotnet_tests.csproj b/rcldotnet_tests/rcldotnet_tests.csproj index 3f2637f4..b455ee39 100644 --- a/rcldotnet_tests/rcldotnet_tests.csproj +++ b/rcldotnet_tests/rcldotnet_tests.csproj @@ -23,5 +23,14 @@ ../../../../install/rcldotnet_tests/lib/rcldotnet_tests/dotnet/test_msgs_assembly.dll + + ../../../../install/rcldotnet_tests/lib/rcldotnet_tests/dotnet/tf2_msgs_assembly.dll + + + ../../../../install/rcldotnet_tests/lib/rcldotnet_tests/dotnet/sensor_msgs_assembly.dll + + + ../../../../install/rcldotnet_tests/lib/rcldotnet_tests/dotnet/geometry_msgs_assembly.dll + diff --git a/rcldotnet_utils/rcldotnet_utils/init_unity_project.py b/rcldotnet_utils/rcldotnet_utils/init_unity_project.py index 533e4ccf..ef78e60d 100644 --- a/rcldotnet_utils/rcldotnet_utils/init_unity_project.py +++ b/rcldotnet_utils/rcldotnet_utils/init_unity_project.py @@ -7,7 +7,7 @@ import pkg_resources import stat -from ament_index_python import get_package_prefix +from ament_index_python import get_package_prefix, get_package_share_directory from ament_index_python.packages import PackageNotFoundError @@ -46,7 +46,10 @@ def __init__(self, unity_project_path): ] self.c_lib_source_dict = {} - self.c_lib_destination_dir = unity_project_path + '/Assets/Plugins/x86_64' + if platform.system() == 'Windows': + self.c_lib_destination_dir = unity_project_path + '/Assets/Plugins/Windows/x86_64' + else: + self.c_lib_destination_dir = unity_project_path + '/Assets/Plugins/Linux/x86_64' self.cs_lib_source_dict = {} self.cs_lib_destination_dir = unity_project_path + '/Assets/Plugins' @@ -163,8 +166,9 @@ def directory_is_a_unity_project(dir_path): def copy_unity_files(unity_project_path): - unity_files_path = pkg_resources.resource_filename('rcldotnet_utils', - 'unity_files') + # unity_files_path = pkg_resources.resource_filename('rcldotnet_utils', + # 'unity_files') + unity_files_path = get_package_share_directory('rcldotnet_utils') + '/unity_files' asset_path = unity_project_path + '/Assets' diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/BuildRos.cs b/rcldotnet_utils/resource/unity_files/BuildRos.cs similarity index 83% rename from rcldotnet_utils/rcldotnet_utils/unity_files/BuildRos.cs rename to rcldotnet_utils/resource/unity_files/BuildRos.cs index 1961ba02..ea8a40fd 100644 --- a/rcldotnet_utils/rcldotnet_utils/unity_files/BuildRos.cs +++ b/rcldotnet_utils/resource/unity_files/BuildRos.cs @@ -12,7 +12,7 @@ public static void BuildGameWindows() string[] levels = new string[] { "Assets/Scenes/RosExample.unity"}; // Build player. - BuildPipeline.BuildPlayer(levels, path + "/BuiltGame.exe", BuildTarget.StandaloneWindows64, BuildOptions.None); + BuildPipeline.BuildPlayer(levels, path + "/RosApplication.exe", BuildTarget.StandaloneWindows64, BuildOptions.None); // Copy a file from the project folder to the build folder, alongside the built game. FileUtil.CopyFileOrDirectory("Assets/Resources/start_player.py", path + "/start_player.py"); @@ -25,12 +25,12 @@ public static void BuildGameLinux() { // Get filename. // FIXME(sam): creates folder for some reason... Allow setting name of game? - string path = EditorUtility.SaveFolderPanel("Choose Location of Built Game", "", ""); + string path = EditorUtility.SaveFolderPanel("Choose Location of Built ROS Application", "", ""); // string path = System.IO.Path.GetDirectoryName(file_path); string[] levels = new string[] { "Assets/Scenes/RosExample.unity"}; // Build player. - BuildPipeline.BuildPlayer(levels, path + "/BuiltGame", BuildTarget.StandaloneLinux64, BuildOptions.None); + BuildPipeline.BuildPlayer(levels, path + "/RosApplication", BuildTarget.StandaloneLinux64, BuildOptions.None); // Copy a file from the project folder to the build folder, alongside the built game. FileUtil.CopyFileOrDirectory("Assets/Resources/start_player.py", path + "/start_player.py"); diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.bash b/rcldotnet_utils/resource/unity_files/start_editor.bash similarity index 100% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.bash rename to rcldotnet_utils/resource/unity_files/start_editor.bash diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.bat b/rcldotnet_utils/resource/unity_files/start_editor.bat similarity index 100% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.bat rename to rcldotnet_utils/resource/unity_files/start_editor.bat diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.py b/rcldotnet_utils/resource/unity_files/start_editor.py similarity index 96% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.py rename to rcldotnet_utils/resource/unity_files/start_editor.py index 53947e8e..4e6c81d4 100644 --- a/rcldotnet_utils/rcldotnet_utils/unity_files/start_editor.py +++ b/rcldotnet_utils/resource/unity_files/start_editor.py @@ -19,12 +19,12 @@ if platform.system() == 'Windows': yaml_data = { 'unity_editor_filename': None, - 'c_libs_asset_path': 'Plugins\\x86_64' + 'c_libs_asset_path': 'Plugins\\Windows\\x86_64' } else: yaml_data = { 'unity_editor_filename': None, - 'c_libs_asset_path': 'Plugins/x86_64' + 'c_libs_asset_path': 'Plugins/Linux/x86_64' } if os.path.isfile(config_filename): diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_player.bash b/rcldotnet_utils/resource/unity_files/start_player.bash similarity index 100% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_player.bash rename to rcldotnet_utils/resource/unity_files/start_player.bash diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_player.bat b/rcldotnet_utils/resource/unity_files/start_player.bat similarity index 100% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_player.bat rename to rcldotnet_utils/resource/unity_files/start_player.bat diff --git a/rcldotnet_utils/rcldotnet_utils/unity_files/start_player.py b/rcldotnet_utils/resource/unity_files/start_player.py similarity index 73% rename from rcldotnet_utils/rcldotnet_utils/unity_files/start_player.py rename to rcldotnet_utils/resource/unity_files/start_player.py index 16e36b64..83eff6ce 100644 --- a/rcldotnet_utils/rcldotnet_utils/unity_files/start_player.py +++ b/rcldotnet_utils/resource/unity_files/start_player.py @@ -6,11 +6,11 @@ build_directory = os.path.dirname(os.path.realpath(sys.argv[0])) if platform.system() == 'Windows': - library_path = build_directory + '\\BuiltGame_Data\\Plugins' + library_path = build_directory + '\\RosApplication_Data\\Plugins' if not (library_path in os.environ['PATH']): os.environ['PATH'] = os.environ['PATH'] + ';' + library_path else: - library_path = build_directory + '/BuiltGame_Data/Plugins' + library_path = build_directory + '/RosApplication_Data/Plugins' if 'LD_LIBRARY_PATH' in os.environ: os.environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + ':' + library_path else: @@ -18,9 +18,9 @@ if platform.system() == 'Windows': - subprocess.call(['BuiltGame.exe']) + subprocess.call(['RosApplication.exe']) else: player_directory = os.path.dirname(os.path.realpath(sys.argv[0])) - player_path = player_directory + '/BuiltGame' + player_path = player_directory + '/RosApplication' print("Binary path: " + player_path) subprocess.call([player_path]) diff --git a/rcldotnet_utils/setup.py b/rcldotnet_utils/setup.py index 3ca64395..6c5a3270 100644 --- a/rcldotnet_utils/setup.py +++ b/rcldotnet_utils/setup.py @@ -1,5 +1,6 @@ from setuptools import find_packages from setuptools import setup +from glob import glob package_name = 'rcldotnet_utils' setup( name=package_name, @@ -9,6 +10,7 @@ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), + ('share/' + package_name + '/unity_files', glob('resource/unity_files/**')), ], install_requires=['setuptools'], zip_safe=True, diff --git a/ros2_dotnet_dashing.repos b/ros2_dotnet_dashing.repos index 9b0bc8eb..f1cc146f 100644 --- a/ros2_dotnet_dashing.repos +++ b/ros2_dotnet_dashing.repos @@ -14,7 +14,7 @@ version: master ros2_dotnet/ros2_dotnet: type: git - url: https://github.com/adamdbrw/ros2_dotnet.git + url: https://github.com/samiamlabs/ros2_dotnet version: master # messages ros2/common_interfaces: diff --git a/rosidl_generator_cs/resource/msg.c.em b/rosidl_generator_cs/resource/msg.c.em index ff9975e4..4a74593f 100644 --- a/rosidl_generator_cs/resource/msg.c.em +++ b/rosidl_generator_cs/resource/msg.c.em @@ -113,14 +113,12 @@ bool @(msg_typename)_native_write_field_@(member.name)(@(get_c_type(member.type. @[for member in message.structure.members]@ @[ if isinstance(member.type, (AbstractSequence, Array)) and isinstance(member.type.value_type, BasicType)]@ ROSIDL_GENERATOR_C_EXPORT -@(get_c_type(member.type.value_type)) *@(msg_typename)_native_read_field_@(member.name)(void *message_handle, int *size) +@(get_c_type(member.type.value_type)) *@(msg_typename)_native_read_field_@(member.name)(void *message_handle) { @(msg_typename) *ros_message = (@(msg_typename) *)message_handle; @[ if isinstance(member.type, Array)]@ - *size = @(member.type.size); return ros_message->@(member.name); @[ elif isinstance(member.type, AbstractSequence)]@ - *size = ros_message->@(member.name).size; return ros_message->@(member.name).data; @[ end if]@ } @@ -195,17 +193,6 @@ void * @(msg_typename)_native_get_nested_message_handle_@(member.name)(void *mes } @[ end if]@ -ROSIDL_GENERATOR_C_EXPORT -int @(msg_typename)_native_get_array_size_@(member.name)(void *message_handle) -{ -@[ if isinstance(member.type, Array)]@ - return @(member.type.size); //TODO - message handle not used -@[ elif isinstance(member.type, AbstractSequence)]@ - @(msg_typename) *ros_message = (@(msg_typename) *)message_handle; - return ros_message->@(member.name).size; -@[ end if]@ -} - ROSIDL_GENERATOR_C_EXPORT bool @(msg_typename)_native_init_sequence_@(member.name)(void *message_handle, int size) { @@ -224,5 +211,18 @@ bool @(msg_typename)_native_init_sequence_@(member.name)(void *message_handle, i return true; @[ end if]@ } +@[ end if]@ +@[ if isinstance(member.type, (AbstractSequence, Array))]@ +ROSIDL_GENERATOR_C_EXPORT +int @(msg_typename)_native_get_array_size_@(member.name)(void *message_handle) +{ +@[ if isinstance(member.type, Array)]@ + return @(member.type.size); //TODO - message handle not used +@[ elif isinstance(member.type, AbstractSequence)]@ + @(msg_typename) *ros_message = (@(msg_typename) *)message_handle; + return ros_message->@(member.name).size; +@[ end if]@ +} + @[ end if]@ @[end for]@ diff --git a/rosidl_generator_cs/resource/msg.cs.em b/rosidl_generator_cs/resource/msg.cs.em index bd8c0950..78b2ab42 100644 --- a/rosidl_generator_cs/resource/msg.cs.em +++ b/rosidl_generator_cs/resource/msg.cs.em @@ -126,7 +126,6 @@ public class @(message_class) : @(parent_interface) @[ if isinstance(member.type.value_type, BasicType)]@ [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate IntPtr NativeReadField@(get_field_name(member.type, member.name, message_class))Type( - out int array_size, IntPtr messageHandle); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -166,14 +165,16 @@ public class @(message_class) : @(parent_interface) IntPtr messageHandle, int index); private static NativeGetNestedHandle@(get_field_name(member.type, member.name, message_class))Type native_get_nested_message_handle_@(member.name) = null; @[ end if]@ - private delegate int NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type( - IntPtr messageHandle); - private static NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type native_get_array_size_@(member.name) = null; - private delegate bool NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type( IntPtr messageHandle, int size); private static NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type native_init_sequence_@(member.name) = null; +@[ end if]@ +@[ if isinstance(member.type, (AbstractSequence, Array))]@ + private delegate int NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type( + IntPtr messageHandle); + private static NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type native_get_array_size_@(member.name) = null; + @[ end if]@ @[end for]@ @@ -223,17 +224,20 @@ public class @(message_class) : @(parent_interface) (NativeGetNestedHandle@(get_field_name(member.type, member.name, message_class))Type)Marshal.GetDelegateForFunctionPointer( native_get_nested_message_handle_@(member.name)_ptr, typeof(NativeGetNestedHandle@(get_field_name(member.type, member.name, message_class))Type)); @[ end if]@ + IntPtr native_init_sequence_@(member.name)_ptr = + dllLoadUtils.GetProcAddress(nativelibrary, "@(c_full_name)_native_init_sequence_@(member.name)"); + @(message_class).native_init_sequence_@(member.name) = + (NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type)Marshal.GetDelegateForFunctionPointer( + native_init_sequence_@(member.name)_ptr, typeof(NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type)); +@[ end if]@ + +@[ if isinstance(member.type, (AbstractSequence, Array))]@ IntPtr native_get_array_size_@(member.name)_ptr = dllLoadUtils.GetProcAddress(nativelibrary, "@(c_full_name)_native_get_array_size_@(member.name)"); @(message_class).native_get_array_size_@(member.name) = (NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type)Marshal.GetDelegateForFunctionPointer( native_get_array_size_@(member.name)_ptr, typeof(NativeGetArraySize@(get_field_name(member.type, member.name, message_class))Type)); - IntPtr native_init_sequence_@(member.name)_ptr = - dllLoadUtils.GetProcAddress(nativelibrary, "@(c_full_name)_native_init_sequence_@(member.name)"); - @(message_class).native_init_sequence_@(member.name) = - (NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type)Marshal.GetDelegateForFunctionPointer( - native_init_sequence_@(member.name)_ptr, typeof(NativeInitSequence@(get_field_name(member.type, member.name, message_class))Type)); @[ end if]@ @[end for]@ } @@ -290,7 +294,13 @@ public class @(message_class) : @(parent_interface) @[ elif isinstance(member.type, (AbstractSequence, Array)) and isinstance(member.type.value_type, BasicType)]@ { //TODO - (adam) this is a bit clunky. Is there a better way to marshal unsigned and bool types? int arraySize = 0; - IntPtr pArr = native_read_field_@(member.name)(out arraySize, handle); + IntPtr pArr = native_read_field_@(member.name)(handle); + + arraySize = native_get_array_size_@(member.name)(handle); + + if (pArr == IntPtr.Zero) + throw new System.InvalidOperationException("Array pointer is null for member @(member.name), size: " + arraySize.ToString()); + @(get_field_name(member.type, member.name, message_class)) = new @(get_dotnet_type(member.type.value_type))[arraySize]; @(get_marshal_array_type(member.type))[] __@(get_field_name(member.type, member.name, message_class)) = new @(get_marshal_array_type(member.type))[arraySize]; int start = 0; diff --git a/rosidl_generator_cs/rosidl_generator_cs/generate_cs_impl.py b/rosidl_generator_cs/rosidl_generator_cs/generate_cs_impl.py index 055d551e..a58a7420 100644 --- a/rosidl_generator_cs/rosidl_generator_cs/generate_cs_impl.py +++ b/rosidl_generator_cs/rosidl_generator_cs/generate_cs_impl.py @@ -46,17 +46,17 @@ def generate_cs(generator_arguments_file, typesupport_impls): #print("Type_support mapping " + str(type_support_impl_by_filename), file=sys.stderr) additional_context = { - 'get_field_name' : get_field_name, - 'get_dotnet_type' : get_dotnet_type, - 'constant_value_to_dotnet' : constant_value_to_dotnet, - 'get_c_type' : get_c_type, - 'get_marshal_type' : get_marshal_type, - 'get_marshal_array_type' : get_marshal_array_type + 'get_field_name': get_field_name, + 'get_dotnet_type': get_dotnet_type, + 'constant_value_to_dotnet': constant_value_to_dotnet, + 'get_c_type': get_c_type, + 'get_marshal_type': get_marshal_type, + 'get_marshal_array_type': get_marshal_array_type } generate_files(generator_arguments_file, mapping, additional_context) for type_support in type_support_impl_by_filename.keys(): - typemapping = { 'idl_typesupport.c.em': type_support } + typemapping = {'idl_typesupport.c.em': type_support} generate_files(generator_arguments_file, typemapping) @@ -107,6 +107,9 @@ def get_builtin_dotnet_type(type_, use_primitives=True): if type_ == 'uint8': return 'byte' if use_primitives else 'System.Byte' + if type_ == 'byte': + return 'byte' if use_primitives else 'System.Byte' + if type_ == 'int16': return 'short' if use_primitives else 'System.Int16' @@ -146,6 +149,7 @@ def get_c_type(type_): 'boolean': 'I1', 'octet': 'U1', 'uint8': 'U1', + 'byte': 'U1', 'int8': 'I1', 'uint16': 'U2', 'int16': 'I2', @@ -165,6 +169,7 @@ def get_c_type(type_): 'boolean': 'byte', 'octet': 'byte', 'uint8': 'byte', + 'byte': 'byte', 'int8': 'char', 'uint16': 'short', 'int16': 'short',