safe_drive/node.rs
1//! Node of ROS2.
2//! Nodes can be create by `Context::create_node`.
3//!
4//! # Example
5//!
6//! ```
7//! use safe_drive::context::Context;
8//!
9//! // Create a context.
10//! let ctx = Context::new().unwrap();
11//!
12//! // Create a node.
13//! let node = ctx
14//! .create_node("node_rs", Some("namespace"), Default::default())
15//! .unwrap();
16//! ```
17
18use libc::atexit;
19
20use crate::{
21 context::{remove_context, Context},
22 error::{DynError, RCLResult},
23 helper::InitOnce,
24 msg::{ServiceMsg, TypeSupport},
25 parameter::ParameterServer,
26 qos, rcl,
27 service::{client::Client, server::Server},
28 topic::publisher::Publisher,
29 topic::subscriber::Subscriber,
30};
31use std::{ffi::CString, sync::Arc};
32
33static SET_ATEXIT: InitOnce = InitOnce::new();
34
35/// Node of ROS2.
36pub struct Node {
37 node: rcl::rcl_node_t,
38 init_param_server: InitOnce,
39 pub(crate) context: Arc<Context>,
40}
41
42impl Node {
43 pub(crate) fn new(
44 context: Arc<Context>,
45 name: &str,
46 namespace: Option<&str>,
47 options: NodeOptions,
48 ) -> RCLResult<Arc<Self>> {
49 let mut node = rcl::MTSafeFn::rcl_get_zero_initialized_node();
50
51 let name_c = CString::new(name).unwrap();
52 let namespace_c = CString::new(namespace.unwrap_or_default()).unwrap();
53
54 {
55 let guard = rcl::MT_UNSAFE_FN.lock();
56 guard.rcl_node_init(
57 &mut node,
58 name_c.as_ptr(),
59 namespace_c.as_ptr(),
60 unsafe { context.as_ptr_mut() },
61 options.as_ptr(),
62 )?;
63 }
64
65 // FastDDS uses atexit(3) to destroy resources when creating a node.
66 // Because of functions registed to atexit(3) will be invoked reverse order,
67 // remove_context() must be set here.
68 SET_ATEXIT.init(|| unsafe { atexit(remove_context) }, 0);
69
70 Ok(Arc::new(Node {
71 node,
72 init_param_server: InitOnce::new(),
73 context,
74 }))
75 }
76
77 pub(crate) fn as_ptr(&self) -> *const rcl::rcl_node_t {
78 &self.node
79 }
80
81 pub(crate) unsafe fn as_ptr_mut(&self) -> *mut rcl::rcl_node_t {
82 &self.node as *const _ as *mut _
83 }
84
85 pub fn get_name(&self) -> RCLResult<String> {
86 rcl::MTSafeFn::rcl_node_get_name(&self.node)
87 }
88
89 pub fn get_fully_qualified_name(&self) -> RCLResult<String> {
90 rcl::MTSafeFn::rcl_node_get_fully_qualified_name(&self.node)
91 }
92
93 pub fn get_namespace(&self) -> RCLResult<String> {
94 rcl::MTSafeFn::rcl_node_get_namespace(&self.node)
95 }
96
97 pub fn create_parameter_server(self: &Arc<Self>) -> Result<ParameterServer, DynError> {
98 self.init_param_server.init(
99 || ParameterServer::new(self.clone()),
100 Err("a parameter server has been already created".into()),
101 )
102 }
103
104 /// Create a publisher.
105 /// If `qos` is specified `None`,
106 /// the default profile is used.
107 ///
108 /// `T` is the type of messages the created publisher send.
109 ///
110 /// # Example
111 ///
112 /// ```
113 /// use safe_drive::{msg::common_interfaces::std_msgs, node::Node, topic::publisher::Publisher};
114 /// use std::sync::Arc;
115 ///
116 /// fn create_new_publisher(node: Arc<Node>) -> Publisher<std_msgs::msg::Bool> {
117 /// node.create_publisher("topic_name", None).unwrap()
118 /// }
119 /// ```
120 pub fn create_publisher<T: TypeSupport>(
121 self: &Arc<Self>,
122 topic_name: &str,
123 qos: Option<qos::Profile>,
124 ) -> RCLResult<Publisher<T>> {
125 Publisher::new(self.clone(), topic_name, qos)
126 }
127
128 /// Create a publisher.
129 /// If `qos` is specified `None`,
130 /// the default profile is used.
131 ///
132 /// `T` is the type of messages the created publisher send.
133 ///
134 /// This function is the same as `create_publisher` but it disables loaned message.
135 ///
136 /// # Example
137 ///
138 /// ```
139 /// use safe_drive::{msg::common_interfaces::std_msgs, node::Node, topic::publisher::Publisher};
140 /// use std::sync::Arc;
141 ///
142 /// fn create_publisher_disable_loaned_message(node: Arc<Node>) -> Publisher<std_msgs::msg::Bool> {
143 /// node.create_publisher_disable_loaned_message("topic_name", None).unwrap()
144 /// }
145 /// ```
146 pub fn create_publisher_disable_loaned_message<T: TypeSupport>(
147 self: &Arc<Self>,
148 topic_name: &str,
149 qos: Option<qos::Profile>,
150 ) -> RCLResult<Publisher<T>> {
151 Publisher::new_disable_loaned_message(self.clone(), topic_name, qos)
152 }
153
154 /// Create a subscriber.
155 /// If `qos` is specified `None`,
156 /// the default profile is used.
157 ///
158 /// `T` is the type of messages the created subscriber receive.
159 ///
160 /// # Example
161 ///
162 /// ```
163 /// use safe_drive::{msg::common_interfaces::std_msgs, node::Node, topic::subscriber::Subscriber};
164 /// use std::sync::Arc;
165 ///
166 /// fn create_new_subscriber(node: Arc<Node>) -> Subscriber<std_msgs::msg::Bool> {
167 /// node.create_subscriber("topic_name", None).unwrap()
168 /// }
169 /// ```
170 pub fn create_subscriber<T: TypeSupport>(
171 self: &Arc<Self>,
172 topic_name: &str,
173 qos: Option<qos::Profile>,
174 ) -> RCLResult<Subscriber<T>> {
175 Subscriber::new(self.clone(), topic_name, qos)
176 }
177
178 /// Create a subscriber.
179 /// If `qos` is specified `None`,
180 /// the default profile is used.
181 ///
182 /// `T` is the type of messages the created subscriber receive.
183 ///
184 /// # Example
185 ///
186 /// ```
187 /// use safe_drive::{msg::common_interfaces::std_msgs, node::Node, topic::subscriber::Subscriber};
188 /// use std::sync::Arc;
189 ///
190 /// fn create_subscriber_disable_loaned_message(node: Arc<Node>) -> Subscriber<std_msgs::msg::Bool> {
191 /// node.create_subscriber_disable_loaned_message("topic_name", None).unwrap()
192 /// }
193 /// ```
194 pub fn create_subscriber_disable_loaned_message<T: TypeSupport>(
195 self: &Arc<Self>,
196 topic_name: &str,
197 qos: Option<qos::Profile>,
198 ) -> RCLResult<Subscriber<T>> {
199 Subscriber::new_disable_loaned_message(self.clone(), topic_name, qos)
200 }
201
202 /// Create a server.
203 /// If `qos` is specified `None`,
204 /// the default profile is used.
205 ///
206 /// A server must receive `ServiceMsg::Request` and send `ServiceMsg::Response`.
207 ///
208 /// # Example
209 ///
210 /// ```
211 /// use safe_drive::{msg::common_interfaces::std_srvs, node::Node, service::server::Server};
212 /// use std::sync::Arc;
213 ///
214 /// fn create_new_server(node: Arc<Node>) -> Server<std_srvs::srv::Empty> {
215 /// node.create_server("service_name", None).unwrap()
216 /// }
217 /// ```
218 pub fn create_server<T: ServiceMsg>(
219 self: &Arc<Self>,
220 service_name: &str,
221 qos: Option<qos::Profile>,
222 ) -> RCLResult<Server<T>> {
223 Server::new(self.clone(), service_name, qos)
224 }
225
226 /// Create a client.
227 /// If `qos` is specified `None`,
228 /// the default profile is used.
229 ///
230 /// A client must send `ServiceMsg::Request` and receive `ServiceMsg::Response`.
231 ///
232 /// # Example
233 ///
234 /// ```
235 /// use safe_drive::{msg::common_interfaces::std_srvs, node::Node, service::client::Client};
236 /// use std::sync::Arc;
237 ///
238 /// fn create_new_client(node: Arc<Node>) -> Client<std_srvs::srv::Empty> {
239 /// node.create_client("service_name", None).unwrap()
240 /// }
241 /// ```
242 pub fn create_client<T: ServiceMsg>(
243 self: &Arc<Self>,
244 service_name: &str,
245 qos: Option<qos::Profile>,
246 ) -> RCLResult<Client<T>> {
247 Client::new(self.clone(), service_name, qos)
248 }
249}
250
251impl Drop for Node {
252 fn drop(&mut self) {
253 let guard = rcl::MT_UNSAFE_FN.lock();
254 let _ = guard.rcl_node_fini(&mut self.node);
255 }
256}
257
258/// Options for nodes.
259pub struct NodeOptions {
260 options: rcl::rcl_node_options_t,
261}
262
263impl Default for NodeOptions {
264 fn default() -> Self {
265 let options = rcl::MTSafeFn::rcl_node_get_default_options();
266 NodeOptions { options }
267 }
268}
269
270impl NodeOptions {
271 /// Create options to create a node
272 pub fn new() -> Self {
273 // TODO: allow setting options
274 Default::default()
275 }
276
277 pub(crate) fn as_ptr(&self) -> *const rcl::rcl_node_options_t {
278 &self.options
279 }
280}
281
282impl Drop for NodeOptions {
283 fn drop(&mut self) {
284 let guard = rcl::MT_UNSAFE_FN.lock();
285 let _ = guard.rcl_node_options_fini(&mut self.options);
286 }
287}
288
289unsafe impl Sync for Node {}
290unsafe impl Send for Node {}