diff --git a/README.md b/README.md index 963c47e54..ca68c0d1d 100644 --- a/README.md +++ b/README.md @@ -19,27 +19,31 @@ What's missing? --------------- Lots of things! -- Nested types - An ament build type for Cargo. The current examples use CMake to install and build the binaries... and it's really ugly. - Component nodes - Clients and services - Tests - Documentation +### Limitations + +- messages are deep-copied and this can be terribly inefficient for big messages like images; the current solution leverages C typesupport implementations and might benefits from a direct serialization/deserialization +- the current solution for crates export with CMake is not very robust +- `rclrs` interface is very limited for now and might not be so much idiomatic yet, any help and suggestion on the interface would be greatly appreciated +- due to the current ROS2 support of non-default clients, packages containing definitions of messages used in Rust crates must be present in the current workspace; otherwise message crates generation won't be triggered + Sounds great, how can I try this out? ------------------------------------- The following steps show how to build the examples: ``` -mkdir -p ~/ros2_rust_ws/src -cd ~/ros2_rust_ws -wget https://raw.githubusercontent.com/esteve/ros2_rust/master/ros2_rust.repos -vcs import ~/ros2_rust_ws/src < ros2_rust.repos -cd ~/ros2_rust_ws/src/ros2/rosidl_typesupport -patch -p1 < ../../ros2_rust/ros2_rust/rosidl_typesupport_ros2_rust.patch -cd ~/ros2_rust_ws -src/ament/ament_tools/scripts/ament.py build --isolated +mkdir -p ros2_rust_ws/src +cd ros2_rust_ws +git clone https://github.com/esteve/ros2_rust.git src/ros2_rust +vcs import src < ./src/ros2_rust/ros2_rust.repos +source /opt/ros/crystal/setup.sh +colcon build ``` Now you can just run a bunch of examples. @@ -49,7 +53,7 @@ Now you can just run a bunch of examples. Publisher: ``` -. ~/ros2_rust_ws/install_isolated/local_setup.sh +. ./install/setup.sh ros2 run rclrs_examples rclrs_publisher ``` @@ -57,7 +61,7 @@ ros2 run rclrs_examples rclrs_publisher Subscriber: ``` -. ~/ros2_rust_ws/install_isolated/local_setup.sh +. ./install/setup.sh ros2 run rclrs_examples rclrs_subscriber ``` diff --git a/rclrs/CMakeLists.txt b/rclrs/CMakeLists.txt index 5adb6ce80..98f1be6a4 100644 --- a/rclrs/CMakeLists.txt +++ b/rclrs/CMakeLists.txt @@ -1,72 +1,27 @@ cmake_minimum_required(VERSION 3.5) +project(rclrs NONE) -project(rclrs C) - -find_package(ament_cmake_ros REQUIRED) +find_package(ament_cmake REQUIRED) find_package(ament_cmake_export_crates REQUIRED) -find_package(rcl REQUIRED) -find_package(rcl_interfaces REQUIRED) find_package(rclrs_common REQUIRED) -find_package(rmw REQUIRED) -find_package(rmw_implementation REQUIRED) -find_package(rmw_implementation_cmake REQUIRED) -find_package(rosidl_generator_c REQUIRED) - -set(${PROJECT_NAME}_SRCS - "src/c/rclrs.c" -) - -set(CMAKE_C_STANDARD 11) -add_library(${PROJECT_NAME} - ${${PROJECT_NAME}_SRCS}) +foreach(_crate_dependency ${rclrs_common_CRATES}) + set(_crates_dependencies "${_crates_dependencies}\n[dependencies.rclrs_common]\npath = '${_crate_dependency}'\n") +endforeach() -ament_target_dependencies(${PROJECT_NAME} - "builtin_interfaces" - "rcl" - "rosidl_generator_c" - "rosidl_typesupport_c") +file(COPY "${CMAKE_SOURCE_DIR}/Cargo.toml" DESTINATION "${CMAKE_BINARY_DIR}/") +file(APPEND "${CMAKE_BINARY_DIR}/Cargo.toml" "${_crates_dependencies}") install( - TARGETS ${PROJECT_NAME} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin -) - -configure_file( - "src/rust/Cargo.toml.in" - "share/${PROJECT_NAME}/rust/Cargo.toml" - @ONLY -) - -install( - FILES "${CMAKE_CURRENT_BINARY_DIR}/share/${PROJECT_NAME}/rust/Cargo.toml" + FILES ${CMAKE_BINARY_DIR}/Cargo.toml build.rs src/rcl_wrapper.h DESTINATION share/${PROJECT_NAME}/rust/ ) install( - DIRECTORY src/rust/src/ + DIRECTORY src/ DESTINATION share/${PROJECT_NAME}/rust/src ) -install( - DIRECTORY src/rust/src/ - DESTINATION share/${PROJECT_NAME}/rust/src -) - -ament_export_dependencies(ament_cmake_ros) -ament_export_dependencies(builtin_interfaces) -ament_export_dependencies(rcl) -ament_export_dependencies(rosidl_generator_c) -ament_export_dependencies(rosidl_typesupport_c) - -ament_export_libraries(${PROJECT_NAME}) -ament_export_crates("share/${PROJECT_NAME}/rust/") - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - ament_lint_auto_find_test_dependencies() -endif() +ament_export_crates("share/${PROJECT_NAME}/rust") -ament_package() +ament_package() \ No newline at end of file diff --git a/rclrs/src/rust/Cargo.toml.in b/rclrs/Cargo.toml similarity index 54% rename from rclrs/src/rust/Cargo.toml.in rename to rclrs/Cargo.toml index 4659fbc94..d4e56345f 100644 --- a/rclrs/src/rust/Cargo.toml.in +++ b/rclrs/Cargo.toml @@ -2,7 +2,11 @@ name = "rclrs" version = "0.1.0" authors = ["Esteve Fernandez "] +edition = "2018" [dependencies] -libc = "0.2" -rclrs_common = { path = '@rclrs_common_CRATES@' } +libc = "0.2.43" +failure = "0.1.5" + +[build-dependencies] +bindgen = "0.45.0" \ No newline at end of file diff --git a/rclrs/build.rs b/rclrs/build.rs new file mode 100644 index 000000000..cb8ccb09c --- /dev/null +++ b/rclrs/build.rs @@ -0,0 +1,34 @@ +extern crate bindgen; + +use std::env; +use std::path::PathBuf; + +fn main() { + let mut builder = bindgen::Builder::default() + .header("src/rcl_wrapper.h") + .derive_copy(false) + .default_enum_style(bindgen::EnumVariation::Rust); + + let ament_prefix_var_name = "AMENT_PREFIX_PATH"; + let ament_prefix_var = env::var(ament_prefix_var_name); + + if let Ok(ament_prefix_paths) = ament_prefix_var { + for ament_prefix_path in ament_prefix_paths.split(":") { + builder = builder.clang_arg(format!("-I{}/include", ament_prefix_path)); + println!("cargo:rustc-link-search=native={}/lib", ament_prefix_path); + } + } + + println!("cargo:rustc-link-lib=dylib=rcl"); + println!("cargo:rustc-link-lib=dylib=rcl_logging_noop"); + println!("cargo:rustc-link-lib=dylib=rcutils"); + println!("cargo:rustc-link-lib=dylib=rmw"); + println!("cargo:rustc-link-lib=dylib=rmw_implementation"); + + let bindings = builder.generate().expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("rcl_bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/rclrs/package.xml b/rclrs/package.xml index a766b8d2d..55e232750 100644 --- a/rclrs/package.xml +++ b/rclrs/package.xml @@ -7,49 +7,15 @@ Esteve Fernandez Apache License 2.0 - ament_cmake_ros + ament_cmake ament_cmake_export_crates - rclrs_common - - ament_cmake_ros - ament_cmake_export_crates - rclrs_common builtin_interfaces - rcl_interfaces rcl - rmw_implementation_cmake - rmw - rosidl_generator_c - rosidl_typesupport_c - rosidl_typesupport_rs - builtin_interfaces - rcl_interfaces - rmw - rosidl_generator_c - rosidl_generator_rs - rosidl_typesupport_c - - builtin_interfaces - rcl_interfaces - rcl - rmw_implementation_cmake - rmw_implementation - rosidl_generator_c - rosidl_parser - - ament_lint_auto - ament_lint_common - builtin_interfaces - rcl_interfaces - rclrs_common - rmw_implementation_cmake - rmw - rosidl_generator_c - rosidl_generator_rs - std_msgs + rcl_interfaces + rclrs_common ament_cmake - + \ No newline at end of file diff --git a/rclrs/src/c/rclrs.c b/rclrs/src/c/rclrs.c deleted file mode 100644 index 7209789fa..000000000 --- a/rclrs/src/c/rclrs.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include - -#include -#include - -bool rclrs_native_ok() { return rcl_ok(); } - -int32_t rclrs_native_init() { - // TODO(esteve): parse args - return rcl_init(0, NULL, rcl_get_default_allocator()); -} - -const char *rclrs_native_get_error_string_safe() { - return rcl_get_error_string_safe(); -} - -void rclrs_native_reset_error() { rcl_reset_error(); } - -int32_t rclrs_native_create_node_handle(uintptr_t *node_handle, - const char *name, - const char *namespace) { - rcl_node_t *node = (rcl_node_t *)malloc(sizeof(rcl_node_t)); - *node = rcl_get_zero_initialized_node(); - - rcl_node_options_t default_options = rcl_node_get_default_options(); - rcl_ret_t ret = rcl_node_init(node, name, namespace, &default_options); - *node_handle = (uintptr_t)node; - return ret; -} - -int32_t rclrs_native_create_publisher_handle( - uintptr_t *publisher_handle, uintptr_t node_handle, - uintptr_t type_support_handle, const char *topic, - uint8_t qos_policy_history, size_t depth, uint8_t qos_policy_reliability, - uint8_t qos_policy_durability, bool avoid_ros_namespace_conventions) { - rcl_node_t *node = (rcl_node_t *)node_handle; - - rosidl_message_type_support_t *type_support = - (rosidl_message_type_support_t *)type_support_handle; - - rcl_publisher_t *publisher = - (rcl_publisher_t *)malloc(sizeof(rcl_publisher_t)); - *publisher = rcl_get_zero_initialized_publisher(); - rcl_publisher_options_t publisher_ops = rcl_publisher_get_default_options(); - - rmw_qos_profile_t qos_profile = { - qos_policy_history, depth, qos_policy_reliability, qos_policy_durability, - avoid_ros_namespace_conventions}; - - publisher_ops.qos = qos_profile; - - rcl_ret_t ret = - rcl_publisher_init(publisher, node, type_support, topic, &publisher_ops); - *publisher_handle = (uintptr_t)publisher; - return ret; -} - -int32_t rclrs_native_publish(uintptr_t publisher_handle, - uintptr_t message_handle) { - rcl_publisher_t *publisher = (rcl_publisher_t *)publisher_handle; - - void *raw_ros_message = (void *)message_handle; - - rcl_ret_t ret = rcl_publish(publisher, raw_ros_message); - - return ret; -} - -uintptr_t rclrs_native_get_zero_initialized_wait_set() { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)malloc(sizeof(rcl_wait_set_t)); - *wait_set = rcl_get_zero_initialized_wait_set(); - return (uintptr_t)wait_set; -} - -void rclrs_native_destroy_wait_set(uintptr_t wait_set_handle) { - free((rcl_wait_set_t *)wait_set_handle); -} - -int32_t rclrs_native_wait_set_init(uintptr_t wait_set_handle, - size_t number_of_subscriptions, - size_t number_of_guard_conditions, - size_t number_of_timers, - size_t number_of_clients, - size_t number_of_services) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - - rcl_ret_t ret = rcl_wait_set_init( - wait_set, number_of_subscriptions, number_of_guard_conditions, - number_of_timers, number_of_clients, number_of_services, - rcl_get_default_allocator()); - - return ret; -} - -int32_t rclrs_native_wait_set_clear_subscriptions(uintptr_t wait_set_handle) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - rcl_ret_t ret = rcl_wait_set_clear_subscriptions(wait_set); - - return ret; -} - -int32_t rclrs_native_wait_set_clear_services(uintptr_t wait_set_handle) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - rcl_ret_t ret = rcl_wait_set_clear_services(wait_set); - - return ret; -} - -int32_t rclrs_native_wait_set_clear_clients(uintptr_t wait_set_handle) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - rcl_ret_t ret = rcl_wait_set_clear_clients(wait_set); - - return ret; -} - -int32_t rclrs_native_wait_set_add_subscription(uintptr_t wait_set_handle, - uintptr_t subscription_handle) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - rcl_subscription_t *subscription = (rcl_subscription_t *)subscription_handle; - rcl_ret_t ret = rcl_wait_set_add_subscription(wait_set, subscription); - - return ret; -} - -int32_t rclrs_native_wait(uintptr_t wait_set_handle, int64_t timeout) { - rcl_wait_set_t *wait_set = (rcl_wait_set_t *)wait_set_handle; - rcl_ret_t ret = rcl_wait(wait_set, timeout); - - return ret; -} - -int32_t rclrs_native_create_subscription_handle( - uintptr_t *subscription_handle, uintptr_t node_handle, - uintptr_t type_support_handle, const char *topic, - uint8_t qos_policy_history, size_t depth, uint8_t qos_policy_reliability, - uint8_t qos_policy_durability, bool avoid_ros_namespace_conventions) { - rcl_node_t *node = (rcl_node_t *)node_handle; - - rosidl_message_type_support_t *type_support = - (rosidl_message_type_support_t *)type_support_handle; - - rcl_subscription_t *subscription = - (rcl_subscription_t *)malloc(sizeof(rcl_subscription_t)); - *subscription = rcl_get_zero_initialized_subscription(); - rcl_subscription_options_t subscription_ops = - rcl_subscription_get_default_options(); - - rmw_qos_profile_t qos_profile = { - qos_policy_history, depth, qos_policy_reliability, qos_policy_durability, - avoid_ros_namespace_conventions}; - subscription_ops.qos = qos_profile; - - rcl_ret_t ret = rcl_subscription_init(subscription, node, type_support, topic, - &subscription_ops); - - *subscription_handle = (uintptr_t)subscription; - return ret; -} - -int32_t rclrs_native_take(uintptr_t subscription_handle, uintptr_t message_handle) { - rcl_subscription_t * subscription = (rcl_subscription_t *)subscription_handle; - void * taken_msg = message_handle; - - rcl_ret_t ret = rcl_take(subscription, taken_msg, NULL); - - return ret; -} diff --git a/rclrs/src/context.rs b/rclrs/src/context.rs new file mode 100644 index 000000000..c3c04ee11 --- /dev/null +++ b/rclrs/src/context.rs @@ -0,0 +1,84 @@ +use crate::error::{RclResult, ToRclResult}; +use crate::{Handle, Node}; +use crate::rcl_bindings::*; +use std::cell::{Ref, RefCell, RefMut}; +use std::env; +use std::ffi::CString; +use std::os::raw::c_char; +use std::rc::Rc; + +pub struct ContextHandle(RefCell); + +impl<'a> Handle for &'a ContextHandle { + type DerefT = Ref<'a, rcl_context_t>; + type DerefMutT = RefMut<'a, rcl_context_t>; + + fn get(self) -> Self::DerefT { + self.0.borrow() + } + + fn get_mut(self) -> Self::DerefMutT { + self.0.borrow_mut() + } +} + +impl Drop for ContextHandle { + fn drop(&mut self) { + let handle = &mut *self.get_mut(); + unsafe { + rcl_shutdown(handle as *mut _); + } + } +} + +pub struct Context { + pub handle: Rc, +} + +impl Context { + fn init(&mut self) -> RclResult { + let args: Vec = env::args() + .filter_map(|arg| CString::new(arg).ok()) + .collect(); + + let c_args: Vec<*const c_char> = args.iter().map(|arg| arg.as_ptr()).collect(); + let handle = &mut *self.handle.get_mut(); + + unsafe { + let allocator = rcutils_get_default_allocator(); + let mut init_options = rcl_get_zero_initialized_init_options(); + rcl_init_options_init(&mut init_options as *mut _, allocator); + rcl_init( + c_args.len() as i32, + c_args.as_ptr(), + &init_options as *const _, + handle as *mut _, + ) + .ok()?; + rcl_init_options_fini(&mut init_options as *mut _).ok()?; + } + + Ok(()) + } + + pub fn ok(&self) -> bool { + let handle = &mut *self.handle.get_mut(); + unsafe { rcl_context_is_valid(handle as *mut _) } + } + + pub fn create_node(&self, node_name: &str) -> RclResult { + Ok(Node::new(node_name, self)?) + } +} + +impl Default for Context { + fn default() -> Self { + let mut context = Self { + handle: Rc::new(ContextHandle(RefCell::new(unsafe { + rcl_get_zero_initialized_context() + }))), + }; + context.init().unwrap(); + context + } +} diff --git a/rclrs/src/error.rs b/rclrs/src/error.rs new file mode 100644 index 000000000..6ff8d67fb --- /dev/null +++ b/rclrs/src/error.rs @@ -0,0 +1,22 @@ +use crate::rcl_bindings::*; +pub use rclrs_common::error::RCLStatusCode as RclError; + +pub type RclResult = Result; + +pub(crate) trait ToRclResult { + fn ok(&self) -> RclResult<()>; + + fn unwrap(&self) { + self.ok().unwrap(); + } +} + +impl ToRclResult for rcl_ret_t { + fn ok(&self) -> RclResult<()> { + if *self as u32 == RCL_RET_OK { + Ok(()) + } else { + Err(RclError::from(*self)) + } + } +} diff --git a/rclrs/src/lib.rs b/rclrs/src/lib.rs new file mode 100644 index 000000000..a1d6c20ce --- /dev/null +++ b/rclrs/src/lib.rs @@ -0,0 +1,96 @@ +pub mod context; +pub mod error; +pub mod node; +pub mod qos; + +mod rcl_bindings; + +pub use self::context::*; +pub use self::error::*; +pub use self::node::*; +pub use self::qos::*; + +use self::rcl_bindings::*; +use std::ops::{Deref, DerefMut}; + +pub trait Handle { + type DerefT: Deref; + type DerefMutT: DerefMut; + + fn get(self) -> Self::DerefT; + fn get_mut(self) -> Self::DerefMutT; +} + +pub fn spin(node: &Node) -> RclResult { + let context_handle = &mut *node.context.get_mut(); + while unsafe { rcl_context_is_valid(context_handle) } { + if let Some(error) = spin_once(node, 500).err() { + match error { + RclError::Timeout => continue, + _ => return Err(error), + } + } + } + + Ok(()) +} + +pub fn spin_once(node: &Node, timeout: i64) -> RclResult { + let mut wait_set_handle = unsafe { rcl_get_zero_initialized_wait_set() }; + + let number_of_subscriptions = node.subscriptions.len(); + let number_of_guard_conditions = 0; + let number_of_timers = 0; + let number_of_clients = 0; + let number_of_services = 0; + + unsafe { + rcl_wait_set_init( + &mut wait_set_handle as *mut _, + number_of_subscriptions, + number_of_guard_conditions, + number_of_timers, + number_of_clients, + number_of_services, + rcutils_get_default_allocator(), + ) + .ok()?; + } + + unsafe { + rcl_wait_set_clear(&mut wait_set_handle as *mut _).ok()?; + } + + for subscription in &node.subscriptions { + if let Some(subscription) = subscription.upgrade() { + let subscription_handle = &*subscription.handle().get(); + unsafe { + rcl_wait_set_add_subscription( + &mut wait_set_handle as *mut _, + subscription_handle as *const _, + std::ptr::null_mut(), + ) + .ok()?; + } + } + } + + unsafe { + rcl_wait(&mut wait_set_handle as *mut _, timeout).ok()?; + } + + for subscription in &node.subscriptions { + if let Some(subscription) = subscription.upgrade() { + let mut message = subscription.create_message(); + let result = subscription.take(&mut *message).unwrap(); + if result { + subscription.callback_fn(message); + } + } + } + unsafe { + rcl_wait_set_fini(&mut wait_set_handle as *mut _).ok()?; + } + + Ok(()) +} diff --git a/rclrs/src/node/mod.rs b/rclrs/src/node/mod.rs new file mode 100644 index 000000000..6e730e31f --- /dev/null +++ b/rclrs/src/node/mod.rs @@ -0,0 +1,105 @@ +use crate::error::{RclResult, ToRclResult}; +use crate::qos::QoSProfile; +use crate::rcl_bindings::*; +use crate::{Context, ContextHandle, Handle}; +use std::cell::{Ref, RefCell, RefMut}; +use std::ffi::CString; +use std::rc::{Rc, Weak}; + +pub mod publisher; +pub use self::publisher::*; +pub mod subscription; +pub use self::subscription::*; + +pub struct NodeHandle(RefCell); + +impl<'a> Handle for &'a NodeHandle { + type DerefT = Ref<'a, rcl_node_t>; + type DerefMutT = RefMut<'a, rcl_node_t>; + + fn get(self) -> Self::DerefT { + self.0.borrow() + } + + fn get_mut(self) -> Self::DerefMutT { + self.0.borrow_mut() + } +} + +impl Drop for NodeHandle { + fn drop(&mut self) { + let handle = &mut *self.get_mut(); + unsafe { + rcl_node_fini(handle as *mut _).unwrap(); + } + } +} + +pub struct Node { + handle: Rc, + pub(crate) context: Rc, + pub(crate) subscriptions: Vec>, +} + +impl Node { + #[allow(clippy::new_ret_no_self)] + pub fn new(node_name: &str, context: &Context) -> RclResult { + Self::new_with_namespace(node_name, "", context) + } + + pub fn new_with_namespace( + node_name: &str, + node_ns: &str, + context: &Context, + ) -> RclResult { + let raw_node_name = CString::new(node_name).unwrap(); + let raw_node_ns = CString::new(node_ns).unwrap(); + + let mut node_handle = unsafe { rcl_get_zero_initialized_node() }; + let context_handle = &mut *context.handle.get_mut(); + + unsafe { + let node_options = rcl_node_get_default_options(); + rcl_node_init( + &mut node_handle as *mut _, + raw_node_name.as_ptr(), + raw_node_ns.as_ptr(), + context_handle as *mut _, + &node_options as *const _, + ) + .ok()?; + } + + let handle = Rc::new(NodeHandle(RefCell::new(node_handle))); + + Ok(Node { + handle, + context: context.handle.clone(), + subscriptions: vec![], + }) + } + + // TODO: make publisher's lifetime depend on node's lifetime + pub fn create_publisher(&self, topic: &str, qos: QoSProfile) -> RclResult> + where + T: rclrs_common::traits::MessageDefinition, + { + Publisher::::new(self, topic, qos) + } + + // TODO: make subscription's lifetime depend on node's lifetime + pub fn create_subscription( + &mut self, + topic: &str, + qos: QoSProfile, + callback: fn(&T), + ) -> RclResult>> + where + T: rclrs_common::traits::MessageDefinition + Default, + { + let subscription = Rc::new(Subscription::::new(self, topic, qos, callback)?); + self.subscriptions + .push(Rc::downgrade(&subscription) as Weak); + Ok(subscription) + } +} diff --git a/rclrs/src/node/publisher.rs b/rclrs/src/node/publisher.rs new file mode 100644 index 000000000..0e3434c9a --- /dev/null +++ b/rclrs/src/node/publisher.rs @@ -0,0 +1,98 @@ +use crate::error::{RclResult, ToRclResult}; +use crate::qos::QoSProfile; +use crate::{Handle, Node, NodeHandle}; +use crate::rcl_bindings::*; +use std::borrow::Borrow; +use std::cell::{Ref, RefCell, RefMut}; +use std::ffi::CString; +use std::marker::PhantomData; +use std::rc::Rc; + +pub struct PublisherHandle { + handle: RefCell, + node_handle: Rc, +} + +impl PublisherHandle { + fn node_handle(&self) -> &NodeHandle { + self.node_handle.borrow() + } +} + +impl<'a> Handle for &'a PublisherHandle { + type DerefT = Ref<'a, rcl_publisher_t>; + type DerefMutT = RefMut<'a, rcl_publisher_t>; + + fn get(self) -> Self::DerefT { + self.handle.borrow() + } + + fn get_mut(self) -> Self::DerefMutT { + self.handle.borrow_mut() + } +} + +impl Drop for PublisherHandle { + fn drop(&mut self) { + let handle = &mut *self.get_mut(); + let node_handle = &mut *self.node_handle().get_mut(); + unsafe { + rcl_publisher_fini(handle as *mut _, node_handle as *mut _); + } + } +} + +pub struct Publisher +where + T: rclrs_common::traits::MessageDefinition, +{ + pub handle: Rc, + message: PhantomData, +} + +impl Publisher +where + T: rclrs_common::traits::MessageDefinition, +{ + pub fn new(node: &Node, topic: &str, qos: QoSProfile) -> RclResult + where + T: rclrs_common::traits::MessageDefinition, + { + let mut publisher_handle = unsafe { rcl_get_zero_initialized_publisher() }; + let type_support = T::get_type_support() as *const rosidl_message_type_support_t; + let topic_c_string = CString::new(topic).unwrap(); + let node_handle = &mut *node.handle.get_mut(); + + unsafe { + let mut publisher_options = rcl_publisher_get_default_options(); + publisher_options.qos = qos.into(); + + rcl_publisher_init( + &mut publisher_handle as *mut _, + node_handle as *mut _, + type_support, + topic_c_string.as_ptr(), + &publisher_options as *const _, + ) + .ok()?; + } + + let handle = Rc::new(PublisherHandle { + handle: RefCell::new(publisher_handle), + node_handle: node.handle.clone(), + }); + + Ok(Self { + handle, + message: PhantomData, + }) + } + + pub fn publish(&self, message: &T) -> RclResult { + let native_message_ptr = message.get_native_message(); + let handle = &mut *self.handle.get_mut(); + let ret = unsafe { rcl_publish(handle as *mut _, native_message_ptr as *mut _) }; + message.destroy_native_message(native_message_ptr); + ret.ok() + } +} diff --git a/rclrs/src/node/subscription.rs b/rclrs/src/node/subscription.rs new file mode 100644 index 000000000..50dc841ad --- /dev/null +++ b/rclrs/src/node/subscription.rs @@ -0,0 +1,160 @@ +use crate::error::{RclError, RclResult, ToRclResult}; +use crate::qos::QoSProfile; +use crate::{Handle, Node, NodeHandle}; +use crate::rcl_bindings::*; +use std::borrow::Borrow; +use std::cell::{Ref, RefCell, RefMut}; +use std::ffi::CString; +use std::marker::PhantomData; +use std::rc::Rc; + +pub struct SubscriptionHandle { + handle: RefCell, + node_handle: Rc, +} + +impl SubscriptionHandle { + fn node_handle(&self) -> &NodeHandle { + self.node_handle.borrow() + } +} + +impl<'a> Handle for &'a SubscriptionHandle { + type DerefT = Ref<'a, rcl_subscription_t>; + type DerefMutT = RefMut<'a, rcl_subscription_t>; + + fn get(self) -> Self::DerefT { + self.handle.borrow() + } + + fn get_mut(self) -> Self::DerefMutT { + self.handle.borrow_mut() + } +} + +impl Drop for SubscriptionHandle { + fn drop(&mut self) { + let handle = &mut *self.get_mut(); + let node_handle = &mut *self.node_handle().get_mut(); + unsafe { + rcl_subscription_fini(handle as *mut _, node_handle as *mut _); + } + } +} + +pub trait SubscriptionBase { + fn handle(&self) -> &SubscriptionHandle; + fn create_message(&self) -> Box; + fn callback_fn(&self, message: Box) -> (); + + fn take(&self, message: &mut rclrs_common::traits::Message) -> RclResult { + let handle = &*self.handle().get(); + let message_handle = message.get_native_message(); + + let result = unsafe { + rcl_take( + handle as *const _, + message_handle as *mut _, + std::ptr::null_mut(), + ) + }; + + let result = match result.into() { + RclError::Ok => { + message.read_handle(message_handle); + Ok(true) + } + RclError::SubscriptionTakeFailed => Ok(false), + error => Err(error), + }; + + message.destroy_native_message(message_handle); + + result + } +} + +pub struct Subscription +where + T: rclrs_common::traits::Message, +{ + pub handle: Rc, + pub callback: fn(&T), + message: PhantomData, +} + +impl Subscription +where + T: rclrs_common::traits::Message, +{ + pub fn new(node: &Node, topic: &str, qos: QoSProfile, callback: fn(&T)) -> RclResult + where + T: rclrs_common::traits::MessageDefinition, + { + let mut subscription_handle = unsafe { rcl_get_zero_initialized_subscription() }; + let type_support = T::get_type_support() as *const rosidl_message_type_support_t; + let topic_c_string = CString::new(topic).unwrap(); + let node_handle = &mut *node.handle.get_mut(); + + unsafe { + let mut subscription_options = rcl_subscription_get_default_options(); + subscription_options.qos = qos.into(); + rcl_subscription_init( + &mut subscription_handle as *mut _, + node_handle as *mut _, + type_support, + topic_c_string.as_ptr(), + &subscription_options as *const _, + ) + .ok()?; + } + + let handle = Rc::new(SubscriptionHandle { + handle: RefCell::new(subscription_handle), + node_handle: node.handle.clone(), + }); + + Ok(Self { + handle, + callback, + message: PhantomData, + }) + } + + pub fn take(&self, message: &mut T) -> RclResult { + let handle = &*self.handle.get(); + let message_handle = message.get_native_message(); + let ret = unsafe { + rcl_take( + handle as *const _, + message_handle as *mut _, + std::ptr::null_mut(), + ) + }; + message.read_handle(message_handle); + message.destroy_native_message(message_handle); + ret.ok() + } + + fn callback_ext(&self, message: Box) { + let msg = message.downcast_ref::().unwrap(); + (self.callback)(msg); + } +} + +impl SubscriptionBase for Subscription +where + T: rclrs_common::traits::MessageDefinition + std::default::Default, +{ + fn handle(&self) -> &SubscriptionHandle { + self.handle.borrow() + } + + fn create_message(&self) -> Box { + Box::new(T::default()) + } + + fn callback_fn(&self, message: Box) { + self.callback_ext(message); + } +} diff --git a/rclrs/src/qos.rs b/rclrs/src/qos.rs new file mode 100644 index 000000000..5ed8c73fd --- /dev/null +++ b/rclrs/src/qos.rs @@ -0,0 +1,135 @@ +use crate::rcl_bindings::*; + +pub enum QoSReliabilityPolicy { + SystemDefault = 0, + Reliable = 1, + BestEffort = 2, +} + +pub enum QoSHistoryPolicy { + SystemDefault = 0, + KeepLast = 1, + KeepAll = 2, +} + +pub enum QoSDurabilityPolicy { + SystemDefault = 0, + TransientLocal = 1, + Volatile = 2, +} + +pub struct QoSProfile { + pub history: QoSHistoryPolicy, + pub depth: isize, + pub reliability: QoSReliabilityPolicy, + pub durability: QoSDurabilityPolicy, + pub avoid_ros_namespace_conventions: bool, +} + +pub const QOS_PROFILE_SENSOR_DATA: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::KeepLast, + depth: 5, + reliability: QoSReliabilityPolicy::BestEffort, + durability: QoSDurabilityPolicy::Volatile, + avoid_ros_namespace_conventions: false, +}; + +pub const QOS_PROFILE_PARAMETERS: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::KeepLast, + depth: 1000, + reliability: QoSReliabilityPolicy::Reliable, + durability: QoSDurabilityPolicy::Volatile, + avoid_ros_namespace_conventions: false, +}; + +pub const QOS_PROFILE_DEFAULT: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::KeepLast, + depth: 10, + reliability: QoSReliabilityPolicy::Reliable, + durability: QoSDurabilityPolicy::Volatile, + avoid_ros_namespace_conventions: false, +}; + +pub const QOS_PROFILE_SERVICES_DEFAULT: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::KeepLast, + depth: 10, + reliability: QoSReliabilityPolicy::Reliable, + durability: QoSDurabilityPolicy::Volatile, + avoid_ros_namespace_conventions: false, +}; + +pub const QOS_PROFILE_PARAMETER_EVENTS: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::KeepAll, + depth: 1000, + reliability: QoSReliabilityPolicy::Reliable, + durability: QoSDurabilityPolicy::Volatile, + avoid_ros_namespace_conventions: false, +}; + +pub const SYSTEM_DEFAULT: isize = 0; + +pub const QOS_PROFILE_SYSTEM_DEFAULT: QoSProfile = QoSProfile { + history: QoSHistoryPolicy::SystemDefault, + depth: SYSTEM_DEFAULT, + reliability: QoSReliabilityPolicy::SystemDefault, + durability: QoSDurabilityPolicy::SystemDefault, + avoid_ros_namespace_conventions: false, +}; + +impl From for rmw_qos_profile_t { + fn from(qos: QoSProfile) -> Self { + Self { + history: qos.history.into(), + depth: qos.depth as usize, + reliability: qos.reliability.into(), + durability: qos.durability.into(), + avoid_ros_namespace_conventions: qos.avoid_ros_namespace_conventions, + } + } +} + +impl From for rmw_qos_history_policy_t { + fn from(policy: QoSHistoryPolicy) -> Self { + match policy { + QoSHistoryPolicy::SystemDefault => { + rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT + } + QoSHistoryPolicy::KeepLast => { + rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_LAST + } + QoSHistoryPolicy::KeepAll => rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_ALL, + } + } +} + +impl From for rmw_qos_reliability_policy_t { + fn from(policy: QoSReliabilityPolicy) -> Self { + match policy { + QoSReliabilityPolicy::SystemDefault => { + rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT + } + QoSReliabilityPolicy::Reliable => { + rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_RELIABLE + } + QoSReliabilityPolicy::BestEffort => { + rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT + } + } + } +} + +impl From for rmw_qos_durability_policy_t { + fn from(policy: QoSDurabilityPolicy) -> Self { + match policy { + QoSDurabilityPolicy::SystemDefault => { + rmw_qos_durability_policy_t::RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT + } + QoSDurabilityPolicy::TransientLocal => { + rmw_qos_durability_policy_t::RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL + } + QoSDurabilityPolicy::Volatile => { + rmw_qos_durability_policy_t::RMW_QOS_POLICY_DURABILITY_VOLATILE + } + } + } +} diff --git a/rclrs/src/rcl_bindings.rs b/rclrs/src/rcl_bindings.rs new file mode 100644 index 000000000..df06b6eb1 --- /dev/null +++ b/rclrs/src/rcl_bindings.rs @@ -0,0 +1,12 @@ +#[allow(dead_code)] + +mod rcl_bindings { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + #![allow(clippy::all)] + + include!(concat!(env!("OUT_DIR"), "/rcl_bindings.rs")); +} + +pub(crate) use self::rcl_bindings::*; \ No newline at end of file diff --git a/rclrs/src/rcl_wrapper.h b/rclrs/src/rcl_wrapper.h new file mode 100644 index 000000000..4bb36ce2d --- /dev/null +++ b/rclrs/src/rcl_wrapper.h @@ -0,0 +1,2 @@ +#include +#include \ No newline at end of file diff --git a/rclrs/src/rust/.gitignore b/rclrs/src/rust/.gitignore deleted file mode 100644 index 6aa106405..000000000 --- a/rclrs/src/rust/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -Cargo.lock diff --git a/rclrs/src/rust/src/lib.rs b/rclrs/src/rust/src/lib.rs deleted file mode 100644 index 7f917a016..000000000 --- a/rclrs/src/rust/src/lib.rs +++ /dev/null @@ -1,264 +0,0 @@ -pub mod qos; -mod node; - -use std::ffi::CStr; -use std::ffi::CString; - -extern crate libc; -extern crate rclrs_common; - -use libc::c_char; -use libc::c_long; -use libc::c_int; -use libc::uintptr_t; -use libc::size_t; -use rclrs_common::error::RCLError; -use rclrs_common::error::RCLStatusCode; - -pub trait Handle { - fn handle(&self) -> uintptr_t; -} - -#[link(name = "rclrs")] -extern "C" { - fn rclrs_native_init() -> c_int; - fn rclrs_native_ok() -> c_int; - fn rclrs_native_get_error_string_safe() -> *const c_char; - fn rclrs_native_reset_error() -> (); - fn rclrs_native_create_node_handle( - node_handle: *mut uintptr_t, - name: *const c_char, - namespace: *const c_char, - ) -> c_int; - - fn rclrs_native_get_zero_initialized_wait_set() -> uintptr_t; - fn rclrs_native_destroy_wait_set(wait_set_handle: uintptr_t) -> (); - - fn rclrs_native_wait_set_init( - wait_set_handle: uintptr_t, - number_of_subscriptions: size_t, - number_of_guard_conditions: size_t, - number_of_timers: size_t, - number_of_clients: size_t, - number_of_services: size_t, - ) -> c_int; - - fn rclrs_native_wait_set_clear_subscriptions(wait_set_handle: uintptr_t) -> c_int; - - fn rclrs_native_wait_set_clear_services(wait_set_handle: uintptr_t) -> c_int; - - fn rclrs_native_wait_set_clear_clients(wait_set_handle: uintptr_t) -> c_int; - - fn rclrs_native_wait_set_add_subscription( - wait_set_handle: uintptr_t, - subscription_handle: uintptr_t, - ) -> c_int; - - fn rclrs_native_wait(wait_set_handle: uintptr_t, timeout: c_long) -> c_int; - - fn rclrs_native_take(subscription_handle: uintptr_t, message_handle: uintptr_t) -> c_int; -} - -pub fn init() -> Result<(), RCLError> { - let ret = unsafe { rclrs_native_init() }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - - -pub fn ok() -> bool { - unsafe { - return rclrs_native_ok() != 0; - } -} - -fn generate_rcl_error(ret: i32) -> RCLError { - let c_error_message = unsafe { CStr::from_ptr(rclrs_native_get_error_string_safe()) }; - let error_message = c_error_message.to_str().unwrap(); - unsafe { - rclrs_native_reset_error(); - } - return RCLError { - code: RCLStatusCode::from(ret), - message: error_message, - }; -} - -fn create_node_handle(name: &str, namespace: &str) -> Result { - let c_string_name = CString::new(name).unwrap(); - let c_string_namespace = CString::new(namespace).unwrap(); - let mut node_handle = 0; - let ret = unsafe { - rclrs_native_create_node_handle( - &mut node_handle, - c_string_name.as_ptr(), - c_string_namespace.as_ptr(), - ) - }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(node_handle), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn create_node(name: &'static str) -> node::Node { - return create_node_with_namespace(name, ""); -} - -pub fn create_node_with_namespace(name: &'static str, namespace: &'static str) -> node::Node { - let node_handle = create_node_handle(name, namespace).unwrap(); - return node::Node::new(node_handle, name); -} - -pub fn get_zero_initialized_wait_set() -> uintptr_t { - return unsafe { rclrs_native_get_zero_initialized_wait_set() }; -} - -pub fn destroy_wait_set(wait_set_handle: uintptr_t) -> () { - unsafe { - rclrs_native_destroy_wait_set(wait_set_handle); - }; -} - -pub fn wait_set_init( - wait_set_handle: uintptr_t, - number_of_subscriptions: usize, - number_of_guard_conditions: usize, - number_of_timers: usize, - number_of_clients: usize, - number_of_services: usize, -) -> Result<(), RCLError> { - let ret = unsafe { - rclrs_native_wait_set_init( - wait_set_handle, - number_of_subscriptions, - number_of_guard_conditions, - number_of_timers, - number_of_clients, - number_of_services, - ) - }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn wait_set_clear_subscriptions(wait_set_handle: uintptr_t) -> Result<(), RCLError> { - let ret = unsafe { rclrs_native_wait_set_clear_subscriptions(wait_set_handle) }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn wait_set_clear_services(wait_set_handle: uintptr_t) -> Result<(), RCLError> { - let ret = unsafe { rclrs_native_wait_set_clear_services(wait_set_handle) }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn wait_set_clear_clients(wait_set_handle: uintptr_t) -> Result<(), RCLError> { - let ret = unsafe { rclrs_native_wait_set_clear_clients(wait_set_handle) }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn wait_set_add_subscription( - wait_set_handle: uintptr_t, - subscription_handle: uintptr_t, -) -> Result<(), RCLError> { - let ret = - unsafe { rclrs_native_wait_set_add_subscription(wait_set_handle, subscription_handle) }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn wait(wait_set_handle: uintptr_t, timeout: i64) -> Result<(), RCLError> { - let ret = unsafe { rclrs_native_wait(wait_set_handle, timeout) }; - let rcl_code = RCLStatusCode::from(ret); - match rcl_code { - RCLStatusCode::OK => Ok(()), - _ => Err(generate_rcl_error(ret)), - } -} - -pub fn take( - subscription_handle: uintptr_t, - message: &mut rclrs_common::traits::Message, -) -> Result { - let message_handle = message.get_native_message(); - let ret = unsafe { rclrs_native_take(subscription_handle, message_handle) }; - let rcl_code = RCLStatusCode::from(ret); - let result = match rcl_code { - RCLStatusCode::OK => { - message.read_handle(message_handle); - Ok(true) - } - RCLStatusCode::SubscriptionTakeFailed => Ok(false), - _ => Err(generate_rcl_error(ret)), - }; - message.destroy_native_message(message_handle); - return result; -} - -pub fn spin(node: &node::Node) { - while ok() { - spin_once(node, 500); - } -} - -pub fn spin_once(node: &node::Node, timeout: i64) -> () { - let wait_set_handle = get_zero_initialized_wait_set(); - - let number_of_subscriptions = node.subscriptions().len(); - let number_of_guard_conditions = 0; - let number_of_timers = 0; - let number_of_clients = 0; - let number_of_services = 0; - - wait_set_init( - wait_set_handle, - number_of_subscriptions, - number_of_guard_conditions, - number_of_timers, - number_of_clients, - number_of_services, - ).unwrap(); - - wait_set_clear_subscriptions(wait_set_handle).unwrap(); - - wait_set_clear_services(wait_set_handle).unwrap(); - - wait_set_clear_clients(wait_set_handle).unwrap(); - - for subscription in node.subscriptions() { - wait_set_add_subscription(wait_set_handle, subscription.handle()).unwrap(); - } - - wait(wait_set_handle, timeout); - - for subscription in node.subscriptions() { - let mut message = subscription.create_message(); - let result = take(subscription.handle(), &mut *message).unwrap(); - if result { - subscription.callback_fn(message); - } - } - destroy_wait_set(wait_set_handle); -} diff --git a/rclrs/src/rust/src/node/mod.rs b/rclrs/src/rust/src/node/mod.rs deleted file mode 100644 index e1f303372..000000000 --- a/rclrs/src/rust/src/node/mod.rs +++ /dev/null @@ -1,183 +0,0 @@ -mod publisher; -mod subscription; - -use std::rc::Rc; - -use qos; - -use std; -use std::ffi::CStr; -use std::ffi::CString; - -use libc::uintptr_t; -use libc::c_int; -use libc::c_char; -use libc::c_uchar; -use libc::size_t; -use rclrs_common; - -use rclrs_common::error::RCLError; -use generate_rcl_error; - -#[link(name = "rclrs")] -extern "C" { - fn rclrs_native_create_publisher_handle( - publisher_handle: *mut uintptr_t, - node_handle: uintptr_t, - type_support_handle: uintptr_t, - topic: *const c_char, - qos_policy_history: c_uchar, - depth: size_t, - qos_policy_reliability: c_uchar, - qos_policy_durability: c_uchar, - avoid_ros_namespace_conventions: c_uchar, - ) -> c_int; - - fn rclrs_native_create_subscription_handle( - subscription_handle: *mut uintptr_t, - node_handle: uintptr_t, - type_support_handle: uintptr_t, - topic: *const c_char, - qos_policy_history: c_uchar, - depth: size_t, - qos_policy_reliability: c_uchar, - qos_policy_durability: c_uchar, - avoid_ros_namespace_conventions: c_uchar, - ) -> c_int; -} - -pub struct Node { - handle: uintptr_t, - name: &'static str, - pub subscriptions: Vec>, -} - -fn create_publisher_handle( - node_handle: uintptr_t, - topic: &'static str, - qos_history: u8, - qos_depth: usize, - qos_reliability: u8, - qos_durability: u8, - qos_avoid_ros_namespace_conventions: u8, -) -> Result -where - T: rclrs_common::traits::MessageDefinition, -{ - let c_string_topic = CString::new(topic).unwrap(); - let mut publisher_handle = 0; - let ret = unsafe { - rclrs_native_create_publisher_handle( - &mut publisher_handle, - node_handle, - T::get_type_support(), - c_string_topic.as_ptr(), - qos_history, - qos_depth, - qos_reliability, - qos_durability, - qos_avoid_ros_namespace_conventions, - ) - }; - - match ret { - 0 => Ok(publisher_handle), - _ => Err(generate_rcl_error(ret)), - } -} - -fn create_subscription_handle( - node_handle: uintptr_t, - topic: &'static str, - qos_history: u8, - qos_depth: usize, - qos_reliability: u8, - qos_durability: u8, - qos_avoid_ros_namespace_conventions: u8, -) -> Result -where - T: rclrs_common::traits::MessageDefinition, -{ - let c_string_topic = CString::new(topic).unwrap(); - let mut subscription_handle = 0; - let ret = unsafe { - rclrs_native_create_subscription_handle( - &mut subscription_handle, - node_handle, - T::get_type_support(), - c_string_topic.as_ptr(), - qos_history, - qos_depth, - qos_reliability, - qos_durability, - qos_avoid_ros_namespace_conventions, - ) - }; - - match ret { - 0 => Ok(subscription_handle), - _ => Err(generate_rcl_error(ret)), - } -} - -impl Node { - pub fn new(handle: uintptr_t, name: &'static str) -> Node { - Node { - handle: handle, - name: name, - subscriptions: Vec::new(), - } - } - - pub fn create_publisher( - self: &Self, - topic: &'static str, - qos_profile: qos::QoSProfile, - ) -> publisher::Publisher - where - T: rclrs_common::traits::MessageDefinition, - { - let publisher_handle = create_publisher_handle::( - self.handle, - topic, - qos_profile.history as u8, - qos_profile.depth as usize, - qos_profile.reliability as u8, - qos_profile.durability as u8, - qos_profile.avoid_ros_namespace_conventions as u8, - ).unwrap(); - return publisher::Publisher::new(publisher_handle, topic); - } - - pub fn create_subscription( - self: &mut Self, - topic: &'static str, - qos_profile: qos::QoSProfile, - callback: fn(&T), - ) -> Rc> - where - T: rclrs_common::traits::MessageDefinition + std::default::Default, - { - let subscription_handle = create_subscription_handle::( - self.handle, - topic, - qos_profile.history as u8, - qos_profile.depth as usize, - qos_profile.reliability as u8, - qos_profile.durability as u8, - qos_profile.avoid_ros_namespace_conventions as u8, - ).unwrap(); - let sub = subscription::Subscription::new(subscription_handle, topic, callback); - let sub_ptr = Rc::new(sub); - self.subscriptions.push(sub_ptr.clone()); - return sub_ptr; - } - - pub fn number_of_subscriptions(&self) -> usize { - return self.subscriptions.len(); - } - - pub fn subscriptions(&self) -> &Vec> { - return &self.subscriptions; - } -} diff --git a/rclrs/src/rust/src/node/publisher.rs b/rclrs/src/rust/src/node/publisher.rs deleted file mode 100644 index d35f92702..000000000 --- a/rclrs/src/rust/src/node/publisher.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::marker::PhantomData; - -use libc::uintptr_t; -use libc::c_int; -use rclrs_common; - -use rclrs_common::error::RCLError; -use generate_rcl_error; - -#[link(name = "rclrs")] -extern "C" { - fn rclrs_native_publish(publisher_handle: uintptr_t, message_handle: uintptr_t) -> c_int; -} - -pub struct Publisher -where - T: rclrs_common::traits::MessageDefinition, -{ - handle: uintptr_t, - topic: &'static str, - publisher_type: PhantomData, -} - -impl Publisher -where - T: rclrs_common::traits::MessageDefinition, -{ - pub fn new(handle: uintptr_t, topic: &'static str) -> Publisher { - Publisher:: { - handle: handle, - topic: topic, - publisher_type: PhantomData, - } - } - - pub fn publish(self: &Self, message: &T) -> Result<(), RCLError> { - let native_message_ptr = message.get_native_message(); - let ret = unsafe { rclrs_native_publish(self.handle, native_message_ptr) }; - message.destroy_native_message(native_message_ptr); - match ret { - 0 => Ok(()), - _ => Err(generate_rcl_error(ret)), - } - } -} diff --git a/rclrs/src/rust/src/node/subscription.rs b/rclrs/src/rust/src/node/subscription.rs deleted file mode 100644 index 7d9b07ce4..000000000 --- a/rclrs/src/rust/src/node/subscription.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std; - -use libc::uintptr_t; -use libc::c_int; -use rclrs_common; - -use rclrs_common::error::RCLError; -use generate_rcl_error; -use Handle; - -use std::any::Any; - -pub trait SubscriptionBase: Handle { - fn create_message(&self) -> Box; - fn callback_fn(&self, message: Box) -> (); -} - -pub struct Subscription -where - T: rclrs_common::traits::MessageDefinition, -{ - handle: uintptr_t, - topic: &'static str, - callback: fn(&T), - subscription_type: std::marker::PhantomData, -} - -impl Handle for Subscription -where - T: rclrs_common::traits::MessageDefinition, -{ - fn handle(&self) -> uintptr_t { - return self.handle; - } -} - -impl SubscriptionBase for Subscription -where - T: rclrs_common::traits::MessageDefinition + std::default::Default, -{ - fn create_message(&self) -> Box { - let message: T = Default::default(); - return Box::new(message); - } - - fn callback_fn(&self, message: Box) -> () { - self.callback_ext(message); - } -} - -impl Subscription -where - T: rclrs_common::traits::MessageDefinition, -{ - pub fn new(handle: uintptr_t, topic: &'static str, callback: fn(&T)) -> Subscription { - Subscription:: { - handle: handle, - topic: topic, - callback: callback, - subscription_type: std::marker::PhantomData, - } - } - - fn callback_ext(&self, message: Box) -> () { - let msg = message.downcast_ref::().unwrap(); - (self.callback)(msg); - } -} diff --git a/rclrs/src/rust/src/qos.rs b/rclrs/src/rust/src/qos.rs deleted file mode 100644 index b541dbad9..000000000 --- a/rclrs/src/rust/src/qos.rs +++ /dev/null @@ -1,75 +0,0 @@ -pub enum QoSReliabilityPolicy { - SystemDefault = 0, - Reliable = 1, - BestEffort = 2, -} - -pub enum QoSHistoryPolicy { - SystemDefault = 0, - KeepLast = 1, - KeepAll = 2, -} - -pub enum QoSDurabilityPolicy { - SystemDefault = 0, - TransientLocal = 1, - Volatile = 2, -} - -pub struct QoSProfile { - pub history: QoSHistoryPolicy, - pub depth: isize, - pub reliability: QoSReliabilityPolicy, - pub durability: QoSDurabilityPolicy, - pub avoid_ros_namespace_conventions: bool, -} - -pub const QOS_PROFILE_SENSOR_DATA: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 5, - reliability: QoSReliabilityPolicy::BestEffort, - durability: QoSDurabilityPolicy::Volatile, - avoid_ros_namespace_conventions: false, -}; - -pub const QOS_PROFILE_PARAMETERS: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 1000, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - avoid_ros_namespace_conventions: false, -}; - -pub const QOS_PROFILE_DEFAULT: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 10, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - avoid_ros_namespace_conventions: false, -}; - -pub const QOS_PROFILE_SERVICES_DEFAULT: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 10, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - avoid_ros_namespace_conventions: false, -}; - -pub const QOS_PROFILE_PARAMETER_EVENTS: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::KeepAll, - depth: 1000, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - avoid_ros_namespace_conventions: false, -}; - -pub const SYSTEM_DEFAULT: isize = 0; - -pub const QOS_PROFILE_SYSTEM_DEFAULT: QoSProfile = QoSProfile { - history: QoSHistoryPolicy::SystemDefault, - depth: SYSTEM_DEFAULT, - reliability: QoSReliabilityPolicy::SystemDefault, - durability: QoSDurabilityPolicy::SystemDefault, - avoid_ros_namespace_conventions: false, -}; diff --git a/rclrs_common/Cargo.toml b/rclrs_common/Cargo.toml index f7e9ade98..aaa4813eb 100644 --- a/rclrs_common/Cargo.toml +++ b/rclrs_common/Cargo.toml @@ -2,7 +2,9 @@ name = "rclrs_common" version = "0.1.0" authors = ["Esteve Fernandez "] +edition = "2018" [dependencies] libc = "0.2" -downcast = "0.9" +downcast = "0.10" +failure = "0.1.5" \ No newline at end of file diff --git a/rclrs_common/src/lib.rs b/rclrs_common/src/lib.rs index 5d7adf144..cf6af5e5b 100644 --- a/rclrs_common/src/lib.rs +++ b/rclrs_common/src/lib.rs @@ -1,48 +1,82 @@ -#[macro_use] -extern crate downcast; -extern crate libc; - pub mod error { + use failure::Fail; + #[derive(Debug)] pub struct RCLError { pub code: RCLStatusCode, pub message: &'static str, } - #[derive(Debug)] + #[derive(Debug, Fail)] pub enum RCLStatusCode { - OK = 0, + #[fail(display = "success")] + Ok = 0, + #[fail(display = "unspecified error")] Error = 1, + #[fail(display = "timeout occurred")] Timeout = 2, + #[fail(display = "failed to allocate memory")] BadAlloc = 10, + #[fail(display = "invalid argument")] InvalidArgument = 11, + #[fail(display = "context already initialized")] AlreadyInit = 100, + #[fail(display = "context not yet initialized")] NotInit = 101, + #[fail(display = "mismatched rmw identifier")] MismatchedRmwId = 102, + #[fail(display = "topic name does not pass validation")] TopicNameInvalid = 103, + #[fail(display = "service name (same as topic name) does not pass validation")] ServiceNameInvalid = 104, + #[fail(display = "topic name substitution is unknown")] UnknownSubstitution = 105, + #[fail(display = "node already shutdown")] + AlreadyShutdown = 106, + #[fail(display = "invalid node given")] NodeInvalid = 200, + #[fail(display = "invalid node name given")] NodeInvalidName = 201, + #[fail(display = "invalid node namespace given")] NodeInvalidNamespace = 202, + #[fail(display = "invalid publisher given")] PublisherInvalid = 300, + #[fail(display = "invalid subscriber given")] SubscriptionInvalid = 400, + #[fail(display = "failed to take a message from the subscription")] SubscriptionTakeFailed = 401, + #[fail(display = "invalid client given")] ClientInvalid = 500, + #[fail(display = "failed to take a response from the client")] ClientTakeFailed = 501, + #[fail(display = "invalid service given")] ServiceInvalid = 600, + #[fail(display = "failed to take a request from the service")] ServiceTakeFailed = 601, + #[fail(display = "invalid timer given")] TimerInvalid = 800, + #[fail(display = "given timer was canceled")] TimerCanceled = 801, + #[fail(display = "invalid wait set given")] WaitSetInvalid = 900, + #[fail(display = "given wait set is empty")] WaitSetEmpty = 901, + #[fail(display = "given wait set is full")] WaitSetFull = 902, + #[fail(display = "argument is not a valid remap rule")] + InvalidRemapRule = 1001, + #[fail(display = "expected one type of lexeme but got another")] + WrongLexeme = 1002, + #[fail(display = "argument is not a valid parameter rule")] + InvalidParamRule = 1010, + #[fail(display = "argument is not a valid log level")] + InvalidLogLevelRule = 1020, } impl From for RCLStatusCode { fn from(error: i32) -> Self { match error { - 0 => RCLStatusCode::OK, + 0 => RCLStatusCode::Ok, 1 => RCLStatusCode::Error, 2 => RCLStatusCode::Timeout, 10 => RCLStatusCode::BadAlloc, @@ -53,6 +87,7 @@ pub mod error { 103 => RCLStatusCode::TopicNameInvalid, 104 => RCLStatusCode::ServiceNameInvalid, 105 => RCLStatusCode::UnknownSubstitution, + 106 => RCLStatusCode::AlreadyShutdown, 200 => RCLStatusCode::NodeInvalid, 201 => RCLStatusCode::NodeInvalidName, 202 => RCLStatusCode::NodeInvalidNamespace, @@ -68,6 +103,10 @@ pub mod error { 900 => RCLStatusCode::WaitSetInvalid, 901 => RCLStatusCode::WaitSetEmpty, 902 => RCLStatusCode::WaitSetFull, + 1001 => RCLStatusCode::InvalidRemapRule, + 1002 => RCLStatusCode::WrongLexeme, + 1010 => RCLStatusCode::InvalidParamRule, + 1020 => RCLStatusCode::InvalidLogLevelRule, _ => unimplemented!(), } } @@ -75,14 +114,17 @@ pub mod error { } pub mod traits { + use downcast::{ + downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any, + }; use libc::uintptr_t; - use downcast::Any; pub trait Message: Any { fn get_native_message(&self) -> uintptr_t; fn destroy_native_message(&self, message_handle: uintptr_t) -> (); fn read_handle(&mut self, message_handle: uintptr_t) -> (); } + downcast!(Message); pub trait MessageDefinition: Message { diff --git a/rclrs_examples/.gitignore b/rclrs_examples/.gitignore deleted file mode 100644 index eccd7b4ab..000000000 --- a/rclrs_examples/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target/ -**/*.rs.bk diff --git a/rclrs_examples/Cargo.toml b/rclrs_examples/Cargo.toml index 39962a458..612ccb798 100644 --- a/rclrs_examples/Cargo.toml +++ b/rclrs_examples/Cargo.toml @@ -2,6 +2,7 @@ name = "rclrs_examples" version = "0.1.0" authors = ["Esteve Fernandez "] +edition = "2018" [[bin]] name = "rclrs_subscriber" @@ -9,4 +10,7 @@ path = "src/rclrs_subscriber.rs" [[bin]] name = "rclrs_publisher" -path = "src/rclrs_publisher.rs" \ No newline at end of file +path = "src/rclrs_publisher.rs" + +[dependencies] +failure = "0.1.5" \ No newline at end of file diff --git a/rclrs_examples/build.rs b/rclrs_examples/build.rs deleted file mode 100644 index 83ff6301e..000000000 --- a/rclrs_examples/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::path::Path; -use std::env; - -fn main() { - let dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - // println!("cargo:rustc-link-search=native={}", Path::new(&dir).join("lib").display()); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/rclrs/lib/"); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/rcl/lib/"); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/rcutils/lib/"); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/rmw/lib/"); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/std_msgs/lib/"); - println!("cargo:rustc-link-search=native=/home/esteve/Projects/rust/ros2_rust_ws/install_isolated/builtin_interfaces/lib/"); -} diff --git a/rclrs_examples/src/rclrs_publisher.rs b/rclrs_examples/src/rclrs_publisher.rs index c6c4b1e7f..11e86f051 100644 --- a/rclrs_examples/src/rclrs_publisher.rs +++ b/rclrs_examples/src/rclrs_publisher.rs @@ -1,22 +1,26 @@ -extern crate rclrs; -extern crate std_msgs; +use rclrs; +use std_msgs; -fn main() { - rclrs::init().unwrap(); +fn main() -> rclrs::RclResult { + let context = rclrs::Context::default(); + + let node = context.create_node("minimal_publisher")?; - let node = rclrs::create_node("minimal_publisher"); let publisher = - node.create_publisher::("topic", rclrs::qos::QOS_PROFILE_DEFAULT); + node.create_publisher::("topic", rclrs::QOS_PROFILE_DEFAULT)?; - let mut message: std_msgs::msg::String = Default::default(); + let mut message = std_msgs::msg::String::default(); let mut publish_count: u32 = 1; - while rclrs::ok() { + while context.ok() { message.data = format!("Hello, world! {}", publish_count); println!("Publishing: [{}]", message.data); - publisher.publish(&message).unwrap(); + publisher.publish(&message)?; publish_count += 1; - std::thread::sleep(std::time::Duration::from_millis(1500)); + std::thread::sleep(std::time::Duration::from_millis(500)); } + + Ok(()) } + diff --git a/rclrs_examples/src/rclrs_subscriber.rs b/rclrs_examples/src/rclrs_subscriber.rs index 82d705bb1..6b69b2185 100644 --- a/rclrs_examples/src/rclrs_subscriber.rs +++ b/rclrs_examples/src/rclrs_subscriber.rs @@ -1,19 +1,20 @@ -extern crate rclrs; -extern crate std_msgs; +use rclrs; +use std_msgs; fn topic_callback(msg: &std_msgs::msg::String) { println!("I heard: '{}'", msg.data); } -fn main() { - rclrs::init().unwrap(); +fn main() -> rclrs::RclResult { + let context = rclrs::Context::default(); - let mut node = rclrs::create_node("minimal_subscriber"); - let subscription = node.create_subscription::( + let mut node = context.create_node("minimal_subscriber")?; + + let _subscription = node.create_subscription::( "topic", - rclrs::qos::QOS_PROFILE_DEFAULT, + rclrs::QOS_PROFILE_DEFAULT, topic_callback, - ); + )?; - rclrs::spin(&node); -} + rclrs::spin(&node) +} \ No newline at end of file diff --git a/ros2_rust.repos b/ros2_rust.repos index b3d9c5645..562be5c33 100644 --- a/ros2_rust.repos +++ b/ros2_rust.repos @@ -1,165 +1,13 @@ repositories: - ament/ament_cmake: - type: git - url: https://github.com/ament/ament_cmake.git - version: master - ament/ament_index: - type: git - url: https://github.com/ament/ament_index.git - version: master - ament/ament_lint: - type: git - url: https://github.com/ament/ament_lint.git - version: master - ament/ament_package: - type: git - url: https://github.com/ament/ament_package.git - version: master - ament/ament_tools: - type: git - url: https://github.com/ament/ament_tools.git - version: master - ament/gmock_vendor: - type: git - url: https://github.com/ament/gmock_vendor.git - version: master - ament/gtest_vendor: - type: git - url: https://github.com/ament/gtest_vendor.git - version: master - ament/osrf_pycommon: - type: git - url: https://github.com/osrf/osrf_pycommon.git - version: master - ament/uncrustify: - type: git - url: https://github.com/ament/uncrustify.git - version: master - eProsima/Fast-CDR: - type: git - url: https://github.com/eProsima/Fast-CDR.git - version: master - eProsima/Fast-RTPS: - type: git - url: https://github.com/eProsima/Fast-RTPS.git - version: master - ros/class_loader: - type: git - url: https://github.com/ros/class_loader.git - version: ros2 - ros2/ament_cmake_ros: - type: git - url: https://github.com/ros2/ament_cmake_ros.git - version: master ros2/common_interfaces: type: git url: https://github.com/ros2/common_interfaces.git - version: master - ros2/demos: - type: git - url: https://github.com/ros2/demos.git - version: master - ros2/example_interfaces: - type: git - url: https://github.com/ros2/example_interfaces.git - version: master - ros2/examples: - type: git - url: https://github.com/ros2/examples.git - version: master - ros2/geometry2: - type: git - url: https://github.com/ros2/geometry2.git - version: ros2 - ros2/launch: - type: git - url: https://github.com/ros2/launch.git - version: master - ros2/poco_vendor: - type: git - url: https://github.com/ros2/poco_vendor.git - version: master - ros2/rcl: - type: git - url: https://github.com/ros2/rcl.git - version: master + version: crystal ros2/rcl_interfaces: type: git url: https://github.com/ros2/rcl_interfaces.git - version: master - ros2/rclc: - type: git - url: https://github.com/ros2/rclc.git - version: master - ros2/rclcpp: - type: git - url: https://github.com/ros2/rclcpp.git - version: master - ros2/rclpy: - type: git - url: https://github.com/ros2/rclpy.git - version: master - ros2/rcutils: - type: git - url: https://github.com/ros2/rcutils.git - version: master - ros2/realtime_support: - type: git - url: https://github.com/ros2/realtime_support.git - version: master - ros2/rmw: - type: git - url: https://github.com/ros2/rmw.git - version: master - ros2/rmw_connext: - type: git - url: https://github.com/ros2/rmw_connext.git - version: master - ros2/rmw_fastrtps: - type: git - url: https://github.com/ros2/rmw_fastrtps.git - version: master - ros2/rmw_implementation: - type: git - url: https://github.com/ros2/rmw_implementation.git - version: master - ros2/ros1_bridge: - type: git - url: https://github.com/ros2/ros1_bridge.git - version: master - ros2/ros2cli: - type: git - url: https://github.com/ros2/ros2cli.git - version: master - ros2/rosidl: - type: git - url: https://github.com/ros2/rosidl.git - version: master - ros2/rosidl_dds: - type: git - url: https://github.com/ros2/rosidl_dds.git - version: master - ros2/rosidl_typesupport: - type: git - url: https://github.com/ros2/rosidl_typesupport.git - version: master - ros2/system_tests: - type: git - url: https://github.com/ros2/system_tests.git - version: master - ros2/tinyxml_vendor: - type: git - url: https://github.com/ros2/tinyxml_vendor.git - version: master - ros2/tlsf: - type: git - url: https://github.com/ros2/tlsf.git - version: master - ros2_rust/ros2_rust: - type: git - url: https://github.com/esteve/ros2_rust.git - version: master - vendor/console_bridge: + version: crystal + ros2/rosidl_defaults: type: git - url: https://github.com/ros/console_bridge.git - version: master + url: https://github.com/ros2/rosidl_defaults.git + version: crystal \ No newline at end of file diff --git a/rosidl_generator_rs/CMakeLists.txt b/rosidl_generator_rs/CMakeLists.txt index 5bef6c363..86ea93f02 100644 --- a/rosidl_generator_rs/CMakeLists.txt +++ b/rosidl_generator_rs/CMakeLists.txt @@ -3,24 +3,38 @@ cmake_minimum_required(VERSION 3.5) project(rosidl_generator_rs) find_package(ament_cmake REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_typesupport_interface REQUIRED) +find_package(rosidl_typesupport_introspection_c REQUIRED) -ament_export_dependencies(ament_cmake) ament_export_dependencies(rosidl_cmake) +ament_export_dependencies(rosidl_generator_c) + +ament_index_register_resource("rosidl_generator_packages") +ament_index_register_resource("rosidl_runtime_packages") ament_python_install_package(${PROJECT_NAME}) +ament_package( + CONFIG_EXTRAS "rosidl_generator_rs-extras.cmake.in" + "cmake/rosidl_generator_rs_get_typesupports.cmake" + "cmake/register_rs.cmake" +) + +install(DIRECTORY cmake + DESTINATION share/${PROJECT_NAME}) +ament_register_extension( + "rosidl_generate_interfaces" + "rosidl_generator_rs" + "${PROJECT_SOURCE_DIR}/cmake/rosidl_generator_rs_generate_interfaces.cmake") + install( PROGRAMS bin/rosidl_generator_rs DESTINATION lib/rosidl_generator_rs ) - install( DIRECTORY cmake resource DESTINATION share/${PROJECT_NAME} ) - -ament_package( - CONFIG_EXTRAS "cmake/rosidl_generator_rs_get_typesupports.cmake" - "cmake/register_rs.cmake" - "rosidl_generator_rs-extras.cmake.in" -) diff --git a/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake b/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake index 82541e451..40795ae86 100644 --- a/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake +++ b/rosidl_generator_rs/cmake/rosidl_generator_rs_generate_interfaces.cmake @@ -12,10 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -find_package(ament_cmake_export_crates REQUIRED) -find_package(rosidl_generator_c REQUIRED) find_package(rmw_implementation_cmake REQUIRED) find_package(rmw REQUIRED) +find_package(ament_cmake_export_crates REQUIRED) find_package(rclrs_common REQUIRED) if(NOT WIN32) @@ -57,8 +56,13 @@ foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES}) if(_parent_folder STREQUAL "msg") set(_has_msg TRUE) + set(_idl_file_without_actions ${_idl_file_without_actions} ${_idl_file}) elseif(_parent_folder STREQUAL "srv") set(_has_srv TRUE) + set(_idl_file_without_actions ${_idl_file_without_actions} ${_idl_file}) + elseif(_parent_folder STREQUAL "action") + set(_has_action TRUE) + message(WARNING "Rust actions generation is not implemented") else() message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") endif() @@ -108,7 +112,7 @@ set(target_dependencies "${rosidl_generator_rs_TEMPLATE_DIR}/srv.c.em" "${rosidl_generator_rs_TEMPLATE_DIR}/msg.rs.em" "${rosidl_generator_rs_TEMPLATE_DIR}/srv.rs.em" - ${rosidl_generate_interfaces_IDL_FILES} + ${_idl_file_without_actions} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}") @@ -116,11 +120,11 @@ foreach(dep ${target_dependencies}) endif() endforeach() -set(generator_arguments_file "${CMAKE_BINARY_DIR}/rosidl_generator_rs__arguments.json") +set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_rs__arguments.json") rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}" + ROS_INTERFACE_FILES "${_idl_file_without_actions}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_generator_rs_TEMPLATE_DIR}" @@ -199,7 +203,7 @@ foreach(_typesupport_impl ${_typesupport_impls}) ${PROJECT_NAME}__${_typesupport_impl} ) rosidl_target_interfaces(${_target_name} - ${PROJECT_NAME} rosidl_typesupport_c) + ${rosidl_generate_interfaces_TARGET} rosidl_typesupport_c) target_include_directories(${_target_name} PUBLIC diff --git a/rosidl_generator_rs/package.xml b/rosidl_generator_rs/package.xml index c465681f0..d2813b540 100644 --- a/rosidl_generator_rs/package.xml +++ b/rosidl_generator_rs/package.xml @@ -1,6 +1,6 @@ - + rosidl_generator_rs 0.0.3 Generate the ROS interfaces in Rust. @@ -20,26 +20,19 @@ rosidl_typesupport_c rosidl_typesupport_interface - rmw_implementation - rmw_implementation_cmake - rosidl_generator_c + + rosidl_generator_c + rosidl_parser ament_cmake_gtest ament_lint_auto ament_lint_common - - rmw_implementation - rmw_implementation_cmake + rosidl_cmake rosidl_generator_c - rosidl_parser - rosidl_cmake - - rosidl_typesupport_c - rosidl_typesupport_connext_c - rosidl_typesupport_introspection_c - rosidl_typesupport_opensplice_c + rosidl_generator_packages + rosidl_runtime_packages ament_cmake diff --git a/rosidl_generator_rs/resource/Cargo.toml.in b/rosidl_generator_rs/resource/Cargo.toml.in index 55f1039e3..3a634a48b 100644 --- a/rosidl_generator_rs/resource/Cargo.toml.in +++ b/rosidl_generator_rs/resource/Cargo.toml.in @@ -1,6 +1,7 @@ [package] name = "@PROJECT_NAME@" version = "0.1.0" +edition = "2018" [dependencies] libc = "0.2" diff --git a/rosidl_generator_rs/resource/msg.c.em b/rosidl_generator_rs/resource/msg.c.em index 583cfa80f..7b1ce2c71 100644 --- a/rosidl_generator_rs/resource/msg.c.em +++ b/rosidl_generator_rs/resource/msg.c.em @@ -1,11 +1,5 @@ #include "rosidl_generator_c/message_type_support_struct.h" -#include "rosidl_generator_c/string.h" -#include "rosidl_generator_c/string_functions.h" - -#include "rosidl_generator_c/primitives_array.h" -#include "rosidl_generator_c/primitives_array_functions.h" - @[for subfolder, msg_spec in msg_specs]@ @{ type_name = msg_spec.base_type.type diff --git a/rosidl_generator_rs/rosidl_generator_rs-extras.cmake.in b/rosidl_generator_rs/rosidl_generator_rs-extras.cmake.in index fe75b9dc9..14ba02d9f 100644 --- a/rosidl_generator_rs/rosidl_generator_rs-extras.cmake.in +++ b/rosidl_generator_rs/rosidl_generator_rs-extras.cmake.in @@ -1,4 +1,5 @@ # generated from rosidl_generator_rs/rosidl_generator_rs-extras.cmake +find_package(rosidl_typesupport_c REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/register_rs.cmake") rosidl_generator_rs_extras( "${rosidl_generator_rs_DIR}/../../../lib/rosidl_generator_rs/rosidl_generator_rs" diff --git a/rosidl_typesupport_ros2_rust.patch b/rosidl_typesupport_ros2_rust.patch deleted file mode 100644 index 7528f747c..000000000 --- a/rosidl_typesupport_ros2_rust.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/rosidl_default_generators/CMakeLists.txt b/rosidl_default_generators/CMakeLists.txt -index d6fda02..f50198d 100644 ---- a/rosidl_default_generators/CMakeLists.txt -+++ b/rosidl_default_generators/CMakeLists.txt -@@ -9,6 +9,7 @@ ament_export_dependencies(rosidl_cmake) - ament_export_dependencies(rosidl_generator_c) - ament_export_dependencies(rosidl_generator_cpp) - ament_export_dependencies(rosidl_generator_py) -+ament_export_dependencies(rosidl_generator_rs) - - if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) -diff --git a/rosidl_default_generators/package.xml b/rosidl_default_generators/package.xml -index 2861acd..ed85d59 100644 ---- a/rosidl_default_generators/package.xml -+++ b/rosidl_default_generators/package.xml -@@ -14,6 +14,7 @@ - rosidl_generator_c - rosidl_generator_cpp - rosidl_generator_py -+ rosidl_generator_rs - - rosidl_typesupport_c - rosidl_typesupport_cpp