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 .idl file support to mix generator #35

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
22 changes: 11 additions & 11 deletions ros2/test/integration/ros2__test_qos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class ROS2QoS : public ::testing::Test
ASSERT_EQ(msg_future.wait_for(0s), std::future_status::ready);
xtypes::DynamicData received_msg = msg_future.get();

EXPECT_EQ(received_msg.type().name(), "std_msgs/String");
EXPECT_EQ(received_msg.type().name(), "std_msgs/msg/String");

xtypes::ReadableDynamicDataRef xtypes_msg = received_msg;
typename std_msgs::msg::String::_data_type ros2_field;
Expand Down Expand Up @@ -165,7 +165,7 @@ TEST_F(ROS2QoS, Durability_Incompatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { durability: TRANSIENT_LOCAL } } }\n";

set_up(yaml);
Expand All @@ -188,7 +188,7 @@ TEST_F(ROS2QoS, Durability_Compatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { durability: VOLATILE } } }\n";

set_up(yaml);
Expand All @@ -211,7 +211,7 @@ TEST_F(ROS2QoS, Deadline_Incompatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { deadline: { sec: 1 } } } }\n";

set_up(yaml);
Expand All @@ -234,7 +234,7 @@ TEST_F(ROS2QoS, Deadline_Compatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { deadline: { sec: 2 } } } }\n";

set_up(yaml);
Expand All @@ -257,7 +257,7 @@ TEST_F(ROS2QoS, Liveliness_Incompatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { liveliness: { kind: MANUAL_BY_TOPIC } } } }\n";

set_up(yaml);
Expand All @@ -280,7 +280,7 @@ TEST_F(ROS2QoS, Liveliness_Compatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { liveliness: { kind: AUTOMATIC } } } }\n";

set_up(yaml);
Expand All @@ -303,7 +303,7 @@ TEST_F(ROS2QoS, Lease_Duration_Incompatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { liveliness: { sec: 1 } } } }\n";

set_up(yaml);
Expand All @@ -325,7 +325,7 @@ TEST_F(ROS2QoS, Lease_Duration_Compatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { liveliness: { sec: 3 } } } }\n";

set_up(yaml);
Expand All @@ -348,7 +348,7 @@ TEST_F(ROS2QoS, Reliability_Incompatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { reliability: RELIABLE } } }\n";

set_up(yaml);
Expand All @@ -371,7 +371,7 @@ TEST_F(ROS2QoS, Reliability_Compatible_QoS)
yaml += " mock_to_ros2: { from: mock, to: ros2 }\n";
yaml += " ros2_to_mock: { from: ros2, to: mock }\n";
yaml += "topics:\n";
yaml += " transmit: { type: 'std_msgs/String', route: ros2_to_mock, ";
yaml += " transmit: { type: 'std_msgs/msg/String', route: ros2_to_mock, ";
yaml += " ros2: { qos: { reliability: BEST_EFFORT } } }\n";

set_up(yaml);
Expand Down
2 changes: 1 addition & 1 deletion ros2/test/resources/ros2__domain_change.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ routes:
domain_5_to_10: { from: ros2_domain5, to: ros2_domain10 }

topics:
string_topic: { type: "std_msgs/String", route: domain_5_to_10 }
string_topic: { type: "std_msgs/msg/String", route: domain_5_to_10 }
4 changes: 2 additions & 2 deletions ros2/test/resources/ros2__geometry_msgs__pubsub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ routes:
ros2_to_mock: { from: ros2, to: mock }

topics:
transmit_pose: { type: "geometry_msgs/Pose", route: ros2_to_mock }
echo_pose: { type: "geometry_msgs/Pose", route: mock_to_ros2 }
transmit_pose: { type: "geometry_msgs/msg/Pose", route: ros2_to_mock }
echo_pose: { type: "geometry_msgs/msg/Pose", route: mock_to_ros2 }
4 changes: 2 additions & 2 deletions ros2/test/resources/ros2__geometry_msgs__services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ routes:
ros2_srv: { server: ros2, clients: mock }

services:
get_plan: { type: "nav_msgs/GetPlan:request", route: ros2_srv }
echo_plan: { type: "nav_msgs/GetPlan:response", route: mock_srv }
get_plan: { type: "nav_msgs/srv/GetPlan:request", route: ros2_srv }
echo_plan: { type: "nav_msgs/srv/GetPlan:response", route: mock_srv }
2 changes: 1 addition & 1 deletion ros2/test/resources/ros2__websocket__test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ routes:
ros2_to_websocket: { from: ros2, to: websocket }

topics:
helloworld: { type: "std_msgs/String", route: websocket_to_ros2, remap: {websocket: {type: std_msgs__String}} }
helloworld: { type: "std_msgs/msg/String", route: websocket_to_ros2, remap: {websocket: {type: std_msgs__String}} }
6 changes: 5 additions & 1 deletion utils/ros2-mix-generator/cmake/is_ros2_rosidl_mix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@ function(is_ros2_rosidl_mix)
endif()
endforeach()

if(NOT Python_EXECUTABLE)
find_package(Python COMPONENTS Interpreter)
endif()

is_mix_generator(
IDL_TYPE
rosidl
SCRIPT
INTERPRETER
${PYTHON_EXECUTABLE}
${Python_EXECUTABLE}
FIND
${CMAKE_CURRENT_LIST_DIR}/scripts/is_ros2_rosidl_find_package_info.py
GENERATE
Expand Down
4 changes: 2 additions & 2 deletions utils/ros2-mix-generator/resources/convert__msg.cpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
@# EmPy template for generating is/rosidl/ros2/<package>/src/msg/convert__msg__<msg>.cpp files
@#
@# Context:
@# - spec (rosidl_parser.MessageSpecification)
@# Parsed specification of the .msg file
@# - spec (rosidl_adapter.parser.MessageSpecification)
@# Parsed specification of the .msg/.idl file
@# - subfolder (string)
@# The subfolder / subnamespace of the message
@# Either 'msg' or 'srv'
Expand Down
18 changes: 5 additions & 13 deletions utils/ros2-mix-generator/resources/convert__msg.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
@# EmPy template for generating is/rosidl/ros2/<package>/include/is/rosidl/ros2/<package>/msg/convert__msg__<msg>.hpp files
@#
@# Context:
@# - spec (rosidl_parser.MessageSpecification)
@# Parsed specification of the .msg file
@# - spec (rosidl_adapter.parser.MessageSpecification)
@# Parsed specification of the .msg/.idl file
@# - subfolder (string)
@# The subfolder / subnamespace of the message
@# Either 'msg' or 'srv'
Expand All @@ -20,7 +20,7 @@ underscore_msg_type = get_header_filename_from_msg_name(camelcase_msg_type)
cpp_msg_type = '{}::msg::{}'.format(
spec.base_type.pkg_name, camelcase_msg_type)

msg_type_string = '{}/{}'.format(
msg_type_string = '{}/msg/{}'.format(
spec.base_type.pkg_name, camelcase_msg_type)

header_guard_parts = [
Expand Down Expand Up @@ -104,27 +104,19 @@ inline const eprosima::xtypes::StructType& type()
}

//==============================================================================
inline void convert_to_ros2(const eprosima::xtypes::ReadableDynamicDataRef& from, Ros2_Msg& to)
inline void convert_to_ros2([[maybe_unused]] const eprosima::xtypes::ReadableDynamicDataRef& from, [[maybe_unused]] Ros2_Msg& to)
{
@[for field in alphabetical_fields]@
utils::Convert<Ros2_Msg::_@(field.name)_type>::from_xtype_field(from["@(field.name)"], to.@(field.name));
@[end for]@

// Suppress possible unused variable warnings
(void)from;
(void)to;
}

//==============================================================================
inline void convert_to_xtype(const Ros2_Msg& from, eprosima::xtypes::WritableDynamicDataRef to)
inline void convert_to_xtype([[maybe_unused]] const Ros2_Msg& from, [[maybe_unused]]eprosima::xtypes::WritableDynamicDataRef to)
{
@[for field in alphabetical_fields]@
utils::Convert<Ros2_Msg::_@(field.name)_type>::to_xtype_field(from.@(field.name), to["@(field.name)"]);
@[end for]@

// Suppress possible unused variable warnings
(void)from;
(void)to;
}

static eprosima::is::utils::Logger logger ("is::sh::ROS2");
Expand Down
6 changes: 3 additions & 3 deletions utils/ros2-mix-generator/resources/convert__srv.cpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
@# EmPy template for generating is/rosidl/ros2/<package>/src/srv/convert__srv__<srv>.cpp files
@#
@# Context:
@# - spec (rosidl_parser.ServiceSpecification)
@# Parsed specification of the .srv file
@# - spec (rosidl_adapter.parser.ServiceSpecification)
@# Parsed specification of the .srv/.idl file
@# - get_header_filename_from_msg_name (function)
@#######################################################################

Expand All @@ -16,7 +16,7 @@ underscore_srv_type = get_header_filename_from_msg_name(camelcase_srv_type)

cpp_srv_type = '{}::srv::{}'.format(spec.pkg_name, camelcase_srv_type)

srv_type_string = '{}/{}'.format(spec.pkg_name, camelcase_srv_type)
srv_type_string = '{}/srv/{}'.format(spec.pkg_name, camelcase_srv_type)

namespace_parts_srv = [
'convert', spec.pkg_name, 'srv', underscore_srv_type]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import argparse
import os
import sys
from pathlib import Path

try:
from rosidl_adapter.parser import parse_message_file
from rosidl_adapter.parser import parse_service_file
from rosidl_parser.parser import parse_idl_file
from rosidl_parser.definition import IdlLocator, NamespacedType, Message, Service

except ImportError:
print('Unable to import rosidl_adapter. Please source a ROS2 installation first.', end='', file=sys.stderr)
Expand All @@ -30,31 +33,35 @@ def find_package_info(requested_pkg_name):

share_dir = get_package_share_directory(requested_pkg_name)

message_dir = '{}/msg'.format(share_dir)
if os.path.exists(message_dir):
for relative_msg_file in os.listdir(message_dir):
if not relative_msg_file.endswith('.msg'):
continue

msg_file = '{}/{}'.format(message_dir, relative_msg_file)

message_dir = Path(share_dir) / 'msg'
if message_dir.exists():
for msg_file in message_dir.glob("*.msg"):
info.msg_files.append(msg_file)

msg = parse_message_file(requested_pkg_name, msg_file)
for field in msg.fields:
if field.type.is_primitive_type():
continue
if not field.type.is_primitive_type():
info.dependencies.append(field.type.pkg_name)

info.dependencies.append(field.type.pkg_name)
ignore_msgs = {p.stem for p in info.msg_files}

service_dir = '{}/srv'.format(share_dir)
if os.path.exists(service_dir):
for relative_srv_file in os.listdir(service_dir):
if not relative_srv_file.endswith('.srv'):
for msg_file in message_dir.glob("*.idl"):
if msg_file.stem in ignore_msgs:
continue

srv_file = '{}/{}'.format(service_dir, relative_srv_file)
info.msg_files.append(msg_file)

idl_file = parse_idl_file(IdlLocator(share_dir, msg_file.relative_to(share_dir)))
idl_msg = idl_file.content.get_elements_of_type(Message)[0]
for member in idl_msg.structure.members:
if isinstance(member.type, NamespacedType):
info.dependencies.append(member.type.namespaces[0])

service_dir = Path(share_dir) / 'srv'
if service_dir.exists():
for srv_file in service_dir.glob("*.srv"):
info.srv_files.append(srv_file)

srv = parse_service_file(requested_pkg_name, srv_file)
for component in [srv.request, srv.response]:
for field in component.fields:
Expand All @@ -63,6 +70,21 @@ def find_package_info(requested_pkg_name):

info.dependencies.append(field.type.pkg_name)

ignore_srvs = {p.stem for p in info.srv_files}

for srv_file in service_dir.glob("*.idl"):
if srv_file.stem in ignore_srvs:
continue

info.srv_files.append(srv_file)

idl_file = parse_idl_file(IdlLocator(share_dir, srv_file.relative_to(share_dir)))
idl_srv = idl_file.content.get_elements_of_type(Service)[0]
for members in [idl_srv.request_message.structure.members, idl_srv.response_message.structure.members]:
for member in members:
if isinstance(member.type, NamespacedType):
info.dependencies.append(member.type.namespaces[0])

return info


Expand All @@ -89,18 +111,18 @@ def print_package_info(root_pkg_name, pkg_info_dict):
dependency_list_str = '#'.join(dependency_list)

message_files = pkg_info_dict[root_pkg_name].msg_files
message_files_str = '#'.join(message_files)
message_files_str = '#'.join(str(f) for f in message_files)

service_files = pkg_info_dict[root_pkg_name].srv_files
service_files_str = '#'.join(service_files)
service_files_str = '#'.join(str(f) for f in service_files)

file_dependencies = []
for pkg, info in pkg_info_dict.items():
file_dependencies.extend(info.msg_files)
if pkg == root_pkg_name:
file_dependencies.extend(info.srv_files)

file_dependencies_str = '#'.join(file_dependencies)
file_dependencies_str = '#'.join(str(f) for f in file_dependencies)

output_str = ';'.join([dependency_list_str, message_files_str, service_files_str, file_dependencies_str])
print(output_str)
Expand Down
Loading