diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b091f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +devel/ +logs/ +build/ +lib/ +msg_gen/ +srv_gen/ +msg/*Action.msg +msg/*ActionFeedback.msg +msg/*ActionGoal.msg +msg/*ActionResult.msg +msg/*Feedback.msg +msg/*Goal.msg +msg/*Result.msg +msg/_*.py +build_isolated/ +devel_isolated/ + +# Generated by dynamic reconfigure +*.cfgc +/cfg/cpp/ +/cfg/*.py + +# Ignore generated docs +*.dox +*.wikidoc + +# eclipse stuff +.project +.cproject + +# qcreator stuff +CMakeLists.txt.user + +srv/_*.py +*.pcd +*.pyc +qtcreator-* +*.user + +/planning/cfg +/planning/docs +/planning/src + +*~ + +# vs-code stuff +.vscode + +# Emacs +.#* + +# Catkin custom files +CATKIN_IGNORE \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f9f6c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) 2019 - 2020 Continental Corporation + + 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5402bd9 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Protobuf based rosidl typesupport + +Middleware agnostic ros2 static typesupport which uses Protobuf for serialization/deserialization. + +## Build instructions + +* Clone latest release of this repository into your [ROS2 workspace](https://index.ros.org/doc/ros2/Tutorials/Workspace/Creating-A-Workspace/) +* Source ROS2 `source /path/to/your/ros/distro/folder/setup.bash` +* Run `colcon build` from your workspace folder +* Setup your workspace `source /path/to/your/workspace/install/setup.bash` + +**Note**: Typesupport must be built and sourced before any project messages are built. +**Note 2**: If you are using messages that are not being built by project (ex. builtin_interfaces) they need to be rebuilt and sourced in your workspace. \ No newline at end of file diff --git a/rosidl_adapter_proto/CMakeLists.txt b/rosidl_adapter_proto/CMakeLists.txt new file mode 100644 index 0000000..8c50488 --- /dev/null +++ b/rosidl_adapter_proto/CMakeLists.txt @@ -0,0 +1,37 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +cmake_minimum_required(VERSION 3.12) + +project(rosidl_adapter_proto) + +find_package(ament_cmake REQUIRED) +find_package(ament_cmake_python REQUIRED) + +ament_python_install_package(${PROJECT_NAME}) + +ament_package(CONFIG_EXTRAS "cmake/rosidl_adapter_proto-extras.cmake.in") + +install( + PROGRAMS bin/rosidl_adapter_proto + DESTINATION lib/rosidl_adapter_proto +) + +install( + DIRECTORY cmake resource + DESTINATION share/${PROJECT_NAME} +) \ No newline at end of file diff --git a/rosidl_adapter_proto/bin/rosidl_adapter_proto b/rosidl_adapter_proto/bin/rosidl_adapter_proto new file mode 100644 index 0000000..bf49b23 --- /dev/null +++ b/rosidl_adapter_proto/bin/rosidl_adapter_proto @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import argparse +import sys +import pathlib +import os + +from rosidl_cmake import read_generator_arguments +from rosidl_adapter_proto import generate_proto +from rosidl_adapter_proto import compile_proto + +def main(argv=sys.argv[1:]): + parser = argparse.ArgumentParser( + description='Generate the Protobuf interfaces for Protobuf type support.', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '--generator-arguments-file', + required=True, + help='The location of the file containing the generator arguments') + parser.add_argument( + '--protoc-path', + required=True, + help='Path to the protoc executable') + + args = parser.parse_args(argv) + + generator_args = read_generator_arguments(args.generator_arguments_file) + + # Generate .proto files + rc = generate_proto(args.generator_arguments_file) + if rc: + return rc + + # Compile .proto files using protoc + cpp_out_dir = str(pathlib.Path(generator_args["output_dir"] + "/..").resolve()) + proto_path_list = [str(pathlib.Path(generator_args["output_dir"] + "/..").resolve())] + proto_files = [] + package_name = generator_args["package_name"] + + if "additional_files" in generator_args: + proto_path_list += generator_args["additional_files"] + + pathlib.Path(cpp_out_dir).mkdir(parents=True, exist_ok=True) + + for idl_tuple in generator_args.get('idl_tuples', []): + idl_parts = idl_tuple.rsplit(':', 1) + assert len(idl_parts) == 2 + idl_rel_path = pathlib.Path(idl_parts[1]) + idl_stem = idl_rel_path.stem + generated_file = os.path.join( + generator_args['output_dir'], + str(idl_rel_path.parent), + idl_stem + ".proto" + ) + proto_files.append(str(pathlib.Path(generated_file).resolve())) + + # compile proto files with protoc + rc = compile_proto(protoc_path = args.protoc_path, + proto_path_list = proto_path_list, + cpp_out_dir = cpp_out_dir, + proto_files = proto_files, + package_name = package_name + ) + + return rc + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/rosidl_adapter_proto/cmake/rosidl_adapt_proto_interfaces.cmake b/rosidl_adapter_proto/cmake/rosidl_adapt_proto_interfaces.cmake new file mode 100644 index 0000000..230e933 --- /dev/null +++ b/rosidl_adapter_proto/cmake/rosidl_adapt_proto_interfaces.cmake @@ -0,0 +1,96 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +find_package(PythonInterp REQUIRED) +if(NOT PYTHON_EXECUTABLE) + message(FATAL_ERROR "Variable 'PYTHON_EXECUTABLE' must not be empty") +endif() + +set(rosidl_adapter_proto_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/rosidl_adapter_proto/${PROJECT_NAME}") + +# Create a list of proto directories +set(_proto_include_dirs "") +foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + set(_proto_dir "${${_pkg_name}_DIR}/../../../share/") + normalize_path(_proto_dir "${_proto_dir}") + list(APPEND _proto_include_dirs "${_proto_dir}") +endforeach() + +set(_target_dependencies + "${rosidl_adapter_proto_BIN}" + ${rosidl_adapter_proto_GENERATOR_FILES} + ${rosidl_generate_interfaces_ABS_IDL_FILES} + ${_proto_include_dirs}) +foreach(dep ${_target_dependencies}) + if(NOT EXISTS "${dep}") + message(FATAL_ERROR "Target dependency '${dep}' does not exist") + endif() +endforeach() + +# Write all this to a file to work around command line length limitations on some platforms +set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_adapter_proto__arguments.json") +rosidl_write_generator_arguments( + "${generator_arguments_file}" + PACKAGE_NAME "${PROJECT_NAME}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" + OUTPUT_DIR "${rosidl_adapter_proto_OUTPUT_DIR}" + TEMPLATE_DIR "${rosidl_adapter_proto_TEMPLATE_DIR}" + TARGET_DEPENDENCIES ${_target_dependencies} + ADDITIONAL_FILES "${_proto_include_dirs}") + +execute_process( + COMMAND "${PYTHON_EXECUTABLE}" "${rosidl_adapter_proto_BIN}" + --generator-arguments-file "${generator_arguments_file}" + --protoc-path "${Protobuf_PROTOC_EXECUTABLE}" + ERROR_VARIABLE error + RESULT_VARIABLE result +) + +if(NOT result EQUAL 0) + message(FATAL_ERROR "Proto file generation failed, error code: ${error}") +endif() + +set(rosidl_adapter_proto_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/rosidl_adapter_proto") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) + get_filename_component(_parent_folder "${_parent_folder}" NAME) + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + list(APPEND rosidl_adapter_proto_GENERATED_CPP "${rosidl_adapter_proto_OUTPUT_DIR}/${_parent_folder}/${_idl_name}.pb.cc") +endforeach() + +# generate header to switch between export and import for a specific package +set(rosidl_adapter_proto_VISIBILITY_CONTROL_HEADER +"${rosidl_adapter_proto_OUTPUT_DIR}/rosidl_adapter_proto__visibility_control.h") +string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER) +configure_file( + "${rosidl_adapter_proto_TEMPLATE_DIR}/rosidl_adapter_proto__visibility_control.h.in" + "${rosidl_adapter_proto_VISIBILITY_CONTROL_HEADER}" + @ONLY +) + +install( + DIRECTORY ${rosidl_adapter_proto_OUTPUT_DIR} + DESTINATION "include/" + PATTERN "*.h" +) + +install( + DIRECTORY ${rosidl_adapter_proto_OUTPUT_DIR} + DESTINATION "share/" + PATTERN "*.proto" +) \ No newline at end of file diff --git a/rosidl_adapter_proto/cmake/rosidl_adapter_proto-extras.cmake.in b/rosidl_adapter_proto/cmake/rosidl_adapter_proto-extras.cmake.in new file mode 100644 index 0000000..24acbaa --- /dev/null +++ b/rosidl_adapter_proto/cmake/rosidl_adapter_proto-extras.cmake.in @@ -0,0 +1,52 @@ +# generated from +# rosidl_adapter_proto/ +# rosidl_adapter_proto-extras.cmake.in + +find_package(Protobuf REQUIRED) + +if(NOT Protobuf_FOUND) + message(STATUS "Could not find Protobuf - skip rosidl_adapter_proto") +else() + find_package(ament_cmake_core QUIET REQUIRED) + ament_register_extension( + "rosidl_generate_idl_interfaces" + "rosidl_adapter_proto" + "${rosidl_adapter_proto_DIR}/rosidl_adapt_proto_interfaces.cmake") + + set(rosidl_adapter_proto_BIN + "${rosidl_adapter_proto_DIR}/../../../lib/rosidl_adapter_proto/rosidl_adapter_proto") + normalize_path(rosidl_adapter_proto_BIN + "${rosidl_adapter_proto_BIN}") + + set(rosidl_adapter_proto_GENERATOR_FILES + "${rosidl_adapter_proto_DIR}/../../../@PYTHON_INSTALL_DIR@/rosidl_adapter_proto/__init__.py") + normalize_path(rosidl_adapter_proto_GENERATOR_FILES + "${rosidl_adapter_proto_GENERATOR_FILES}") + + set(rosidl_adapter_proto_TEMPLATE_DIR + "${rosidl_adapter_proto_DIR}/../resource") + normalize_path(rosidl_adapter_proto_TEMPLATE_DIR + "${rosidl_adapter_proto_TEMPLATE_DIR}") + + include("${rosidl_adapter_proto_DIR}/rosidl_adapt_proto_interfaces.cmake") + + add_compile_definitions("ROSIDL_ADAPTER_PROTO_BUILDING_DLL__${PROJECT_NAME}") + + # There is no clean way to include additional files into protobuf headers + if(NOT WIN32) + add_compile_options("-include${rosidl_adapter_proto_VISIBILITY_CONTROL_HEADER}") + else() + add_compile_options( "/FI\"${rosidl_adapter_proto_VISIBILITY_CONTROL_HEADER}\"") + endif() + + foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + set(_proto_dir "${${_pkg_name}_DIR}/../../../include/${_pkg_name}/rosidl_adapter_proto__visibility_control.h") + normalize_path(_proto_dir "${_proto_dir}") + if(NOT WIN32) + add_compile_options("-include${_proto_dir}") + else() + add_compile_options( "/FI\"${_proto_dir}\"") + endif() + endforeach() + +endif() \ No newline at end of file diff --git a/rosidl_adapter_proto/package.xml b/rosidl_adapter_proto/package.xml new file mode 100644 index 0000000..7b0a027 --- /dev/null +++ b/rosidl_adapter_proto/package.xml @@ -0,0 +1,23 @@ + + + + rosidl_adapter_proto + 0.0.1 + Generate the Protobuf interfaces for Protobuf serialization. + Aleksandar Brakmić + Apache License 2.0 + + ament_cmake + + python3-empy + rosidl_cli + rosidl_parser + + rosidl_interface_packages + + + + ament_cmake + proto + + \ No newline at end of file diff --git a/rosidl_adapter_proto/resource/action.proto.em b/rosidl_adapter_proto/resource/action.proto.em new file mode 100644 index 0000000..5cd66b6 --- /dev/null +++ b/rosidl_adapter_proto/resource/action.proto.em @@ -0,0 +1,63 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +import rosidl_parser.definition as rosidl + +from rosidl_adapter_proto import PROTO_PACKAGE_POSTFIX +from rosidl_adapter_proto import MSG_TYPE_TO_PROTO +from rosidl_adapter_proto import PROTO_ACTION_SEND_GOAL_CALL_NAME +from rosidl_adapter_proto import PROTO_ACTION_GET_RESULT_CALL_NAME + +}@ +option cc_generic_services = true; + +@# +@# ================ Message definitions ================ +@# +@[for message in [action.goal, + action.send_goal_service.request_message, + action.send_goal_service.response_message, + action.result, + action.get_result_service.request_message, + action.get_result_service.response_message, + action.feedback, + action.feedback_message, + ] +]@ +@{ +TEMPLATE( + 'msg.proto.em', + package_name=package_name, + interface_path=interface_path, + message=message, +) +}@ + + +@[end for]@ +@# +@# ================ Service definitions ================ +@# +service @(action.namespaced_type.name) +{ + rpc @(PROTO_ACTION_SEND_GOAL_CALL_NAME) (@(action.send_goal_service.request_message.structure.namespaced_type.name)) returns (@(action.send_goal_service.response_message.structure.namespaced_type.name)); + rpc @(PROTO_ACTION_GET_RESULT_CALL_NAME) (@(action.get_result_service.request_message.structure.namespaced_type.name)) returns (@(action.get_result_service.response_message.structure.namespaced_type.name)); +} \ No newline at end of file diff --git a/rosidl_adapter_proto/resource/idl.proto.em b/rosidl_adapter_proto/resource/idl.proto.em new file mode 100644 index 0000000..56f8c18 --- /dev/null +++ b/rosidl_adapter_proto/resource/idl.proto.em @@ -0,0 +1,127 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +from rosidl_adapter_proto import PROTO_PACKAGE_POSTFIX +}@ +// generated from rosidl_adapter_proto/resource/idl.proto.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice + +syntax = "proto3"; + +package @('.'.join([package_name] + list(interface_path.parts)[:-1] + [PROTO_PACKAGE_POSTFIX])); + +@{ +####################################################################### +# Protobuf imports +####################################################################### +from rosidl_adapter_proto import collect_proto_imports +from rosidl_adapter_proto import to_proto_import +import rosidl_parser.definition as rosidl + +proto_import_set = set() +already_imported = set() + +# Collect imports from plain messages +for message in content.get_elements_of_type(rosidl.Message): + proto_import_set |= collect_proto_imports(message) + + already_imported.add(to_proto_import(message.structure.namespaced_type)) + +# Collect imports from services +for service in content.get_elements_of_type(rosidl.Service): + proto_import_set |= collect_proto_imports(service.request_message) + proto_import_set |= collect_proto_imports(service.response_message) + + already_imported.add(to_proto_import(service.namespaced_type)) + already_imported.add(to_proto_import(service.request_message.structure.namespaced_type)) + already_imported.add(to_proto_import(service.response_message.structure.namespaced_type)) + +# Collect imports from actions +for action in content.get_elements_of_type(rosidl.Action): + proto_import_set |= collect_proto_imports(action.goal) + proto_import_set |= collect_proto_imports(action.send_goal_service.request_message) + proto_import_set |= collect_proto_imports(action.send_goal_service.response_message) + proto_import_set |= collect_proto_imports(action.result) + proto_import_set |= collect_proto_imports(action.get_result_service.request_message) + proto_import_set |= collect_proto_imports(action.get_result_service.response_message) + proto_import_set |= collect_proto_imports(action.feedback) + proto_import_set |= collect_proto_imports(action.feedback_message) + + already_imported.add(to_proto_import(action.namespaced_type)) + already_imported.add(to_proto_import(action.goal.structure.namespaced_type)) + already_imported.add(to_proto_import(action.send_goal_service.request_message.structure.namespaced_type)) + already_imported.add(to_proto_import(action.send_goal_service.response_message.structure.namespaced_type)) + already_imported.add(to_proto_import(action.result.structure.namespaced_type)) + already_imported.add(to_proto_import(action.get_result_service.request_message.structure.namespaced_type)) + already_imported.add(to_proto_import(action.get_result_service.response_message.structure.namespaced_type)) + already_imported.add(to_proto_import(action.feedback.structure.namespaced_type)) + already_imported.add(to_proto_import(action.feedback_message.structure.namespaced_type)) + +for already_imported_proto_file in already_imported: + if already_imported_proto_file in proto_import_set: + proto_import_set.remove(already_imported_proto_file) +}@ +@[for import_proto_file_path in proto_import_set]@ +import "@(import_proto_file_path)"; +@[end for]@ +@# +@# Newline after import statements +@# +@[if len(proto_import_set) != 0]@ + +@[end if]@ +@{ +####################################################################### +# Handle message +####################################################################### +from rosidl_parser.definition import Message +for message in content.get_elements_of_type(Message): + TEMPLATE( + 'msg.proto.em', + package_name=package_name, + interface_path=interface_path, + message=message, + ) + +######################################################################## +## Handle service +######################################################################## +from rosidl_parser.definition import Service +for service in content.get_elements_of_type(Service): + TEMPLATE( + 'srv.proto.em', + package_name=package_name, + interface_path=interface_path, + service=service, + ) + +######################################################################## +## Handle action +######################################################################## +from rosidl_parser.definition import Action +for action in content.get_elements_of_type(Action): + TEMPLATE( + 'action.proto.em', + package_name=package_name, + interface_path=interface_path, + action=action, + ) +}@ \ No newline at end of file diff --git a/rosidl_adapter_proto/resource/msg.proto.em b/rosidl_adapter_proto/resource/msg.proto.em new file mode 100644 index 0000000..c120a5a --- /dev/null +++ b/rosidl_adapter_proto/resource/msg.proto.em @@ -0,0 +1,143 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +import rosidl_parser.definition as rosidl + +from rosidl_adapter_proto import PROTO_PACKAGE_POSTFIX +from rosidl_adapter_proto import MSG_TYPE_TO_PROTO +from rosidl_adapter_proto import compute_proto_field_number + +import sys +import re + +}@ +@# +@# ================ Message definition ================ +@# +@{ +comment = "" +for annotation in message.structure.annotations: + if (annotation.name == "verbatim") \ + and ("language" in annotation.value) \ + and (annotation.value["language"] == "comment") \ + and ("text" in annotation.value): + comment = "//" + re.sub(r"\\n", "\n//", annotation.value["text"]) + break +}@ +@[if comment != ""]@ +@(comment) +@[end if]@ +message @(message.structure.namespaced_type.name) +{ + +@# Message fields +@{ +used_field_numbers = set() +proto_member_list = [] + +str_max_len_type = 0 +str_max_len_name = 0 +str_max_len_field_number = 0 + +for member in message.structure.members: + + idl_type = member.type + + is_repeated = False + is_byte_type = False + is_char_type = False + + # Check if datatype is repeated + if isinstance(idl_type, rosidl.AbstractNestedType): + is_repeated = True + idl_type = idl_type.value_type + + # Check for actual datatype + if isinstance(idl_type, rosidl.BasicType): + proto_type = MSG_TYPE_TO_PROTO[idl_type.typename] + if idl_type.typename in [rosidl.OCTET_TYPE, 'uint8', 'int8']: + is_byte_type = True + elif idl_type.typename in rosidl.CHARACTER_TYPES: + is_char_type = True + elif isinstance(idl_type, rosidl.AbstractString): + proto_type = "string" + elif isinstance(idl_type, rosidl.AbstractWString): + proto_type = "bytes" + elif isinstance(idl_type, rosidl.NamespacedType): + proto_type = ".".join(idl_type.namespaces + [PROTO_PACKAGE_POSTFIX] + [idl_type.name]) + elif isinstance(idl_type, rosidl.NamedType): + proto_type = idl_type.name + + # Check if we can improve the repeated field with a scalar type + if is_repeated: + if is_byte_type: + proto_type = "bytes" + elif is_char_type: + proto_type = "string" + else: + proto_type = "repeated " + proto_type + + # Compute a field number of the actual variable name. This will almost always be unique. + member_name_for_field_number = member.name + additional_counter = 0 + + field_number = compute_proto_field_number(member_name_for_field_number) + + while field_number in used_field_numbers: + sys.stderr.write("WARNING: Field " + member.name + " maps to a protobuf field number that is already in use. This will hurt the downward compatibility of this message..\n") + member_name_for_field_number = member.name + str(additional_counter) + field_number = compute_proto_field_number(member_name_for_field_number) + additional_counter += 1 + + used_field_numbers.add(field_number) + + member_dict = { + "type": proto_type, + "name": member.name, + "field_number": field_number, + } + + for annotation in member.annotations: + if (annotation.name == "verbatim") \ + and ("language" in annotation.value) \ + and (annotation.value["language"] == "comment") \ + and ("text" in annotation.value): + member_dict["comment"] = " //" + re.sub(r"\\n", "\n //", annotation.value["text"]) + if (annotation.name == "unit") and ("value" in annotation.value): + member_dict["unit"] = annotation.value["value"] + + + proto_member_list.append(member_dict) + + str_max_len_type = max(str_max_len_type, len(proto_type)) + str_max_len_name = max(str_max_len_name, len(member.name)) + str_max_len_field_number = max(str_max_len_field_number, len(str(field_number))) +}@ +@[for proto_member in proto_member_list]@ +@[ if "comment" in proto_member]@ + +@(proto_member["comment"]) +@[ end if]@ + @(str.ljust(proto_member["type"], str_max_len_type)) @(str.ljust(proto_member["name"], str_max_len_name)) = @(str.rjust(str(proto_member["field_number"]), str_max_len_field_number));@ +@[ if "unit" in proto_member]@ + // [@(proto_member["unit"])@]@ +@[ end if] +@[end for]@ +} \ No newline at end of file diff --git a/rosidl_adapter_proto/resource/rosidl_adapter_proto__visibility_control.h.in b/rosidl_adapter_proto/resource/rosidl_adapter_proto__visibility_control.h.in new file mode 100644 index 0000000..b88fe70 --- /dev/null +++ b/rosidl_adapter_proto/resource/rosidl_adapter_proto__visibility_control.h.in @@ -0,0 +1,42 @@ +// generated from +// rosidl_typesupport_protobuf/rosidl_adapter_proto/resource/rosidl_adapter_proto__visibility_control.h.in +// generated code does not contain a copyright notice +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define ROSIDL_ADAPTER_PROTO_EXPORT__@PROJECT_NAME@ __attribute__ ((dllexport)) + #define ROSIDL_ADAPTER_PROTO_IMPORT__@PROJECT_NAME@ __attribute__ ((dllimport)) + #else + #define ROSIDL_ADAPTER_PROTO_EXPORT__@PROJECT_NAME@ __declspec(dllexport) + #define ROSIDL_ADAPTER_PROTO_IMPORT__@PROJECT_NAME@ __declspec(dllimport) + #endif + #ifdef ROSIDL_ADAPTER_PROTO_BUILDING_DLL__@PROJECT_NAME@ + #define ROSIDL_ADAPTER_PROTO_PUBLIC__@PROJECT_NAME@ ROSIDL_ADAPTER_PROTO_EXPORT__@PROJECT_NAME@ + #else + #define ROSIDL_ADAPTER_PROTO_PUBLIC__@PROJECT_NAME@ ROSIDL_ADAPTER_PROTO_IMPORT__@PROJECT_NAME@ + #endif + #define ROSIDL_ADAPTER_PROTO_LOCAL__@PROJECT_NAME@ +#else + #define ROSIDL_ADAPTER_PROTO_EXPORT__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_ADAPTER_PROTO_IMPORT__@PROJECT_NAME@ + #if __GNUC__ >= 4 + #define ROSIDL_ADAPTER_PROTO_PUBLIC__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_ADAPTER_PROTO_LOCAL__@PROJECT_NAME@ __attribute__ ((visibility("hidden"))) + #else + #define ROSIDL_ADAPTER_PROTO_PUBLIC__@PROJECT_NAME@ + #define ROSIDL_ADAPTER_PROTO_LOCAL__@PROJECT_NAME@ + #endif +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/rosidl_adapter_proto/resource/srv.proto.em b/rosidl_adapter_proto/resource/srv.proto.em new file mode 100644 index 0000000..e25b279 --- /dev/null +++ b/rosidl_adapter_proto/resource/srv.proto.em @@ -0,0 +1,60 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +import rosidl_parser.definition as rosidl + +from rosidl_adapter_proto import PROTO_PACKAGE_POSTFIX +from rosidl_adapter_proto import MSG_TYPE_TO_PROTO +from rosidl_adapter_proto import PROTO_SERVICE_CALL_NAME + +}@ +option cc_generic_services = true; + +@# +@# ================ Message definitions ================ +@# +@{ +TEMPLATE( + 'msg.proto.em', + package_name=package_name, + interface_path=interface_path, + message=service.request_message, +) +}@ + + +@{ +TEMPLATE( + 'msg.proto.em', + package_name=package_name, + interface_path=interface_path, + message=service.response_message, +) +}@ + + +@# +@# ================ Service definitions ================ +@# +service @(service.namespaced_type.name) +{ + rpc @(PROTO_SERVICE_CALL_NAME) (@(service.request_message.structure.namespaced_type.name)) returns (@(service.response_message.structure.namespaced_type.name)); +} \ No newline at end of file diff --git a/rosidl_adapter_proto/rosidl_adapter_proto/__init__.py b/rosidl_adapter_proto/rosidl_adapter_proto/__init__.py new file mode 100644 index 0000000..5abe056 --- /dev/null +++ b/rosidl_adapter_proto/rosidl_adapter_proto/__init__.py @@ -0,0 +1,114 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +from rosidl_cmake import generate_files + +import rosidl_parser.definition as rosidl + +import subprocess +import zlib + +# A postfix for the protobuf package name / the c++ namespace +PROTO_PACKAGE_POSTFIX = "pb" + +# The rpc-function name for service calls. As ros services can only offer a +# single function, this function gets a static name in the protobuf service +PROTO_SERVICE_CALL_NAME = "Call" + +# The rpc function name for sending an action goal +PROTO_ACTION_SEND_GOAL_CALL_NAME = "SendGoal" + +# The rpc function name for retrieving the action result +PROTO_ACTION_GET_RESULT_CALL_NAME = "GetResult" + +# A Mapping from IDL -> Protobuf type +MSG_TYPE_TO_PROTO = { + 'boolean': 'bool', + 'octet': 'uint32', + 'char': 'uint32', + 'wchar': 'uint32', + 'float': 'float', + 'double': 'double', + 'long double': 'double', + 'uint8': 'uint32', + 'int8': 'int32', + 'uint16': 'uint32', + 'int16': 'int32', + 'uint32': 'fixed32', + 'int32': 'sfixed32', + 'uint64': 'fixed64', + 'int64': 'sfixed64', + 'string': 'string', + 'wstring': 'bytes', +} + +field_val = 0 + +def compute_proto_field_number(variable_name): + # Field number rules (https://developers.google.com/protocol-buffers/docs/proto#assigning_field_numbers) + # + # Smallest: 1 + # Largest: 536870911 (= 2^29 - 1) + # + # Reserved Range: 19000 to 19999 (=> 1000 values) + + field_number = zlib.crc32(bytearray(variable_name, 'utf8')) # Create a 32 bit hash from the variable name + field_number = (field_number % (536870911 - 1000)) # Reduce to the correct amount of values + field_number += 1 # Account for the fact that we must not use 0 + if field_number >= 19000: + field_number += 1000 # Account for the fact that we must not use 19000 to 19999 + + return field_number + +def to_proto_import(namespaced_type): + assert isinstance(namespaced_type, rosidl.NamespacedType) + return "/".join(namespaced_type.namespaces + [namespaced_type.name]) + ".proto" + +def collect_proto_imports(rosidl_message): + assert isinstance(rosidl_message, rosidl.Message) + import_set = set() + + for member in rosidl_message.structure.members: + if isinstance(member.type, rosidl.NamespacedType): + namespaced_type = member.type + elif isinstance(member.type, rosidl.AbstractNestedType) \ + and isinstance(member.type.value_type, rosidl.NamespacedType): + namespaced_type = member.type.value_type + else: + continue + + import_set.add(to_proto_import(namespaced_type)) + + return import_set + +def generate_proto(generator_arguments_file): + mapping = { + 'idl.proto.em': '%s.proto', + } + generate_files(generator_arguments_file, mapping, keep_case=True) + return 0 + +def compile_proto(protoc_path, proto_path_list, cpp_out_dir, proto_files, package_name): + protoc_cmd = [protoc_path] + + for path in proto_path_list: + protoc_cmd.append("--proto_path=" + path) + + protoc_cmd.append(f"--cpp_out=dllexport_decl=ROSIDL_ADAPTER_PROTO_PUBLIC__{package_name}:{cpp_out_dir}") + protoc_cmd = protoc_cmd + proto_files + + subprocess.check_call(protoc_cmd) \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/CHANGELOG.rst b/rosidl_typesupport_protobuf/CHANGELOG.rst new file mode 100644 index 0000000..6694d49 --- /dev/null +++ b/rosidl_typesupport_protobuf/CHANGELOG.rst @@ -0,0 +1,3 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosidl_typesupport_protobuf_cpp +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/CMakeLists.txt b/rosidl_typesupport_protobuf/CMakeLists.txt new file mode 100644 index 0000000..f881b69 --- /dev/null +++ b/rosidl_typesupport_protobuf/CMakeLists.txt @@ -0,0 +1,36 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +cmake_minimum_required(VERSION 3.5) + +project(rosidl_typesupport_protobuf) + +find_package(ament_cmake REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(rosidl_generator_c REQUIRED) + +ament_export_include_directories(include) + +ament_python_install_package(${PROJECT_NAME}) + +install( + DIRECTORY include/ + DESTINATION include +) + +ament_package(CONFIG_EXTRAS "cmake/discover-ros-distro-extras.cmake") \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/cmake/discover-ros-distro-extras.cmake b/rosidl_typesupport_protobuf/cmake/discover-ros-distro-extras.cmake new file mode 100644 index 0000000..47d6000 --- /dev/null +++ b/rosidl_typesupport_protobuf/cmake/discover-ros-distro-extras.cmake @@ -0,0 +1,46 @@ +# ========================= RMW eCAL LICENSE ================================= +# +# Copyright (C) 2019 - 2020 Continental Corporation +# +# 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. +# +# ========================= RMW eCAL LICENSE ================================= + +set(supported_distros + dashing + eloquent + foxy + rolling +) + +list(FIND supported_distros $ENV{ROS_DISTRO} index) +if(index EQUAL -1) + message(FATAL_ERROR "'$ENV{ROS_DISTRO}' is an unsupported ros2 distro.") +endif() + +list(FIND supported_distros foxy foxy_index) + +if(${index} GREATER_EQUAL ${foxy_index}) + set(is_foxy_or_greater true) +else() + set(is_foxy_or_greater false) +endif() + + +set(distro_index 0) +foreach(distro ${supported_distros}) + add_compile_definitions("$=${distro_index}") + MATH(EXPR distro_index "${distro_index}+1") +endforeach() + +add_compile_definitions("ROS_DISTRO=$") \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support.hpp new file mode 100644 index 0000000..33ef29b --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support.hpp @@ -0,0 +1,39 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +namespace rosidl_typesupport_protobuf +{ + +typedef struct message_type_support_t +{ + const char * message_namespace; + const char * message_name; + + bool (* serialize)(const void * ros_message, std::string& serialized_message); + bool (* deserialize)(void * ros_message, const void *serialized_data, size_t size); + std::string (*get_descriptor)(); + +} message_type_support_t; + +} + diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support_decl.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support_decl.hpp new file mode 100644 index 0000000..93d3179 --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/message_type_support_decl.hpp @@ -0,0 +1,35 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +//rosidl_message_type_support_t +#include "rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp" + +namespace rosidl_typesupport_protobuf +{ + +// This is implemented in the shared library provided by this package. +template +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +const rosidl_message_type_support_t * get_message_type_support_handle(); + +} // namespace rosidl_typesupport_protobuf_cpp diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/proto_descriptor_helper.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/proto_descriptor_helper.hpp new file mode 100644 index 0000000..0d71133 --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/proto_descriptor_helper.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include +#include +#include +#include + +// protobuf includes +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4100 4127 4146 4800) // disable proto warnings +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +inline bool HasFile(const google::protobuf::FileDescriptorSet& fset_, const std::string& fname_) +{ + for (auto findex = 0; findex < fset_.file_size(); ++findex) + { + if (fset_.file(findex).name() == fname_) + { + return(true); + } + } + return(false); +} + +inline bool GetFileDescriptor(const google::protobuf::Descriptor* desc_, google::protobuf::FileDescriptorSet& fset_) +{ + + if (desc_ == nullptr) return(false); + const google::protobuf::FileDescriptor* fdesc = desc_->file(); + + for (auto dep = 0; dep < fdesc->dependency_count(); ++dep) + { + // iterate containing messages + const google::protobuf::FileDescriptor* sfdesc = fdesc->dependency(dep); + + for (auto mtype = 0; mtype < sfdesc->message_type_count(); ++mtype) + { + const google::protobuf::Descriptor* desc = sfdesc->message_type(mtype); + GetFileDescriptor(desc, fset_); + } + + // containing enums ? + if (sfdesc->enum_type_count() > 0) + { + const google::protobuf::EnumDescriptor* edesc = sfdesc->enum_type(0); + const google::protobuf::FileDescriptor* efdesc = edesc->file(); + + if (!HasFile(fset_, efdesc->name())) + { + google::protobuf::FileDescriptorProto* epdesc = fset_.add_file(); + efdesc->CopyTo(epdesc); + } + } + + + // containing services ? + if (sfdesc->service_count() > 0) + { + const google::protobuf::ServiceDescriptor* svdesc = sfdesc->service(0); + const google::protobuf::FileDescriptor* svfdesc = svdesc->file(); + + if (!HasFile(fset_, svfdesc->name())) + { + google::protobuf::FileDescriptorProto* svpdesc = fset_.add_file(); + svfdesc->CopyTo(svpdesc); + } + } + } + + if (HasFile(fset_, fdesc->name())) return(true); + + google::protobuf::FileDescriptorProto* pdesc = fset_.add_file(); + fdesc->CopyTo(pdesc); + for (auto field = 0; field < desc_->field_count(); ++field) + { + const google::protobuf::FieldDescriptor* fddesc = desc_->field(field); + const google::protobuf::Descriptor* desc = fddesc->message_type(); + GetFileDescriptor(desc, fset_); + } + + return(true); +} + +template +inline std::string GetProtoMessageDescription() +{ + const google::protobuf::Descriptor* desc = T::descriptor(); + google::protobuf::FileDescriptorSet pset; + if (GetFileDescriptor(desc, pset)) + { + std::string desc_s = pset.SerializeAsString(); + return(desc_s); + } + return(""); +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp new file mode 100644 index 0000000..6fcf54c --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp @@ -0,0 +1,153 @@ +/* ========================= RMW eCAL LICENSE ================================= +* +* Copyright (C) 2019 - 2020 Continental Corporation +* +* 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. +* +* ========================= RMW eCAL LICENSE ================================= +*/ + +//From Foxy distro rosidl_generator_c has been renamed to rosidl_generator_c, +//purpose of this header file is to alias old C type names to new ones, that way the +//rest of the code doesn't have to care about old package name regardless of distro. +//any rosidl_generator_c to rosidl_runtime_c adaptions should be added here + +#pragma once + +#if ROS_DISTRO >= FOXY + +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(STRUCT_NAME) \ + using rosidl_runtime_c__##STRUCT_NAME##__Sequence = rosidl_generator_c__##STRUCT_NAME##__Sequence; + +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(float) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(double) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(long_double) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(char) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(wchar) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(boolean) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(octet) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(uint8) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(int8) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(uint16) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(int16) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(uint32) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(int32) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(uint64) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(int64) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(String) +ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE(U16String) + +#undef ADAPT_PRIMITIVE_SEQUENCE_NAMESPACE + +using rosidl_runtime_c__String = rosidl_generator_c__String; +using rosidl_runtime_c__U16String = rosidl_generator_c__U16String; + +#define rosidl_runtime_c__float__Sequence__fini(sequence) rosidl_generator_c__float__Sequence__fini(sequence) +#define rosidl_runtime_c__float__Sequence__init(sequence, size) rosidl_generator_c__float__Sequence__init(sequence, size) + +#define rosidl_runtime_c__double__Sequence__fini(sequence) rosidl_generator_c__double__Sequence__fini(sequence) +#define rosidl_runtime_c__double__Sequence__init(sequence, size) rosidl_generator_c__double__Sequence__init(sequence, size) + +#define rosidl_runtime_c__long_double__Sequence__fini(sequence) rosidl_generator_c__long_double__Sequence__fini(sequence) +#define rosidl_runtime_c__long_double__Sequence__init(sequence, size) rosidl_generator_c__long_double__Sequence__init(sequence, size) + +#define rosidl_runtime_c__char__Sequence__fini(sequence) rosidl_generator_c__char__Sequence__fini(sequence) +#define rosidl_runtime_c__char__Sequence__init(sequence, size) rosidl_generator_c__char__Sequence__init(sequence, size) + +#define rosidl_runtime_c__wchar__Sequence__fini(sequence) rosidl_generator_c__wchar__Sequence__fini(sequence) +#define rosidl_runtime_c__wchar__Sequence__init(sequence, size) rosidl_generator_c__wchar__Sequence__init(sequence, size) + +#define rosidl_runtime_c__boolean__Sequence__fini(sequence) rosidl_generator_c__boolean__Sequence__fini(sequence) +#define rosidl_runtime_c__boolean__Sequence__init(sequence, size) rosidl_generator_c__boolean__Sequence__init(sequence, size) + +#define rosidl_runtime_c__octet__Sequence__fini(sequence) rosidl_generator_c__octet__Sequence__fini(sequence) +#define rosidl_runtime_c__octet__Sequence__init(sequence, size) rosidl_generator_c__octet__Sequence__init(sequence, size) + +#define rosidl_runtime_c__uint8__Sequence__fini(sequence) rosidl_generator_c__uint8__Sequence__fini(sequence) +#define rosidl_runtime_c__uint8__Sequence__init(sequence, size) rosidl_generator_c__uint8__Sequence__init(sequence, size) + +#define rosidl_runtime_c__int8__Sequence__fini(sequence) rosidl_generator_c__int8__Sequence__fini(sequence) +#define rosidl_runtime_c__int8__Sequence__init(sequence, size) rosidl_generator_c__int8__Sequence__init(sequence, size) + +#define rosidl_runtime_c__uint16__Sequence__fini(sequence) rosidl_generator_c__uint16__Sequence__fini(sequence) +#define rosidl_runtime_c__uint16__Sequence__init(sequence, size) rosidl_generator_c__uint16__Sequence__init(sequence, size) + +#define rosidl_runtime_c__int16__Sequence__fini(sequence) rosidl_generator_c__int16__Sequence__fini(sequence) +#define rosidl_runtime_c__int16__Sequence__init(sequence, size) rosidl_generator_c__int16__Sequence__init(sequence, size) + +#define rosidl_runtime_c__uint32__Sequence__fini(sequence) rosidl_generator_c__uint32__Sequence__fini(sequence) +#define rosidl_runtime_c__uint32__Sequence__init(sequence, size) rosidl_generator_c__uint32__Sequence__init(sequence, size) + +#define rosidl_runtime_c__int32__Sequence__fini(sequence) rosidl_generator_c__int32__Sequence__fini(sequence) +#define rosidl_runtime_c__int32__Sequence__init(sequence, size) rosidl_generator_c__int32__Sequence__init(sequence, size) + +#define rosidl_runtime_c__uint64__Sequence__fini(sequence) rosidl_generator_c__uint64__Sequence__fini(sequence) +#define rosidl_runtime_c__uint64__Sequence__init(sequence, size) rosidl_generator_c__uint64__Sequence__init(sequence, size) + +#define rosidl_runtime_c__int64__Sequence__fini(sequence) rosidl_generator_c__int64__Sequence__fini(sequence) +#define rosidl_runtime_c__int64__Sequence__init(sequence, size) rosidl_generator_c__int64__Sequence__init(sequence, size) + +#define rosidl_runtime_c__bool__Sequence__init(sequence, size) rosidl_generator_c__bool__Sequence__init(sequence, size) +#define rosidl_runtime_c__bool__Sequence__fini(sequence) rosidl_generator_c__bool__Sequence__init(sequence) + +#define rosidl_runtime_c__byte__Sequence__init(sequence, size) rosidl_generator_c__byte__Sequence__init(sequence, size) +#define rosidl_runtime_c__byte__Sequence__fini(sequence) rosidl_generator_c__byte__Sequence__fini(sequence) + +#define rosidl_runtime_c__float32__Sequence__init(sequence, size) rosidl_generator_c__float32__Sequence__init(sequence, size) +#define rosidl_runtime_c__float32__Sequence__fini(sequence) rosidl_generator_c__float32__Sequence__fini(sequence) + +#define rosidl_runtime_c__float64__Sequence__init(sequence, size) rosidl_generator_c__float64__Sequence__init(sequence, size) +#define rosidl_runtime_c__float64__Sequence__fini(sequence) rosidl_generator_c__float64__Sequence__fini(sequence) + +#define rosidl_runtime_c__String__init(str) rosidl_generator_c__String__init(str) +#define rosidl_runtime_c__String__fini(str) rosidl_generator_c__String__fini(str) +#define rosidl_runtime_c__String__assignn(str, value, n) rosidl_generator_c__String__assignn(str, value, n) +#define rosidl_runtime_c__String__assign(str, value) rosidl_generator_c__String__assign(str, value) +#define rosidl_runtime_c__String__Sequence__init(sequence, size) rosidl_generator_c__String__Sequence__init(sequence, size) +#define rosidl_runtime_c__String__Sequence__fini(sequence) rosidl_generator_c__String__Sequence__fini(sequence) +#define rosidl_runtime_c__String__Sequence__create(size) rosidl_generator_c__String__Sequence__create(size) +#define rosidl_runtime_c__String__Sequence__destroy(sequence) rosidl_generator_c__String__Sequence__destroy(sequence) + +#define rosidl_runtime_c__U16String__init(str) rosidl_generator_c__U16String__init(str) +#define rosidl_runtime_c__U16String__fini(str) rosidl_generator_c__U16String__fini(str) +#define rosidl_runtime_c__U16String__assignn(str, value, n) rosidl_generator_c__U16String__assignn(str, value, n) +#define rosidl_runtime_c__U16String__assign(str, value) rosidl_generator_c__U16String__assign(str, value) +#define rosidl_runtime_c__U16String__assignn_from_char(str, value, n) rosidl_generator_c__U16String__assignn_from_char(str, value, n) +#define rosidl_runtime_c__U16String__len(value) rosidl_generator_c__U16String__len(value) +#define rosidl_runtime_c__U16String__resize(str, n) rosidl_generator_c__U16String__resize(str, n) +#define rosidl_runtime_c__U16String__Sequence__init(sequence, size) rosidl_generator_c__U16String__Sequence__init(sequence, size) +#define rosidl_runtime_c__U16String__Sequence__fini(sequence) rosidl_generator_c__U16String__Sequence__fini(sequence) +#define rosidl_runtime_c__U16String__Sequence__create(size) rosidl_generator_c__U16String__Sequence__create(size) +#define rosidl_runtime_c__U16String__Sequence__destroy(sequence) rosidl_generator_c__U16String__Sequence__destroy(sequence) + +#endif \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support.hpp new file mode 100644 index 0000000..da558fc --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support.hpp @@ -0,0 +1,38 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +#include "rosidl_typesupport_protobuf/message_type_support.hpp" + +namespace rosidl_typesupport_protobuf +{ + +typedef struct service_type_support_t +{ + const char * service_namespace; + const char * service_name; + + const rosidl_message_type_support_t * request; + const rosidl_message_type_support_t * response; +} service_type_support_t; + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support_decl.hpp b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support_decl.hpp new file mode 100644 index 0000000..854b99f --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/service_type_support_decl.hpp @@ -0,0 +1,39 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +//rosidl_service_type_support_t +#include "rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp" + +namespace rosidl_typesupport_protobuf +{ + +/// Get the rosidl service typesupport handler of the type. +/** + * This is implemented in the shared library provided by this package.a + * \return The rosidl_service_type_support_t of type T. + */ +template +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +const rosidl_service_type_support_t * get_service_type_support_handle(); + +} // namespace rosidl_typesupport_protobuf_cpp diff --git a/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/visibility_control.h b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/visibility_control.h new file mode 100644 index 0000000..ce6940d --- /dev/null +++ b/rosidl_typesupport_protobuf/include/rosidl_typesupport_protobuf/visibility_control.h @@ -0,0 +1,57 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT __attribute__ ((dllexport)) + #define ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT __attribute__ ((dllimport)) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT __declspec(dllexport) + #define ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT __declspec(dllimport) + #endif + #ifdef ROSIDL_TYPESUPPORT_PROTOBUF_BUILDING_DLL + #define ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT + #endif + #define ROSIDL_TYPESUPPORT_PROTOBUF_LOCAL +#else + #define ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT + #if __GNUC__ >= 4 + #define ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_LOCAL __attribute__ ((visibility("hidden"))) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC + #define ROSIDL_TYPESUPPORT_PROTOBUF_LOCAL + #endif +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/package.xml b/rosidl_typesupport_protobuf/package.xml new file mode 100644 index 0000000..61066a4 --- /dev/null +++ b/rosidl_typesupport_protobuf/package.xml @@ -0,0 +1,16 @@ + + + + rosidl_typesupport_protobuf + 0.0.1 + Shared code for rosidl_typesupport_protobuf_cpp and rosidl_typesupport_protobuf_c. + Aleksandar Brakmić + Apache License 2.0 + + ament_cmake + + + + ament_cmake + + \ No newline at end of file diff --git a/rosidl_typesupport_protobuf/rosidl_typesupport_protobuf/__init__.py b/rosidl_typesupport_protobuf/rosidl_typesupport_protobuf/__init__.py new file mode 100644 index 0000000..a790484 --- /dev/null +++ b/rosidl_typesupport_protobuf/rosidl_typesupport_protobuf/__init__.py @@ -0,0 +1,130 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import os + +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_parser import definition + +# A postfix for the protobuf package name / the c++ namespace +PROTO_PACKAGE_POSTFIX = "pb" + +DISTROS = {"dashing": 0, "eloquent": 1, "foxy": 2} +CURRENT_DISTRO_NAME = os.getenv("ROS_DISTRO") +CURRENT_DISTRO = DISTROS[CURRENT_DISTRO_NAME] + +_TYPE_SUPPORT_NAME = "" +_NAMESPACE_DELIMETER = "" + +def set_type_support_name(val): + global _TYPE_SUPPORT_NAME + _TYPE_SUPPORT_NAME = val + +def set_namespace_delimeter(val): + global _NAMESPACE_DELIMETER + _NAMESPACE_DELIMETER = val + +def ros_message_header(package_name, interface_path): + include_parts = [package_name] + list(interface_path.parents[0].parts) + if CURRENT_DISTRO >= DISTROS["foxy"]: + include_parts += ["detail"] + include_parts += [convert_camel_case_to_lower_case_underscore(interface_path.stem)] + include_base = '/'.join(include_parts) + + return f"{include_base}__struct.hpp" + +def ros_message_header_c(package_name, interface_path): + include_parts = [package_name] + list(interface_path.parents[0].parts) + if CURRENT_DISTRO >= DISTROS["foxy"]: + include_parts += ["detail"] + include_parts += [convert_camel_case_to_lower_case_underscore(interface_path.stem)] + include_base = '/'.join(include_parts) + + return f"{include_base}__struct.h" + +def ros_message_functions_header_c(package_name, interface_path): + include_parts = [package_name] + list(interface_path.parents[0].parts) + if CURRENT_DISTRO >= DISTROS["foxy"]: + include_parts += ["detail"] + include_parts += [convert_camel_case_to_lower_case_underscore(interface_path.stem)] + include_base = '/'.join(include_parts) + + return f"{include_base}__functions.h" + +def ros_message_functions_header_c_from_namespace(namespace, name): + include_parts = namespace; + if CURRENT_DISTRO >= DISTROS["foxy"]: + include_parts += ["detail"] + include_parts += [convert_camel_case_to_lower_case_underscore(name)] + include_base = '/'.join(include_parts) + + return f"{include_base}__functions.h" + +def protobuf_message_header(package_name, interface_path): + include_parts = [package_name] + list(interface_path.parents[0].parts) + include_base = '/'.join(include_parts) + include_prefix = interface_path.stem + + return '/'.join(include_parts + [include_prefix + ".pb.h"]) + +def typesupport_header(package_name, interface_path): + include_parts = [package_name] + list(interface_path.parents[0].parts) + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] + include_base = '/'.join(include_parts) + + return f"{include_base}__{_TYPE_SUPPORT_NAME}.hpp" + +def visibility_control_header(package_name): + return f"{package_name}/{_TYPE_SUPPORT_NAME}__visibility_control.h" + +def ros_type_namespace(package_name, interface_path): + return _NAMESPACE_DELIMETER.join([package_name] + list(interface_path.parents[0].parts)) + +def ros_type_name(message): + return message.structure.namespaced_type.name + +def ros_type(package_name, interface_path, message): + ros_type_ns = ros_type_namespace(package_name, interface_path) + ros_type_nm = ros_type_name(message) + return "::" + _NAMESPACE_DELIMETER.join([ros_type_ns, ros_type_nm]) + +def ros_type_from_namespaced_type(namespaced_type): + return "::" + _NAMESPACE_DELIMETER.join(namespaced_type.namespaces + [namespaced_type.name]) + +def ros_type_from_namespaced_type_c(namespaced_type): + return "::" + _NAMESPACE_DELIMETER.join(namespaced_type.namespaces + [namespaced_type.name]) + +def ros_service_namespace(package_name, interface_path): + return _NAMESPACE_DELIMETER.join([package_name] + list(interface_path.parents[0].parts)) + +def ros_service_name(service): + return service.namespaced_type.name + +def ros_service_type(package_name, interface_path, service): + ros_type_ns = ros_service_namespace(package_name, interface_path) + ros_type_nm = ros_service_name(service) + return "::" + _NAMESPACE_DELIMETER.join([ros_type_ns, ros_type_nm]) + +def protobuf_type(package_name, interface_path, message): + namespace = "::".join([package_name] + list(interface_path.parents[0].parts)) + return "::" + "::".join([namespace, PROTO_PACKAGE_POSTFIX, ros_type_name(message)]) + +def protobuf_type_from_namespaced_type(namespaced_type): + return "::" + "::".join(namespaced_type.namespaces + [PROTO_PACKAGE_POSTFIX, namespaced_type.name]) + +def protobuf_type_from_namespaced_type_c(namespaced_type): + return "::" + "::".join(namespaced_type.namespaces + [PROTO_PACKAGE_POSTFIX, namespaced_type.name]) diff --git a/rosidl_typesupport_protobuf_c/CMakeLists.txt b/rosidl_typesupport_protobuf_c/CMakeLists.txt new file mode 100644 index 0000000..a7e25cd --- /dev/null +++ b/rosidl_typesupport_protobuf_c/CMakeLists.txt @@ -0,0 +1,130 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +cmake_minimum_required(VERSION 3.12) + +project(rosidl_typesupport_protobuf_c) + +if(DEFINED ENV{PROTOBUF_STATIC_DISABLE}) + set(PROTOBUF_STATIC_DISABLE $ENV{PROTOBUF_STATIC_DISABLE} + CACHE BOOL "If Protobuf Static should be disabled.") +else() + set(PROTOBUF_STATIC_DISABLE FALSE + CACHE BOOL "If Protobuf Static should be disabled.") +endif() + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/W4) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + +find_package(ament_cmake REQUIRED) + +if(PROTOBUF_STATIC_DISABLE) + ament_package() + message(STATUS "protobuf static rmw implementation explicitly disabled - skipping '${PROJECT_NAME}'") + return() +endif() + +find_package(rmw REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(rosidl_typesupport_protobuf REQUIRED) +find_package(rosidl_generator_c REQUIRED) +if(${is_foxy_or_greater}) + find_package(rosidl_runtime_c REQUIRED) +endif() +find_package(rosidl_typesupport_introspection_c REQUIRED) +find_package(rosidl_typesupport_introspection_cpp REQUIRED) + +ament_export_dependencies(rmw) +ament_export_dependencies(rosidl_cmake) +ament_export_dependencies(rosidl_generator_c) +if(${is_foxy_or_greater}) + ament_export_dependencies(rosidl_runtime_c) +endif() +ament_export_dependencies(rosidl_typesupport_introspection_c) +ament_export_dependencies(rosidl_typesupport_introspection_cpp) +ament_export_dependencies(rosidl_typesupport_interface) +ament_export_dependencies(rosidl_typesupport_protobuf) + +ament_export_include_directories(include) + +ament_python_install_package(${PROJECT_NAME}) + +add_library(${PROJECT_NAME} SHARED + src/identifier.cpp + src/wstring_conversion.cpp + src/to_ros_c_string.cpp +) +if(WIN32) + target_compile_definitions(${PROJECT_NAME} + PRIVATE "ROSIDL_TYPESUPPORT_PROTOBUF_C_BUILDING_DLL") +endif() + +if(${is_foxy_or_greater}) + ament_target_dependencies(${PROJECT_NAME} "rosidl_typesupport_protobuf" rosidl_runtime_c) +else() + ament_target_dependencies(${PROJECT_NAME} "rosidl_typesupport_protobuf" rosidl_generator_c) +endif() + +target_include_directories(${PROJECT_NAME} PUBLIC include) + +ament_export_libraries(${PROJECT_NAME}) + +ament_target_dependencies(${PROJECT_NAME} rosidl_typesupport_protobuf) + +ament_index_register_resource("rosidl_typesupport_c") + +ament_package( + CONFIG_EXTRAS "cmake/rosidl_typesupport_protobuf_c-extras.cmake.in" +) + +install( + PROGRAMS bin/rosidl_typesupport_protobuf_c + DESTINATION lib/rosidl_typesupport_protobuf_c +) + +install( + DIRECTORY cmake resource + DESTINATION share/${PROJECT_NAME} +) + +install( + DIRECTORY include/ + DESTINATION include +) + +install( + TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/bin/rosidl_typesupport_protobuf_c b/rosidl_typesupport_protobuf_c/bin/rosidl_typesupport_protobuf_c new file mode 100644 index 0000000..42ae009 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/bin/rosidl_typesupport_protobuf_c @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import argparse +import os +import sys +import rosidl_typesupport_protobuf + +from rosidl_typesupport_protobuf_c import generate_typesupport_protobuf_c + +def is_valid_file(parser, file_name): + if not os.path.exists(file_name): + parser.error("File does not exist: '{0}'".format(file_name)) + file_name_abs = os.path.abspath(file_name) + if not os.path.isfile(file_name_abs): + parser.error("Path exists but is not a file: '{0}'".format(file_name_abs)) + return file_name + + +def main(argv=sys.argv[1:]): + parser = argparse.ArgumentParser( + description='Generate the C interfaces for Protobuf.', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '--generator-arguments-file', + required=True, + help='The location of the file containing the generator arguments') + args = parser.parse_args(argv) + + rosidl_typesupport_protobuf.set_namespace_delimeter("__") + rosidl_typesupport_protobuf.set_type_support_name("rosidl_typesupport_protobuf_c") + + return generate_typesupport_protobuf_c(args.generator_arguments_file) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c-extras.cmake.in b/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c-extras.cmake.in new file mode 100644 index 0000000..9a297aa --- /dev/null +++ b/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c-extras.cmake.in @@ -0,0 +1,29 @@ +# generated from +# rosidl_typesupport_protobuf_c/rosidl_typesupport_protobuf_c-extras.cmake.in + +find_package(Protobuf REQUIRED) + +if(NOT Protobuf_FOUND) + message(STATUS "Could not find Protobuf: skipping rosidl_typesupport_protobuf_c") +else() + find_package(ament_cmake_core QUIET REQUIRED) + ament_register_extension( + "rosidl_generate_idl_interfaces" + "rosidl_typesupport_protobuf_c" + "rosidl_typesupport_protobuf_c_generate_interfaces.cmake") + + set(rosidl_typesupport_protobuf_c_BIN + "${rosidl_typesupport_protobuf_c_DIR}/../../../lib/rosidl_typesupport_protobuf_c/rosidl_typesupport_protobuf_c") + normalize_path(rosidl_typesupport_protobuf_c_BIN + "${rosidl_typesupport_protobuf_c_BIN}") + + set(rosidl_typesupport_protobuf_c_GENERATOR_FILES + "${rosidl_typesupport_protobuf_c_DIR}/../../../@PYTHON_INSTALL_DIR@/rosidl_typesupport_protobuf_c/__init__.py") + normalize_path(rosidl_typesupport_protobuf_c_GENERATOR_FILES + "${rosidl_typesupport_protobuf_c_GENERATOR_FILES}") + + set(rosidl_typesupport_protobuf_c_TEMPLATE_DIR + "${rosidl_typesupport_protobuf_c_DIR}/../resource") + normalize_path(rosidl_typesupport_protobuf_c_TEMPLATE_DIR + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}") +endif() diff --git a/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c_generate_interfaces.cmake b/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c_generate_interfaces.cmake new file mode 100644 index 0000000..7077c9c --- /dev/null +++ b/rosidl_typesupport_protobuf_c/cmake/rosidl_typesupport_protobuf_c_generate_interfaces.cmake @@ -0,0 +1,185 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +find_package(Protobuf REQUIRED) + +find_package(rosidl_adapter_proto REQUIRED) +find_package(rosidl_typesupport_protobuf REQUIRED) + +set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_c/${PROJECT_NAME}") +set(_generated_files "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) + get_filename_component(_parent_folder "${_parent_folder}" NAME) + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) + list(APPEND _generated_files + "${_output_path}/${_parent_folder}/${_header_name}__rosidl_typesupport_protobuf_c.hpp" + "${_output_path}/${_parent_folder}/detail/${_header_name}__type_support.cpp" + ) +endforeach() + +set(_dependency_files "") +set(_dependencies "") +foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + foreach(_idl_file ${${_pkg_name}_IDL_FILES}) + set(_abs_idl_file "${${_pkg_name}_DIR}/../${_idl_file}") + normalize_path(_abs_idl_file "${_abs_idl_file}") + list(APPEND _dependency_files "${_abs_idl_file}") + list(APPEND _dependencies "${_pkg_name}:${_abs_idl_file}") + endforeach() +endforeach() + +set(target_dependencies + "${rosidl_typesupport_protobuf_c_BIN}" + ${rosidl_typesupport_protobuf_c_GENERATOR_FILES} + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/idl__rosidl_typesupport_protobuf_c.hpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/idl__type_support.cpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/msg__rosidl_typesupport_protobuf_c.hpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/msg__type_support.cpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/srv__rosidl_typesupport_protobuf_c.hpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/srv__type_support.cpp.em" + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/rosidl_typesupport_protobuf_c__visibility_control.h.in" + ${rosidl_generate_interfaces_ABS_IDL_FILES} + ${_dependency_files} +) + +set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_c__arguments.json") +rosidl_write_generator_arguments( + "${generator_arguments_file}" + PACKAGE_NAME "${PROJECT_NAME}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" + ROS_INTERFACE_DEPENDENCIES "${_dependencies}" + OUTPUT_DIR "${_output_path}" + TEMPLATE_DIR "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}" + TARGET_DEPENDENCIES ${target_dependencies} +) + +add_custom_command( + OUTPUT ${_generated_files} + COMMAND ${PYTHON_EXECUTABLE} ${rosidl_typesupport_protobuf_c_BIN} + --generator-arguments-file "${generator_arguments_file}" + DEPENDS ${target_dependencies} + COMMENT "Generating C type support for Protobuf" + VERBATIM +) + +set(_target_suffix "__rosidl_typesupport_protobuf_c") + +link_directories(${Protobuf_LIBRARY_DIRS}) + +add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} SHARED + ${_generated_files} + ${rosidl_adapter_proto_GENERATED_CPP} +) + +if(rosidl_generate_interfaces_LIBRARY_NAME) + set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES OUTPUT_NAME "${rosidl_generate_interfaces_LIBRARY_NAME}${_target_suffix}") +endif() + +set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES CXX_STANDARD 14 +) + +ament_target_dependencies(${rosidl_generate_interfaces_TARGET}${_target_suffix} + rmw + rosidl_typesupport_protobuf + rosidl_typesupport_protobuf_c + rosidl_typesupport_interface +) + +# Set flag for visibility macro +if(WIN32) + target_compile_definitions(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PRIVATE "ROSIDL_TYPESUPPORT_PROTOBUF_BUILDING_DLL" "ROSIDL_TYPESUPPORT_PROTOBUF_C_BUILDING_DLL__${PROJECT_NAME}") + set (Protobuf_USE_STATIC_LIBS TRUE) +endif() + +if(NOT WIN32) + set(_target_compile_flags "-Wall -Wextra -Wpedantic") +else() + set(_target_compile_flags "/W4") +endif() + +string(REPLACE ";" " " _target_compile_flags "${_target_compile_flags}") +set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES COMPILE_FLAGS "${_target_compile_flags}" +) + +target_include_directories(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PUBLIC + ${_output_path} + ${Protobuf_INCLUDE_DIR} + ${rosidl_adapter_proto_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_c +) + +# generate header to switch between export and import for a specific package +set(_visibility_control_file +"${_output_path}/rosidl_typesupport_protobuf_c__visibility_control.h") +string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER) +configure_file( + "${rosidl_typesupport_protobuf_c_TEMPLATE_DIR}/rosidl_typesupport_protobuf_c__visibility_control.h.in" + "${_visibility_control_file}" + @ONLY +) + +# Depend on dependencies +foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + ament_target_dependencies(${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${_pkg_name}) + target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${${_pkg_name}_LIBRARIES${_target_suffix}}) +endforeach() + +target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${rosidl_generate_interfaces_TARGET}__rosidl_generator_c + ${Protobuf_LIBRARY} +) + +add_dependencies( + ${rosidl_generate_interfaces_TARGET} + ${rosidl_generate_interfaces_TARGET}${_target_suffix} +) + +if(NOT rosidl_generate_interfaces_SKIP_INSTALL) + install( + DIRECTORY "${_output_path}/" + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.cpp" EXCLUDE + ) + + if(NOT _generated_files STREQUAL "") + ament_export_include_directories(include) + endif() + + install( + TARGETS ${rosidl_generate_interfaces_TARGET}${_target_suffix} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + + rosidl_export_typesupport_libraries(${_target_suffix} + ${rosidl_generate_interfaces_TARGET}${_target_suffix}) + + ament_export_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix}) +endif() diff --git a/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/identifier.hpp b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/identifier.hpp new file mode 100644 index 0000000..6e93c1b --- /dev/null +++ b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/identifier.hpp @@ -0,0 +1,30 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +namespace rosidl_typesupport_protobuf_c +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT +extern const char *identifier; + +} // namespace rosidl_typesupport_protobuf_cpp \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/to_ros_c_string.hpp b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/to_ros_c_string.hpp new file mode 100644 index 0000000..ebd741e --- /dev/null +++ b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/to_ros_c_string.hpp @@ -0,0 +1,33 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +#include "rosidl_typesupport_protobuf/visibility_control.h" +#include "rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp" + +namespace typesupport_protobuf_c +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +void to_ros_c_string(const std::string &str, rosidl_runtime_c__String &ros_str); + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/wstring_conversion.hpp b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/wstring_conversion.hpp new file mode 100644 index 0000000..c6db489 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/include/rosidl_typesupport_protobuf_c/wstring_conversion.hpp @@ -0,0 +1,36 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +#include "rosidl_typesupport_protobuf/visibility_control.h" +#include "rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp" + +namespace rosidl_typesupport_protobuf_c +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +void write_to_string(const rosidl_runtime_c__U16String &u16str, std::string &str); + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +void write_to_u16string(const std::string &str, rosidl_runtime_c__U16String &u16str); + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/package.xml b/rosidl_typesupport_protobuf_c/package.xml new file mode 100644 index 0000000..d52b0ea --- /dev/null +++ b/rosidl_typesupport_protobuf_c/package.xml @@ -0,0 +1,35 @@ + + + + rosidl_typesupport_protobuf_c + 0.0.1 + Generate the C interfaces for Protobuf. + Aleksandar Brakmić + Apache License 2.0 + + ament_cmake + rosidl_cmake + rosidl_generator_c + rosidl_adapter_proto + rosidl_typesupport_protobuf + + ament_cmake + rosidl_cmake + rosidl_adapter_proto + rosidl_generator_c + rosidl_typesupport_protobuf + + rmw + + rosidl_parser + rosidl_typesupport_interface + + ament_lint_auto + ament_lint_common + + rosidl_typesupport_c_packages + + + ament_cmake + + diff --git a/rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em b/rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em new file mode 100644 index 0000000..3051145 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em @@ -0,0 +1,92 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +// generated from rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __rosidl_typesupport_protobuf_c.hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +#pragma once + +@{ + +include_directives = set() + +####################################################################### +# Handle message +####################################################################### +from rosidl_parser.definition import Message +for message in content.get_elements_of_type(Message): + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=message, + include_directives=include_directives) + +####################################################################### +# Handle service +####################################################################### +from rosidl_parser.definition import Service +for service in content.get_elements_of_type(Service): + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, + interface_path=interface_path, + service=service, + include_directives=include_directives) + +####################################################################### +# Handle action +####################################################################### +from rosidl_parser.definition import Action +for action in content.get_elements_of_type(Action): + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/resource/idl__type_support.cpp.em b/rosidl_typesupport_protobuf_c/resource/idl__type_support.cpp.em new file mode 100644 index 0000000..ea6864d --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/idl__type_support.cpp.em @@ -0,0 +1,121 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +// generated from rosidl_typesupport_protobuf_c/resource/idl__type_support.cpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __type_support.cpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_typesupport_protobuf import * + +include_directives = set() +forward_declared_types = set() + +system_header_files = [] +header_files = [ + typesupport_header(package_name, interface_path), + ros_message_header_c(package_name, interface_path), + ros_message_functions_header_c(package_name, interface_path) +] + +}@ + +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ + +####################################################################### +# Handle message +####################################################################### +from rosidl_parser.definition import Message +for message in content.get_elements_of_type(Message): + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + +####################################################################### +# Handle service +####################################################################### +from rosidl_parser.definition import Service +for service in content.get_elements_of_type(Service): + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + service=service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + +####################################################################### +# Handle action +####################################################################### +from rosidl_parser.definition import Action +for action in content.get_elements_of_type(Action): + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/resource/msg__rosidl_typesupport_protobuf_c.hpp.em b/rosidl_typesupport_protobuf_c/resource/msg__rosidl_typesupport_protobuf_c.hpp.em new file mode 100644 index 0000000..5bc5342 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/msg__rosidl_typesupport_protobuf_c.hpp.em @@ -0,0 +1,85 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_typesupport_protobuf import * + +system_header_files = [ + "string" +] + +header_files = [ + "rosidl_typesupport_cpp/message_type_support.hpp", + ros_message_header_c(package_name, interface_path), + ros_message_header(package_name, interface_path), + visibility_control_header(package_name), + "rosidl_typesupport_interface/macros.h", + protobuf_message_header(package_name, interface_path) +] + +ros_type_ns = ros_type_namespace(package_name, interface_path) +ros_type_name = ros_type_name(message) +ros_type = ros_type(package_name, interface_path, message) +proto_type = protobuf_type(package_name, interface_path, message) + +}@ + +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@[for ns in message.structure.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[end for]@ +namespace typesupport_protobuf_c +{ + +bool +ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@(package_name) +convert_to_proto(const @(ros_type) &ros_msg, @(proto_type) &pb_msg); + +bool +ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@(package_name) +convert_to_ros(const @(proto_type) &pb_msg, @(ros_type) &ros_msg); + +} // namespace typesupport_protobuf_c +@[ for ns in reversed(message.structure.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +#ifdef __cplusplus +extern "C" +{ +#endif + +ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@(package_name) +const rosidl_message_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(ros_type_ns.replace("__", ", ")), @(ros_type_name))(); + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_c/resource/msg__type_support.cpp.em b/rosidl_typesupport_protobuf_c/resource/msg__type_support.cpp.em new file mode 100644 index 0000000..2815849 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/msg__type_support.cpp.em @@ -0,0 +1,338 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_c/resource/idl__type_support.c.em +@{ +import rosidl_parser.parser as rosidl +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_parser.definition import * +from rosidl_typesupport_protobuf import * + +ros_type_ns = ros_type_namespace(package_name, interface_path) +ros_type_name = ros_type_name(message) +ros_type = ros_type(package_name, interface_path, message) +proto_type = protobuf_type(package_name, interface_path, message) + +system_header_files = [ + 'string', + 'algorithm' +] + +header_files = [ + 'rosidl_typesupport_cpp/message_type_support.hpp', + visibility_control_header(package_name), + 'rosidl_typesupport_protobuf_c/identifier.hpp', + 'rosidl_typesupport_protobuf_c/to_ros_c_string.hpp', + 'rosidl_typesupport_protobuf_c/wstring_conversion.hpp', + 'rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp', + 'rosidl_typesupport_protobuf/message_type_support.hpp', + 'rosidl_typesupport_protobuf/message_type_support_decl.hpp', + 'rosidl_typesupport_protobuf/proto_descriptor_helper.hpp', + protobuf_message_header(package_name, interface_path) +] + +for member in message.structure.members: + keys = set([]) + type_ = member.type + + if isinstance(type_, AbstractNestedType): + type_ = type_.value_type + if isinstance(type_, NamespacedType): + if ( + type_.name.endswith(ACTION_GOAL_SUFFIX) or + type_.name.endswith(ACTION_RESULT_SUFFIX) or + type_.name.endswith(ACTION_FEEDBACK_SUFFIX) + ): + typename = type_.name.rsplit('_', 1)[0] + else: + typename = type_.name + + keys.add(ros_message_functions_header_c_from_namespace(type_.namespaces, typename)) + + for key in keys: + header_files.append(key) + + header_files.sort(); + +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'tmpl_forward_declarations.em', + message=message, + forward_declared_types=forward_declared_types +) +}@ +@[ for ns in message.structure.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[ end for]@ +namespace typesupport_protobuf_c +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@(package_name) +bool convert_to_proto(const @(ros_type) &ros_msg, @(proto_type) &pb_msg) +{ +@[for member in message.structure.members]@ + // Member: @(member.name) +@[ if isinstance(member.type, AbstractNestedType)]@ +@[ if isinstance(member.type, Array)]@ +@[ if isinstance(member.type.value_type, BasicType)]@ + *pb_msg.mutable_@(member.name)() = { std::begin(ros_msg.@(member.name)), std::end(ros_msg.@(member.name)) }; +@[ elif isinstance(member.type.value_type, AbstractString)]@ + for(auto &data : ros_msg.@(member.name)) + { + auto &str{*pb_msg.add_@(member.name)()}; + str = data.data; + } +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + for(auto &data : ros_msg.@(member.name)) + { + auto &str{*pb_msg.add_@(member.name)()}; + ::rosidl_typesupport_protobuf_c::write_to_string(data, str); + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + for(auto &data : ros_msg.@(member.name)) + { + auto ptr{pb_msg.add_@(member.name)()}; + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_c::convert_to_proto(data, *ptr); + } +@[ end if]@ +@[ elif isinstance(member.type, AbstractSequence)]@ + { + auto size{ros_msg.@(member.name).size}; + auto data{ros_msg.@(member.name).data}; + auto arr_ptr{pb_msg.mutable_@(member.name)()}; +@[ if isinstance(member.type.value_type, BasicType)]@ +@{is_string = member.type.value_type.typename in [*CHARACTER_TYPES, OCTET_TYPE, 'uint8', 'int8']}@ +@[ if is_string]@ + arr_ptr->insert(arr_ptr->end(), data, data + size); +@[ else] + arr_ptr->Reserve(size); + for(size_t i{0}; i < size; i++) + { + arr_ptr->AddAlreadyReserved(data[i]); + } +@[ end if]@ +@[ elif isinstance(member.type.value_type, AbstractString)]@ + arr_ptr->Reserve(size); + for(size_t i{0}; i < size; i++) + { + arr_ptr->Add({data[i].data, data[i].size}); + } +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + arr_ptr->Reserve(size); + for(size_t i{0}; i < size; i++) + { + ::rosidl_typesupport_protobuf_c::write_to_string(data[i], *arr_ptr->Add()); + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + arr_ptr->Reserve(size); + for(size_t i{0}; i < size; i++) + { + auto obj{arr_ptr->Add()}; + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_c::convert_to_proto(data[i], *obj); + } +@[ end if]@ + } +@[ end if]@ +@[ elif isinstance(member.type, BasicType)]@ + pb_msg.set_@(member.name)(ros_msg.@(member.name)); +@[ elif isinstance(member.type, AbstractString)]@ + pb_msg.set_@(member.name)(ros_msg.@(member.name).data); +@[ elif isinstance(member.type, AbstractWString)]@ + ::rosidl_typesupport_protobuf_c::write_to_string(ros_msg.@(member.name), *pb_msg.mutable_@(member.name)()); +@[ elif isinstance(member.type, NamespacedType)]@ + @("::" + "::".join(member.type.namespaces))::typesupport_protobuf_c::convert_to_proto(ros_msg.@(member.name), *pb_msg.mutable_@(member.name)()); +@[ end if]@ +@[end for]@ + + return true; +} + +ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@(package_name) +bool convert_to_ros(const @(proto_type) &pb_msg, @(ros_type) &ros_msg) +{ +@[for member in message.structure.members]@ + // Member: @(member.name) +@[ if isinstance(member.type, AbstractNestedType)]@ +@[ if isinstance(member.type, Array)]@ + { + auto &pb_arr{pb_msg.@(member.name)()}; + +@[ if isinstance(member.type.value_type, BasicType)]@ + std::copy(pb_arr.begin(), pb_arr.end(), ros_msg.@(member.name)); +@[ elif isinstance(member.type.value_type, AbstractString)]@ + for(size_t i{0}; i < sizeof(ros_msg.@(member.name))/sizeof(ros_msg.@(member.name)[0]); i++) + { + ::typesupport_protobuf_c::to_ros_c_string(pb_arr[i], ros_msg.@(member.name)[i]); + } +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + for(size_t i{0}; i < sizeof(ros_msg.@(member.name))/sizeof(ros_msg.@(member.name)[0]); i++) + { + ::rosidl_typesupport_protobuf_c::write_to_u16string(pb_arr[i], ros_msg.@(member.name)[i]); + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + for(size_t i{0}; i < sizeof(ros_msg.@(member.name))/sizeof(ros_msg.@(member.name)[0]); i++) + { + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_c::convert_to_ros(pb_arr[i], ros_msg.@(member.name)[i]); + } +@[ end if]@ + } +@[ elif isinstance(member.type, AbstractSequence)]@ +@{ +value_type_ = member.type.value_type +if isinstance(value_type_, AbstractString): + array_init = 'rosidl_runtime_c__String__Sequence__init' + array_fini = 'rosidl_runtime_c__String__Sequence__fini' +elif isinstance(value_type_, AbstractWString): + array_init = 'rosidl_runtime_c__U16String__Sequence__init' + array_fini = 'rosidl_runtime_c__U16String__Sequence__fini' +elif isinstance(value_type_, BasicType): + type_ = value_type_.typename + type_ = type_.replace(' ', '_') + array_init = 'rosidl_runtime_c__{type_}__Sequence__init'.format(**locals()) + array_fini = 'rosidl_runtime_c__{type_}__Sequence__fini'.format(**locals()) +else: + type_ = value_type_ + array_init = '__'.join(type_.namespaced_name()) + '__Sequence__init' + array_fini = '__'.join(type_.namespaced_name()) + '__Sequence__fini' +}@ + { + auto &pb_arr{pb_msg.@(member.name)()}; + auto size{pb_arr.size()}; + + @(array_init)(&ros_msg.@(member.name), size); + auto ros_arr{ros_msg.@(member.name).data}; + +@[ if isinstance(member.type.value_type, BasicType)]@ + std::copy(pb_arr.begin(), pb_arr.end(), ros_arr); +@[ elif isinstance(member.type.value_type, AbstractString)]@ + for(int i{0}; i < size; i++) + { + ::typesupport_protobuf_c::to_ros_c_string(pb_arr[i], ros_arr[i]); + } +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + for(int i{0}; i < size; i++) + { + ::rosidl_typesupport_protobuf_c::write_to_u16string(pb_arr[i], ros_arr[i]); + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + for(int i{0}; i < size; i++) + { + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_c::convert_to_ros(pb_arr[i], ros_arr[i]); + } +@[ end if]@ + } +@[ end if]@ +@[ elif isinstance(member.type, BasicType)]@ + ros_msg.@(member.name) = pb_msg.@(member.name)(); +@[ elif isinstance(member.type, AbstractString)]@ + ::typesupport_protobuf_c::to_ros_c_string(pb_msg.@(member.name)(), ros_msg.@(member.name)); +@[ elif isinstance(member.type, AbstractWString)]@ + ::rosidl_typesupport_protobuf_c::write_to_u16string(pb_msg.@(member.name)(), ros_msg.@(member.name)); +@[ elif isinstance(member.type, NamespacedType)]@ + @("::" + "::".join(member.type.namespaces))::typesupport_protobuf_c::convert_to_ros(pb_msg.@(member.name)(), ros_msg.@(member.name)); +@[ end if]@ +@[end for]@ + + return true; +} + +static bool _@(ros_type_name)__serialize(const void *untyped_ros_msg, std::string &serialized_msg) +{ + @(proto_type) pb_msg{}; + auto ros_msg{static_cast(untyped_ros_msg)}; + + convert_to_proto(*ros_msg, pb_msg); + return pb_msg.SerializeToString(&serialized_msg); +} + +static bool _@(ros_type_name)__deserialize(void *untyped_ros_msg, const void *serialized_msg, size_t size) +{ + @(proto_type) pb_msg{}; + auto ros_msg{static_cast<@(ros_type) *>(untyped_ros_msg)}; + + pb_msg.ParseFromArray(serialized_msg, size); + return convert_to_ros(pb_msg, *ros_msg); +} + +static std::string _@(ros_type_name)__get_descriptor() +{ + return ""; + return GetProtoMessageDescription<@(proto_type)>(); +} + +@{type_support_name = "_" + ros_type_name + "__type_support"}@ +static rosidl_typesupport_protobuf::message_type_support_t @(type_support_name) = { + "@(ros_type_ns.replace("__", "::"))", + "@(ros_type_name)", + _@(ros_type_name)__serialize, + _@(ros_type_name)__deserialize, + _@(ros_type_name)__get_descriptor +}; + +@{ +handle_name = "_" + ros_type_name + "__handle" +namespaced_handle_name = "::".join([ros_type_ns.replace("__", "::"), "typesupport_protobuf_c", handle_name]) +}@ +static rosidl_message_type_support_t @(handle_name) = { + rosidl_typesupport_protobuf_c::identifier, + &@(type_support_name), + get_message_typesupport_handle_function +}; + +} // namespace typesupport_protobuf_c +@[ for ns in reversed(message.structure.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +namespace rosidl_typesupport_protobuf +{ + +template<> +ROSIDL_TYPESUPPORT_PROTOBUF_C_EXPORT__@(package_name) +const rosidl_message_type_support_t *get_message_type_support_handle<@(ros_type)>() +{ + return &@(namespaced_handle_name); +} + +} // namespace rosidl_typesupport_protobuf + +#ifdef __cplusplus +extern "C" +{ +#endif + +const rosidl_message_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(ros_type_ns.replace("__", ", ")), @(ros_type_name))() { + return &@(namespaced_handle_name); +} + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_c/resource/rosidl_typesupport_protobuf_c__visibility_control.h.in b/rosidl_typesupport_protobuf_c/resource/rosidl_typesupport_protobuf_c__visibility_control.h.in new file mode 100644 index 0000000..4a62e64 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/rosidl_typesupport_protobuf_c__visibility_control.h.in @@ -0,0 +1,42 @@ +// generated from +// rosidl_typesupport_protobuf/rosidl_typesupport_protobuf_cpp/resource/visibility_control.h.in +// generated code does not contain a copyright notice +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_EXPORT__@PROJECT_NAME@ __attribute__ ((dllexport)) + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_IMPORT__@PROJECT_NAME@ __attribute__ ((dllimport)) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_EXPORT__@PROJECT_NAME@ __declspec(dllexport) + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_IMPORT__@PROJECT_NAME@ __declspec(dllimport) + #endif + #ifdef ROSIDL_TYPESUPPORT_PROTOBUF_C_BUILDING_DLL__@PROJECT_NAME@ + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@PROJECT_NAME@ ROSIDL_TYPESUPPORT_PROTOBUF_C_EXPORT__@PROJECT_NAME@ + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@PROJECT_NAME@ ROSIDL_TYPESUPPORT_PROTOBUF_C_IMPORT__@PROJECT_NAME@ + #endif + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_LOCAL__@PROJECT_NAME@ +#else + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_EXPORT__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_IMPORT__@PROJECT_NAME@ + #if __GNUC__ >= 4 + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_LOCAL__@PROJECT_NAME@ __attribute__ ((visibility("hidden"))) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_PUBLIC__@PROJECT_NAME@ + #define ROSIDL_TYPESUPPORT_PROTOBUF_C_LOCAL__@PROJECT_NAME@ + #endif +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/resource/srv__rosidl_typesupport_protobuf_c.hpp.em b/rosidl_typesupport_protobuf_c/resource/srv__rosidl_typesupport_protobuf_c.hpp.em new file mode 100644 index 0000000..e6cce60 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/srv__rosidl_typesupport_protobuf_c.hpp.em @@ -0,0 +1,49 @@ +@# Included from rosidl_typesupport_protobuf_c/resource/idl__rosidl_typesupport_protobuf_c.hpp.em +@{ +system_header_files = [] +header_files = [ + 'rmw/types.h', + 'rosidl_typesupport_cpp/service_type_support.hpp', + 'rosidl_typesupport_interface/macros.h', + 'rosidl_typesupport_protobuf/visibility_control.h', +] +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_protobuf_c.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.response_message, + include_directives=include_directives) +}@ + +#ifdef __cplusplus +extern "C" +{ +#endif + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +const rosidl_service_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(', '.join([package_name] + list(interface_path.parents[0].parts) + [service.namespaced_type.name])))(); + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_c/resource/srv__type_support.cpp.em b/rosidl_typesupport_protobuf_c/resource/srv__type_support.cpp.em new file mode 100644 index 0000000..9e7e50a --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/srv__type_support.cpp.em @@ -0,0 +1,116 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_c/resource/idl__type_support.cpp.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_typesupport_protobuf import ros_service_name, ros_service_namespace, ros_service_type + +system_header_files = [] +header_files = [ + 'rmw/error_handling.h', + 'rosidl_typesupport_protobuf_c/identifier.hpp', + 'rosidl_typesupport_protobuf/service_type_support.hpp', + 'rosidl_typesupport_protobuf/service_type_support_decl.hpp', +] + +service_name = ros_service_name(service) +service_namespace = ros_service_namespace(package_name, interface_path) +service_type = ros_service_type(package_name, interface_path, service) + +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files = system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.request_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.response_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ + +@[for ns in service.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[end for]@ +namespace typesupport_protobuf_c +{ + +static rosidl_typesupport_protobuf::service_type_support_t _@(service.namespaced_type.name)__callbacks = { + "@(service_namespace.replace("__", "::"))", + "@(service_name)", + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name)_Request)(), + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name)_Response)(), +}; + +static rosidl_service_type_support_t _@(service.namespaced_type.name)__handle = { + rosidl_typesupport_protobuf_c::identifier, + &_@(service_name)__callbacks, + get_service_typesupport_handle_function, +}; + +} // namespace typesupport_protobuf_c +@[for ns in reversed(service.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[end for]@ + +namespace rosidl_typesupport_protobuf +{ + +template<> +ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT +const rosidl_service_type_support_t * +get_service_type_support_handle<@('::'.join([package_name] + list(interface_path.parents[0].parts) + [service.namespaced_type.name]))>() +{ + return &@('::'.join([package_name] + list(interface_path.parents[0].parts)))::typesupport_protobuf_c::_@(service.namespaced_type.name)__handle; +} + +} // namespace rosidl_typesupport_protobuf_c + +#ifdef __cplusplus +extern "C" +{ +#endif + +const rosidl_service_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_protobuf_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name))() { + return &@('::'.join([package_name] + list(interface_path.parents[0].parts)))::typesupport_protobuf_c::_@(service.namespaced_type.name)__handle; +} + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_c/resource/tmpl_forward_declarations.em b/rosidl_typesupport_protobuf_c/resource/tmpl_forward_declarations.em new file mode 100644 index 0000000..16880f8 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/tmpl_forward_declarations.em @@ -0,0 +1,74 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +from rosidl_parser.definition import * +from rosidl_typesupport_protobuf import PROTO_PACKAGE_POSTFIX, ros_type_from_namespaced_type, ros_type_from_namespaced_type_c, protobuf_type_from_namespaced_type, protobuf_type_from_namespaced_type_c + +def isNamespacedType(type_): + from rosidl_parser.definition import NamespacedType + return isinstance(type_, NamespacedType) + +def isNamespacedArrayType(type_): + from rosidl_parser.definition import AbstractNestedType + from rosidl_parser.definition import NamespacedType + return isinstance(type_, AbstractNestedType) and isinstance(type_.value_type, NamespacedType) + +def isTypeAlreadyDeclared(type_, fw_declared_types): + from rosidl_typesupport_protobuf import ros_type_from_namespaced_type + return ros_type_from_namespaced_type(type_) in fw_declared_types + +def registerDeclaredType(type_, fw_declared_types): + from rosidl_typesupport_protobuf import ros_type_from_namespaced_type + fw_declared_types.add(ros_type_from_namespaced_type(type_)) + +types_to_declare = list() +for member in message.structure.members: + if isNamespacedType(member.type) and not isTypeAlreadyDeclared(member.type, forward_declared_types): + types_to_declare.append(member.type) + registerDeclaredType(member.type, forward_declared_types) + elif isNamespacedArrayType(member.type) and not isTypeAlreadyDeclared(member.type.value_type, forward_declared_types): + types_to_declare.append(member.type.value_type) + registerDeclaredType(member.type.value_type, forward_declared_types) +}@ +@[if len(types_to_declare) > 0]@ +// forward declaration of message dependencies and their conversion functions +@[end if]@ +@[for type_ in types_to_declare]@ +@{ +ros_type = ros_type_from_namespaced_type_c(type_) +proto_type = protobuf_type_from_namespaced_type_c(type_) +}@ + +@[ for ns in type_.namespaces]@ +namespace @(ns) +{ +@[ end for]@ +namespace typesupport_protobuf_c +{ + +bool convert_to_proto(const @(ros_type)&, @(proto_type)&); +bool convert_to_ros(const @(proto_type)&, @(ros_type)&); + +} // namespace typesupport_protobuf_cpp +@[ for ns in reversed(type_.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +@[end for]@ diff --git a/rosidl_typesupport_protobuf_c/resource/tmpl_include_directories.em b/rosidl_typesupport_protobuf_c/resource/tmpl_include_directories.em new file mode 100644 index 0000000..0923243 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/resource/tmpl_include_directories.em @@ -0,0 +1,47 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +def is_protobuf_header(header_file): + header_file.endswith(".pb.h") +} +@[for header_file in system_header_files]@ +@[ if header_file not in include_directives]@ +@{include_directives.add(header_file)}@ +#include <@(header_file)> +@[ end if]@ +@[end for]@ + +@[for header_file in header_files]@ +@[ if header_file not in include_directives]@ +@{include_directives.add(header_file)}@ +@[ if is_protobuf_header(header_file)]@ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127 4146 4800) +#endif +#include "@(header_file)" +#ifdef _MSC_VER +#pragma warning(pop) +#endif +@[ else]@ +#include "@(header_file)" +@[ end if]@ +@[ end if]@ +@[end for]@ diff --git a/rosidl_typesupport_protobuf_c/rosidl_typesupport_protobuf_c/__init__.py b/rosidl_typesupport_protobuf_c/rosidl_typesupport_protobuf_c/__init__.py new file mode 100644 index 0000000..1be76da --- /dev/null +++ b/rosidl_typesupport_protobuf_c/rosidl_typesupport_protobuf_c/__init__.py @@ -0,0 +1,26 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +from rosidl_cmake import generate_files + +def generate_typesupport_protobuf_c(generator_arguments_file): + mapping = { + 'idl__rosidl_typesupport_protobuf_c.hpp.em': '%s__rosidl_typesupport_protobuf_c.hpp', + 'idl__type_support.cpp.em': 'detail/%s__type_support.cpp', + } + generate_files(generator_arguments_file, mapping) diff --git a/rosidl_typesupport_protobuf_c/src/identifier.cpp b/rosidl_typesupport_protobuf_c/src/identifier.cpp new file mode 100644 index 0000000..24c42e4 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/src/identifier.cpp @@ -0,0 +1,29 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#include + +namespace rosidl_typesupport_protobuf_c +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT +const char *identifier = "rosidl_typesupport_protobuf_c"; + +} // namespace rosidl_typesupport_protobuf_cpp + diff --git a/rosidl_typesupport_protobuf_c/src/to_ros_c_string.cpp b/rosidl_typesupport_protobuf_c/src/to_ros_c_string.cpp new file mode 100644 index 0000000..29e31f3 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/src/to_ros_c_string.cpp @@ -0,0 +1,32 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include "rosidl_typesupport_protobuf_c/to_ros_c_string.hpp" + +namespace typesupport_protobuf_c +{ + +void to_ros_c_string(const std::string &str, rosidl_runtime_c__String &ros_str) +{ + rosidl_runtime_c__String__assignn(&ros_str, &str[0], str.size()); +} + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_c/src/wstring_conversion.cpp b/rosidl_typesupport_protobuf_c/src/wstring_conversion.cpp new file mode 100644 index 0000000..fca0bd5 --- /dev/null +++ b/rosidl_typesupport_protobuf_c/src/wstring_conversion.cpp @@ -0,0 +1,46 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include "rosidl_typesupport_protobuf_c/wstring_conversion.hpp" + +#include + +namespace rosidl_typesupport_protobuf_c +{ + +void write_to_string(const rosidl_runtime_c__U16String &u16str, std::string &str) +{ + auto data_size = u16str.size * sizeof(decltype(*u16str.data)); + str.resize(data_size); + auto str_start = &str[0]; + std::memcpy(str_start, u16str.data, data_size); +} + +void write_to_u16string(const std::string &str, rosidl_runtime_c__U16String &u16str) +{ + auto data_size = str.size(); + auto u16str_size = str.size() / sizeof(decltype(*u16str.data)); + rosidl_runtime_c__U16String__resize(&u16str, u16str_size); + auto wstr_start = u16str.data; + std::memcpy(wstr_start, str.data(), data_size); +} + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/CMakeLists.txt b/rosidl_typesupport_protobuf_cpp/CMakeLists.txt new file mode 100644 index 0000000..d7697aa --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/CMakeLists.txt @@ -0,0 +1,107 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +cmake_minimum_required(VERSION 3.12) + +project(rosidl_typesupport_protobuf_cpp) + +if(DEFINED ENV{PROTOBUF_STATIC_DISABLE}) + set(PROTOBUF_STATIC_DISABLE $ENV{PROTOBUF_STATIC_DISABLE} + CACHE BOOL "If Protobuf Static should be disabled.") +else() + set(PROTOBUF_STATIC_DISABLE FALSE + CACHE BOOL "If Protobuf Static should be disabled.") +endif() + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + add_compile_options(/W4) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() + +find_package(ament_cmake REQUIRED) +if(PROTOBUF_STATIC_DISABLE) + ament_package() + message(STATUS "Protobuf static typesupport implementation explicitly disabled - skipping '${PROJECT_NAME}'") + return() +endif() + +find_package(ament_cmake_python REQUIRED) +find_package(rosidl_typesupport_protobuf REQUIRED) +find_package(rosidl_generator_c REQUIRED) + +ament_export_dependencies(rmw) +ament_export_dependencies(rcutils) +ament_export_dependencies(rosidl_cmake) +ament_export_dependencies(rosidl_generator_c) +ament_export_dependencies(rosidl_generator_cpp) +ament_export_dependencies(rosidl_typesupport_interface) +ament_export_dependencies(rosidl_typesupport_protobuf) + +ament_export_include_directories(include) + +ament_python_install_package(${PROJECT_NAME}) + +add_library(${PROJECT_NAME} SHARED + src/identifier.cpp + src/wstring_conversion.cpp) + +if(WIN32) + target_compile_definitions(${PROJECT_NAME} + PRIVATE "ROSIDL_TYPESUPPORT_PROTOBUF_CPP_BUILDING_DLL") +endif() + +target_include_directories(${PROJECT_NAME} + PUBLIC include +) + +ament_target_dependencies(${PROJECT_NAME} rosidl_typesupport_protobuf) + +ament_export_libraries(${PROJECT_NAME}) + +ament_index_register_resource("rosidl_typesupport_cpp") + +ament_package(CONFIG_EXTRAS "cmake/rosidl_typesupport_protobuf_cpp-extras.cmake.in") + +install( + PROGRAMS bin/rosidl_typesupport_protobuf_cpp + DESTINATION lib/rosidl_typesupport_protobuf_cpp +) + +install( + DIRECTORY cmake resource + DESTINATION share/${PROJECT_NAME} +) + +install( + DIRECTORY include/ + DESTINATION include +) + +install( + TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/bin/rosidl_typesupport_protobuf_cpp b/rosidl_typesupport_protobuf_cpp/bin/rosidl_typesupport_protobuf_cpp new file mode 100644 index 0000000..c8f50a5 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/bin/rosidl_typesupport_protobuf_cpp @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import argparse +import sys +import pathlib +import os +import rosidl_typesupport_protobuf + +from rosidl_cmake import read_generator_arguments +from rosidl_typesupport_protobuf_cpp import generate_cpp + +def main(argv=sys.argv[1:]): + parser = argparse.ArgumentParser( + description='Generate the Protobuf & C++ interfaces for Protobuf type support.', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '--generator-arguments-file', + required=True, + help='The location of the file containing the generator arguments') + + args = parser.parse_args(argv) + rosidl_typesupport_protobuf.set_namespace_delimeter("::") + rosidl_typesupport_protobuf.set_type_support_name("rosidl_typesupport_protobuf_cpp") + # Generate typesupport cpp files + rc = generate_cpp(args.generator_arguments_file) + + return rc + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp-extras.cmake.in b/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp-extras.cmake.in new file mode 100644 index 0000000..fc06bc4 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp-extras.cmake.in @@ -0,0 +1,32 @@ +# generated from +# rosidl_typesupport_protobuf_cpp/ +# rosidl_typesupport_protobuf_cpp-extras.cmake.in + +find_package(Protobuf REQUIRED) + +if(NOT Protobuf_FOUND) + message(STATUS + "Could not find Protobuf - skip rosidl_typesupport_protobuf_cpp" + ) +else() + find_package(ament_cmake_core QUIET REQUIRED) + ament_register_extension( + "rosidl_generate_idl_interfaces" + "rosidl_typesupport_protobuf_cpp" + "rosidl_typesupport_protobuf_cpp_generate_interfaces.cmake") + + set(rosidl_typesupport_protobuf_cpp_BIN + "${rosidl_typesupport_protobuf_cpp_DIR}/../../../lib/rosidl_typesupport_protobuf_cpp/rosidl_typesupport_protobuf_cpp") + normalize_path(rosidl_typesupport_protobuf_cpp_BIN + "${rosidl_typesupport_protobuf_cpp_BIN}") + + set(rosidl_typesupport_protobuf_cpp_GENERATOR_FILES + "${rosidl_typesupport_protobuf_cpp_DIR}/../../../@PYTHON_INSTALL_DIR@/rosidl_typesupport_protobuf_cpp/__init__.py") + normalize_path(rosidl_typesupport_protobuf_cpp_GENERATOR_FILES + "${rosidl_typesupport_protobuf_cpp_GENERATOR_FILES}") + + set(rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR + "${rosidl_typesupport_protobuf_cpp_DIR}/../resource") + normalize_path(rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}") +endif() diff --git a/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp_generate_interfaces.cmake b/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp_generate_interfaces.cmake new file mode 100644 index 0000000..62c4068 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/cmake/rosidl_typesupport_protobuf_cpp_generate_interfaces.cmake @@ -0,0 +1,203 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +find_package(Protobuf REQUIRED) + +find_package(rosidl_adapter_proto REQUIRED) +find_package(rosidl_typesupport_protobuf REQUIRED) + +set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_cpp/${PROJECT_NAME}") + +# Create a list of files that will be generated from each IDL file +set(_generated_files "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) + get_filename_component(_parent_folder "${_parent_folder}" NAME) + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + # Turn idl name into file names + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) + list(APPEND _generated_files + "${_output_path}/${_parent_folder}/detail/${_header_name}__type_support.cpp" + "${_output_path}/${_parent_folder}/${_header_name}__rosidl_typesupport_protobuf_cpp.hpp" + ) +endforeach() + +# Create a list of IDL files from other packages that this generator should depend on +set(_dependency_files "") +set(_dependencies "") +foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + foreach(_idl_file ${${_pkg_name}_IDL_FILES}) + # ${{_pkg_name}_DIR} is absolute path ending in 'share//cmake', so go back one + # directory for IDL files + set(_abs_idl_file "${${_pkg_name}_DIR}/../${_idl_file}") + normalize_path(_abs_idl_file "${_abs_idl_file}") + list(APPEND _dependency_files "${_abs_idl_file}") + list(APPEND _dependencies "${_pkg_name}:${_abs_idl_file}") + endforeach() +endforeach() + +# Create a list of templates and source files this generator uses, and check that they exist +set(target_dependencies + "${rosidl_typesupport_protobuf_cpp_BIN}" + ${rosidl_typesupport_protobuf_cpp_GENERATOR_FILES} + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/idl__rosidl_typesupport_protobuf_cpp.hpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/idl__type_support.cpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/msg__rosidl_typesupport_protobuf_cpp.hpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/msg__type_support.cpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/srv__rosidl_typesupport_protobuf_cpp.hpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/srv__type_support.cpp.em" + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/rosidl_typesupport_protobuf_cpp__visibility_control.h.in" + ${rosidl_generate_interfaces_ABS_IDL_FILES} + ${_dependency_files} +) +foreach(dep ${target_dependencies}) + if(NOT EXISTS "${dep}") + message(FATAL_ERROR "Target dependency '${dep}' does not exist") + endif() +endforeach() + +# Write all this to a file to work around command line length limitations on some platforms +set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_cpp__arguments.json") +rosidl_write_generator_arguments( + "${generator_arguments_file}" + PACKAGE_NAME "${PROJECT_NAME}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" + ROS_INTERFACE_DEPENDENCIES "${_dependencies}" + OUTPUT_DIR "${_output_path}" + TEMPLATE_DIR "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}" + TARGET_DEPENDENCIES ${target_dependencies} +) + +# Add a command that invokes generator at build time +add_custom_command( + OUTPUT ${_generated_files} + COMMAND ${PYTHON_EXECUTABLE} ${rosidl_typesupport_protobuf_cpp_BIN} + --generator-arguments-file "${generator_arguments_file}" + DEPENDS ${target_dependencies} + COMMENT "Generating C++ type support for Protobuf" + VERBATIM +) + +# generate header to switch between export and import for a specific package +set(_visibility_control_file +"${_output_path}/rosidl_typesupport_protobuf_cpp__visibility_control.h") +string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER) +configure_file( + "${rosidl_typesupport_protobuf_cpp_TEMPLATE_DIR}/rosidl_typesupport_protobuf_cpp__visibility_control.h.in" + "${_visibility_control_file}" + @ONLY +) + +set(_target_suffix "__rosidl_typesupport_protobuf_cpp") + +add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} SHARED + ${_generated_files} + ${rosidl_adapter_proto_GENERATED_CPP} +) + +# Change output library name if asked to +if(rosidl_generate_interfaces_LIBRARY_NAME) + set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES OUTPUT_NAME "${rosidl_generate_interfaces_LIBRARY_NAME}${_target_suffix}") +endif() + +# set C++ standard +set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES CXX_STANDARD 14 +) + +# Set flag for visibility macro +if(WIN32) + target_compile_definitions(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PRIVATE "ROSIDL_TYPESUPPORT_PROTOBUF_BUILDING_DLL" "ROSIDL_TYPESUPPORT_PROTOBUF_CPP_BUILDING_DLL__${PROJECT_NAME}") + set (Protobuf_USE_STATIC_LIBS TRUE) +endif() + +# Set compiler flags +if(NOT WIN32) + set(_target_compile_flags "-Wall -Wextra -Wpedantic") +else() + set(_target_compile_flags "/W4") +endif() +string(REPLACE ";" " " _target_compile_flags "${_target_compile_flags}") +set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PROPERTIES COMPILE_FLAGS "${_target_compile_flags}" +) + +# Include headers from other generators +target_include_directories(${rosidl_generate_interfaces_TARGET}${_target_suffix} + PUBLIC + ${_output_path} + ${Protobuf_INCLUDE_DIR} + ${rosidl_adapter_proto_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp + ${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_protobuf_cpp +) + +ament_target_dependencies(${rosidl_generate_interfaces_TARGET}${_target_suffix} + rmw + rosidl_typesupport_protobuf + rosidl_typesupport_protobuf_cpp + rosidl_typesupport_interface +) + +# Depend on dependencies +foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) + ament_target_dependencies(${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${_pkg_name}) + target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${${_pkg_name}_LIBRARIES${_target_suffix}}) +endforeach() + +target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} ${Protobuf_LIBRARY}) + +# Make top level generation target depend on this library +add_dependencies( + ${rosidl_generate_interfaces_TARGET} + ${rosidl_generate_interfaces_TARGET}${_target_suffix} +) + +# Make this library depend on target created by rosidl_generator_cpp +add_dependencies( + ${rosidl_generate_interfaces_TARGET}${_target_suffix} + ${rosidl_generate_interfaces_TARGET}__cpp +) + +if(NOT rosidl_generate_interfaces_SKIP_INSTALL) + install( + DIRECTORY "${_output_path}/" + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.cpp" EXCLUDE + ) + + if(NOT _generated_files STREQUAL "") + ament_export_include_directories(include) + endif() + + install( + TARGETS ${rosidl_generate_interfaces_TARGET}${_target_suffix} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + + rosidl_export_typesupport_libraries(${_target_suffix} + ${rosidl_generate_interfaces_TARGET}${_target_suffix}) + + ament_export_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix}) +endif() \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/identifier.hpp b/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/identifier.hpp new file mode 100644 index 0000000..083c23c --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/identifier.hpp @@ -0,0 +1,30 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +namespace rosidl_typesupport_protobuf_cpp +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_IMPORT +extern const char *identifier; + +} // namespace rosidl_typesupport_protobuf_cpp diff --git a/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp b/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp new file mode 100644 index 0000000..e51b756 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/include/rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp @@ -0,0 +1,35 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#pragma once + +#include + +#include + +namespace rosidl_typesupport_protobuf_cpp +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +void write_to_string(const std::u16string &u16str, std::string &str); + +ROSIDL_TYPESUPPORT_PROTOBUF_PUBLIC +void write_to_u16string(const std::string &str, std::u16string &u16str); + +} \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/package.xml b/rosidl_typesupport_protobuf_cpp/package.xml new file mode 100644 index 0000000..5097a8f --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/package.xml @@ -0,0 +1,34 @@ + + + + rosidl_typesupport_protobuf_cpp + 0.0.1 + Generate the C++ interfaces for Protobuf serialization. + Aleksandar Brakmić + Apache License 2.0 + + ament_cmake + rosidl_cmake + rosidl_generator_cpp + rosidl_adapter_proto + rosidl_typesupport_protobuf + + ament_cmake + rosidl_cmake + rosidl_generator_cpp + rosidl_adapter_proto + rosidl_typesupport_protobuf + + rmw + + rosidl_parser + rosidl_adapter_proto + rosidl_typesupport_interface + rosidl_typesupport_protobuf + + rosidl_typesupport_cpp_packages + + + ament_cmake + + diff --git a/rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em b/rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em new file mode 100644 index 0000000..7dedcec --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em @@ -0,0 +1,92 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +// generated from rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __rosidl_typesupport_protobuf_cpp.hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +#pragma once + +@{ + +include_directives = set() + +####################################################################### +# Handle message +####################################################################### +from rosidl_parser.definition import Message +for message in content.get_elements_of_type(Message): + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=message, + include_directives=include_directives) + +####################################################################### +# Handle service +####################################################################### +from rosidl_parser.definition import Service +for service in content.get_elements_of_type(Service): + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, + interface_path=interface_path, + service=service, + include_directives=include_directives) + +####################################################################### +# Handle action +####################################################################### +from rosidl_parser.definition import Action +for action in content.get_elements_of_type(Action): + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) + TEMPLATE( + 'srv__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) + TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em b/rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em new file mode 100644 index 0000000..f1f18d3 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em @@ -0,0 +1,118 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +// generated from rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __type_support.cpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@{ +from rosidl_typesupport_protobuf import typesupport_header, ros_message_header +from rosidl_cmake import convert_camel_case_to_lower_case_underscore + +include_directives = set() +forward_declared_types = set() + +system_header_files = [] +header_files = [ + typesupport_header(package_name, interface_path), + ros_message_header(package_name, interface_path) +] +}@ + +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ +####################################################################### +# Handle message +####################################################################### +from rosidl_parser.definition import Message +for message in content.get_elements_of_type(Message): + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + +####################################################################### +# Handle service +####################################################################### +from rosidl_parser.definition import Service +for service in content.get_elements_of_type(Service): + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + service=service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + +####################################################################### +# Handle action +####################################################################### +from rosidl_parser.definition import Action +for action in content.get_elements_of_type(Action): + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives, + forward_declared_types = forward_declared_types) + TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/resource/msg__rosidl_typesupport_protobuf_cpp.hpp.em b/rosidl_typesupport_protobuf_cpp/resource/msg__rosidl_typesupport_protobuf_cpp.hpp.em new file mode 100644 index 0000000..c707f80 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/msg__rosidl_typesupport_protobuf_cpp.hpp.em @@ -0,0 +1,83 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_typesupport_protobuf import * + +system_header_files = [ + "string" +] + +header_files = [ + ros_message_header(package_name, interface_path), + visibility_control_header(package_name), + 'rosidl_typesupport_protobuf/rosidl_generator_c_pkg_adapter.hpp', + 'rosidl_typesupport_interface/macros.h', + protobuf_message_header(package_name, interface_path) +] + +ros_type_ns = ros_type_namespace(package_name, interface_path) +ros_type_name = ros_type_name(message) +ros_type = ros_type(package_name, interface_path, message) +proto_type = protobuf_type(package_name, interface_path, message) + +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@[for ns in message.structure.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[end for]@ +namespace typesupport_protobuf_cpp +{ + +bool +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +convert_to_proto(const @(ros_type) &ros_msg, @(proto_type) &pb_msg); + +bool +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +convert_to_ros(const @(proto_type) &pb_msg, @(ros_type) &ros_msg); + +} // namespace typesupport_protobuf_cpp +@[ for ns in reversed(message.structure.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +#ifdef __cplusplus +extern "C" +{ +#endif + +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +const rosidl_message_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(ros_type_ns.replace("::", ", ")), @(ros_type_name))(); + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em b/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em new file mode 100644 index 0000000..a58c86a --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/msg__type_support.cpp.em @@ -0,0 +1,239 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em +@{ +import rosidl_parser.parser as rosidl +from rosidl_parser.definition import * +from rosidl_typesupport_protobuf import * + +ros_type_ns = ros_type_namespace(package_name, interface_path) +ros_type_name = ros_type_name(message) +ros_type = ros_type(package_name=package_name, interface_path=interface_path, message=message) +proto_type = protobuf_type(package_name=package_name, interface_path=interface_path, message=message) + +system_header_files = [ + 'string', + 'algorithm' +] + +header_files = [ + 'rosidl_typesupport_cpp/message_type_support.hpp', + 'rosidl_typesupport_protobuf_cpp/identifier.hpp', + 'rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp', + 'rosidl_typesupport_protobuf/message_type_support.hpp', + 'rosidl_typesupport_protobuf/message_type_support_decl.hpp', + 'rosidl_typesupport_protobuf/proto_descriptor_helper.hpp', + visibility_control_header(package_name), + protobuf_message_header(package_name, interface_path) +] +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'tmpl_forward_declarations.em', + message=message, + forward_declared_types=forward_declared_types +) +}@ +@[ for ns in message.structure.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[ end for]@ +namespace typesupport_protobuf_cpp +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +bool convert_to_proto(const @(ros_type) &ros_msg, @(proto_type) &pb_msg) +{ +@[for member in message.structure.members]@ + // Member: @(member.name) +@[ if isinstance(member.type, AbstractNestedType)]@ +@[ if isinstance(member.type.value_type, BasicType) or isinstance(member.type.value_type, AbstractString)]@ + *pb_msg.mutable_@(member.name)() = { ros_msg.@(member.name).begin(), ros_msg.@(member.name).end() }; +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + for(auto &member : ros_msg.@(member.name)) + { + ::rosidl_typesupport_protobuf_cpp::write_to_string(member, *pb_msg.add_@(member.name)()); + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + for(auto &member : ros_msg.@(member.name)) + { + auto ptr{pb_msg.add_@(member.name)()}; + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_cpp::convert_to_proto(member, *ptr); + } +@[ end if]@ +@[ elif isinstance(member.type, BasicType) or isinstance(member.type, AbstractString)]@ + pb_msg.set_@(member.name)(ros_msg.@(member.name)); +@[ elif isinstance(member.type, BasicType) or isinstance(member.type, AbstractWString)]@ + ::rosidl_typesupport_protobuf_cpp::write_to_string(ros_msg.@(member.name), *pb_msg.mutable_@(member.name)()); +@[ elif isinstance(member.type, NamespacedType)]@ + @("::" + "::".join(member.type.namespaces))::typesupport_protobuf_cpp::convert_to_proto(ros_msg.@(member.name), *pb_msg.mutable_@(member.name)()); +@[ end if]@ +@[end for]@ + + return true; +} + +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +bool convert_to_ros(const @(proto_type) &pb_msg, @(ros_type) &ros_msg) +{ +@[for member in message.structure.members]@ + // Member: @(member.name) +@[ if isinstance(member.type, AbstractNestedType)]@ +@[ if isinstance(member.type.value_type, BasicType) or isinstance(member.type.value_type, AbstractString)]@ +@[ if isinstance(member.type, Array)]@ + std::copy_n(pb_msg.@(member.name)().begin(), ros_msg.@(member.name).size(), ros_msg.@(member.name).begin()); +@[ else]@ +@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename == BOOLEAN_TYPE]@ + for(auto val : pb_msg.@(member.name)()) + { + ros_msg.@(member.name).push_back(val); + } +@[ else]@ + ros_msg.@(member.name) = { pb_msg.@(member.name)().begin(), pb_msg.@(member.name)().end() }; +@[ end if]@ +@[ end if]@ +@[ elif isinstance(member.type.value_type, AbstractWString)]@ + { +@[ if not isinstance(member.type, Array)]@ + auto size{pb_msg.@(member.name)_size()}; + ros_msg.@(member.name).resize(size); + +@[ end if]@ + auto& data{pb_msg.@(member.name)()}; + auto& ros_data{ros_msg.@(member.name)}; + int i{0}; + for(auto &str : data) + { + ::rosidl_typesupport_protobuf_cpp::write_to_u16string(str, ros_data[i]); + i++; + } + } +@[ elif isinstance(member.type.value_type, NamespacedType)]@ + { +@[ if not isinstance(member.type, Array)]@ + auto size{pb_msg.@(member.name)_size()}; + ros_msg.@(member.name).resize(size); + +@[ end if]@ + auto& data{pb_msg.@(member.name)()}; + auto& ros_data{ros_msg.@(member.name)}; + int i{0}; + for(auto &member : data) + { + //auto ptr = pb_msg.add_@(member.name)(); + @("::" + "::".join(member.type.value_type.namespaces))::typesupport_protobuf_cpp::convert_to_ros(member, ros_data[i]); + i++; + } + } +@[ end if]@ +@[ elif isinstance(member.type, BasicType) or isinstance(member.type, AbstractString)]@ + ros_msg.@(member.name) = pb_msg.@(member.name)(); +@[ elif isinstance(member.type, BasicType) or isinstance(member.type, AbstractWString)]@ + ::rosidl_typesupport_protobuf_cpp::write_to_u16string(pb_msg.@(member.name)(), ros_msg.@(member.name)); +@[ elif isinstance(member.type, NamespacedType)]@ + @("::" + "::".join(member.type.namespaces))::typesupport_protobuf_cpp::convert_to_ros(pb_msg.@(member.name)(), ros_msg.@(member.name)); +@[ end if]@ +@[end for]@ + + return true; +} + +static bool _@(ros_type_name)__serialize(const void *untyped_ros_msg, std::string &serialized_msg) +{ + @(proto_type) pb_msg{}; + auto ros_msg{static_cast(untyped_ros_msg)}; + + convert_to_proto(*ros_msg, pb_msg); + return pb_msg.SerializeToString(&serialized_msg); +} + +static bool _@(ros_type_name)__deserialize(void *untyped_ros_msg, const void *serialized_msg, size_t size) +{ + @(proto_type) pb_msg{}; + auto ros_msg{static_cast<@(ros_type) *>(untyped_ros_msg)}; + + pb_msg.ParseFromArray(serialized_msg, size); + return convert_to_ros(pb_msg, *ros_msg); +} + +static std::string _@(ros_type_name)__get_descriptor() +{ + return ""; + return GetProtoMessageDescription<@(proto_type)>(); +} + +@{type_support_name = "_" + ros_type_name + "__type_support"}@ +static rosidl_typesupport_protobuf::message_type_support_t @(type_support_name) = { + "@(ros_type_ns)", + "@(ros_type_name)", + _@(ros_type_name)__serialize, + _@(ros_type_name)__deserialize, + _@(ros_type_name)__get_descriptor +}; + +@{ +handle_name = "_" + ros_type_name + "__handle" +namespaced_handle_name = "::".join([ros_type_ns, "typesupport_protobuf_cpp", handle_name]) +}@ +static rosidl_message_type_support_t @(handle_name) = { + rosidl_typesupport_protobuf_cpp::identifier, + &@(type_support_name), + get_message_typesupport_handle_function +}; + +} // namespace typesupport_protobuf_cpp +@[ for ns in reversed(message.structure.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +namespace rosidl_typesupport_protobuf +{ + +template<> +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@(package_name) +const rosidl_message_type_support_t *get_message_type_support_handle<@(ros_type)>() +{ + return &@(namespaced_handle_name); +} + +} // namespace rosidl_typesupport_protobuf + +#ifdef __cplusplus +extern "C" +{ +#endif + +const rosidl_message_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(ros_type_ns.replace("::", ", ")), @(ros_type_name))() { + return &@(namespaced_handle_name); +} + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_cpp/resource/rosidl_typesupport_protobuf_cpp__visibility_control.h.in b/rosidl_typesupport_protobuf_cpp/resource/rosidl_typesupport_protobuf_cpp__visibility_control.h.in new file mode 100644 index 0000000..f9b08dd --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/rosidl_typesupport_protobuf_cpp__visibility_control.h.in @@ -0,0 +1,42 @@ +// generated from +// rosidl_typesupport_protobuf/rosidl_typesupport_protobuf_cpp/resource/visibility_control.h.in +// generated code does not contain a copyright notice +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef __GNUC__ + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@PROJECT_NAME@ __attribute__ ((dllexport)) + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_IMPORT__@PROJECT_NAME@ __attribute__ ((dllimport)) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@PROJECT_NAME@ __declspec(dllexport) + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_IMPORT__@PROJECT_NAME@ __declspec(dllimport) + #endif + #ifdef ROSIDL_TYPESUPPORT_PROTOBUF_CPP_BUILDING_DLL__@PROJECT_NAME@ + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@PROJECT_NAME@ ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@PROJECT_NAME@ + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@PROJECT_NAME@ ROSIDL_TYPESUPPORT_PROTOBUF_CPP_IMPORT__@PROJECT_NAME@ + #endif + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_LOCAL__@PROJECT_NAME@ +#else + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_IMPORT__@PROJECT_NAME@ + #if __GNUC__ >= 4 + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@PROJECT_NAME@ __attribute__ ((visibility("default"))) + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_LOCAL__@PROJECT_NAME@ __attribute__ ((visibility("hidden"))) + #else + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@PROJECT_NAME@ + #define ROSIDL_TYPESUPPORT_PROTOBUF_CPP_LOCAL__@PROJECT_NAME@ + #endif +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/resource/srv__rosidl_typesupport_protobuf_cpp.hpp.em b/rosidl_typesupport_protobuf_cpp/resource/srv__rosidl_typesupport_protobuf_cpp.hpp.em new file mode 100644 index 0000000..52b6a1f --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/srv__rosidl_typesupport_protobuf_cpp.hpp.em @@ -0,0 +1,47 @@ +@# Included from rosidl_typesupport_protobuf_cpp/resource/idl__rosidl_typesupport_protobuf_cpp.hpp.em +@{ +system_header_files = [] +header_files = [ + 'rosidl_typesupport_cpp/service_type_support.hpp', + 'rosidl_typesupport_interface/macros.h' +] +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files=system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_protobuf_cpp.hpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.response_message, + include_directives=include_directives) +}@ + +#ifdef __cplusplus +extern "C" +{ +#endif + +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_PUBLIC__@(package_name) +const rosidl_service_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts) + [service.namespaced_type.name])))(); + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_cpp/resource/srv__type_support.cpp.em b/rosidl_typesupport_protobuf_cpp/resource/srv__type_support.cpp.em new file mode 100644 index 0000000..e555c0b --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/srv__type_support.cpp.em @@ -0,0 +1,115 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@# Included from rosidl_typesupport_protobuf_cpp/resource/idl__type_support.cpp.em +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_typesupport_protobuf import ros_service_name, ros_service_namespace, ros_service_type + +system_header_files = [] +header_files = [ + 'rosidl_typesupport_protobuf_cpp/identifier.hpp', + 'rosidl_typesupport_protobuf/service_type_support.hpp', + 'rosidl_typesupport_protobuf/service_type_support_decl.hpp' +] + +service_name = ros_service_name(service) +service_namespace = ros_service_namespace(package_name, interface_path) +service_type = ros_service_type(package_name, interface_path, service) + +}@ +@{ +TEMPLATE( + 'tmpl_include_directories.em', + header_files=header_files, + system_header_files = system_header_files, + include_directives=include_directives +) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.request_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, + interface_path=interface_path, + message=service.response_message, + include_directives=include_directives, + forward_declared_types = forward_declared_types) +}@ + +@[for ns in service.namespaced_type.namespaces]@ +namespace @(ns) +{ +@[end for]@ +namespace typesupport_protobuf_cpp +{ + +static rosidl_typesupport_protobuf::service_type_support_t _@(service_name)__callbacks = { + "@(service_namespace)", + "@(service_name)", + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name)_Request)(), + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name)_Response)(), +}; + +static rosidl_service_type_support_t _@(service.namespaced_type.name)__handle = { + rosidl_typesupport_protobuf_cpp::identifier, + &_@(service_name)__callbacks, + get_service_typesupport_handle_function, +}; + +} // namespace typesupport_protobuf_cpp +@[for ns in reversed(service.namespaced_type.namespaces)]@ +} // namespace @(ns) +@[end for]@ + +namespace rosidl_typesupport_protobuf +{ + +template<> +ROSIDL_TYPESUPPORT_PROTOBUF_CPP_EXPORT__@(package_name) +const rosidl_service_type_support_t * +get_service_type_support_handle<@(service_type)>() +{ + return &@(service_namespace)::typesupport_protobuf_cpp::_@(service_name)__handle; +} + +} // namespace rosidl_typesupport_protobuf + +#ifdef __cplusplus +extern "C" +{ +#endif + +const rosidl_service_type_support_t * +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_protobuf_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.namespaced_type.name))() { + return &@(service_namespace)::typesupport_protobuf_cpp::_@(service_name)__handle; +} + +#ifdef __cplusplus +} +#endif diff --git a/rosidl_typesupport_protobuf_cpp/resource/tmpl_forward_declarations.em b/rosidl_typesupport_protobuf_cpp/resource/tmpl_forward_declarations.em new file mode 100644 index 0000000..3fe7784 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/tmpl_forward_declarations.em @@ -0,0 +1,73 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +from rosidl_parser.definition import * +from rosidl_typesupport_protobuf import PROTO_PACKAGE_POSTFIX, ros_type_from_namespaced_type, protobuf_type_from_namespaced_type + +def isNamespacedType(type_): + from rosidl_parser.definition import NamespacedType + return isinstance(type_, NamespacedType) + +def isNamespacedArrayType(type_): + from rosidl_parser.definition import AbstractNestedType + from rosidl_parser.definition import NamespacedType + return isinstance(type_, AbstractNestedType) and isinstance(type_.value_type, NamespacedType) + +def isTypeAlreadyDeclared(type_, fw_declared_types): + from rosidl_typesupport_protobuf import ros_type_from_namespaced_type + return ros_type_from_namespaced_type(type_) in fw_declared_types + +def registerDeclaredType(type_, fw_declared_types): + from rosidl_typesupport_protobuf import ros_type_from_namespaced_type + fw_declared_types.add(ros_type_from_namespaced_type(type_)) + +types_to_declare = list() +for member in message.structure.members: + if isNamespacedType(member.type) and not isTypeAlreadyDeclared(member.type, forward_declared_types): + types_to_declare.append(member.type) + registerDeclaredType(member.type, forward_declared_types) + elif isNamespacedArrayType(member.type) and not isTypeAlreadyDeclared(member.type.value_type, forward_declared_types): + types_to_declare.append(member.type.value_type) + registerDeclaredType(member.type.value_type, forward_declared_types) +}@ +@[if len(types_to_declare) > 0]@ +// forward declaration of message dependencies and their conversion functions +@[end if]@ +@[for type_ in types_to_declare]@ +@{ +ros_type = ros_type_from_namespaced_type(type_) +proto_type = protobuf_type_from_namespaced_type(type_) +}@ +@[ for ns in type_.namespaces]@ +namespace @(ns) +{ +@[ end for]@ +namespace typesupport_protobuf_cpp +{ + +bool convert_to_proto(const @(ros_type)&, @(proto_type)&); +bool convert_to_ros(const @(proto_type)&, @(ros_type)&); + +} // namespace typesupport_protobuf_cpp +@[ for ns in reversed(type_.namespaces)]@ +} // namespace @(ns) +@[ end for]@ + +@[end for]@ diff --git a/rosidl_typesupport_protobuf_cpp/resource/tmpl_include_directories.em b/rosidl_typesupport_protobuf_cpp/resource/tmpl_include_directories.em new file mode 100644 index 0000000..fe7a311 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/resource/tmpl_include_directories.em @@ -0,0 +1,47 @@ +@{ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= +}@ +@{ +def is_protobuf_header(header_file): + header_file.endswith(".pb.h") +} +@[for header_file in system_header_files]@ +@[ if header_file not in include_directives]@ +@{include_directives.add(header_file)}@ +#include <@(header_file)> +@[ end if]@ +@[end for]@ + +@[for header_file in header_files]@ +@[ if header_file not in include_directives]@ +@{include_directives.add(header_file)}@ +@[ if is_protobuf_header(header_file)]@ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127 4146 4800) +#endif +#include "@(header_file)" +#ifdef _MSC_VER +#pragma warning(pop) +#endif +@[ else]@ +#include "@(header_file)" +@[ end if]@ +@[ end if]@ +@[end for]@ \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/rosidl_typesupport_protobuf_cpp/__init__.py b/rosidl_typesupport_protobuf_cpp/rosidl_typesupport_protobuf_cpp/__init__.py new file mode 100644 index 0000000..644abe8 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/rosidl_typesupport_protobuf_cpp/__init__.py @@ -0,0 +1,29 @@ +# ================================= Apache 2.0 ================================= +# +# Copyright (C) 2021 Continental +# +# 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. +# +# ================================= Apache 2.0 ================================= + +import rosidl_typesupport_protobuf + +from rosidl_cmake import generate_files, convert_camel_case_to_lower_case_underscore + +def generate_cpp(generator_arguments_file): + mapping = { + "idl__rosidl_typesupport_protobuf_cpp.hpp.em": "%s__rosidl_typesupport_protobuf_cpp.hpp", + "idl__type_support.cpp.em": "detail/%s__type_support.cpp", + } + generate_files(generator_arguments_file, mapping) + return 0 \ No newline at end of file diff --git a/rosidl_typesupport_protobuf_cpp/src/identifier.cpp b/rosidl_typesupport_protobuf_cpp/src/identifier.cpp new file mode 100644 index 0000000..29754be --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/src/identifier.cpp @@ -0,0 +1,28 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#include + +namespace rosidl_typesupport_protobuf_cpp +{ + +ROSIDL_TYPESUPPORT_PROTOBUF_EXPORT +const char *identifier = "rosidl_typesupport_protobuf_cpp"; + +} // namespace rosidl_typesupport_protobuf_cpp diff --git a/rosidl_typesupport_protobuf_cpp/src/wstring_conversion.cpp b/rosidl_typesupport_protobuf_cpp/src/wstring_conversion.cpp new file mode 100644 index 0000000..0dc9eb6 --- /dev/null +++ b/rosidl_typesupport_protobuf_cpp/src/wstring_conversion.cpp @@ -0,0 +1,42 @@ +/* ================================ Apache 2.0 ================================= + * + * Copyright (C) 2021 Continental + * + * 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. + * + * ================================ Apache 2.0 ================================= + */ + +#include "rosidl_typesupport_protobuf_cpp/wstring_conversion.hpp" + +#include + +namespace rosidl_typesupport_protobuf_cpp +{ + +void write_to_string(const std::u16string &u16str, std::string &str) +{ + auto data_size = u16str.size() * sizeof(std::u16string::value_type); + str.resize(data_size); + auto str_start = &str[0]; + std::memcpy(str_start, u16str.data(), data_size); +} + +void write_to_u16string(const std::string &str, std::u16string &u16str) +{ + u16str.resize(str.size() / sizeof(std::u16string::value_type)); + auto wstr_start = &u16str[0]; + std::memcpy(wstr_start, str.data(), str.size()); +} + +} \ No newline at end of file