Skip to content

Commit 86867ec

Browse files
authored
Make rclrs no_std compatible (#60)
* Convert error to mostly c-style enums Implement display for result code Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Remove unused imports Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Re-implement `to_rcl_result` Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Initial transcription of `context` Note: no default implementation due to `no_std` lacking environment variable support... Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Forgot to include custom Mutex (Spinlock) Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Fix missing dependencies Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Fix more missing dependencies Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Generate `no_std` compatible bindings Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * First working version of `no_std` code Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Quick `cargo fmt` run Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]> * Replace custom spinlock with `spin` crate. Also enable a "std" feature for compilation. Distro A, OPSEC #4584. You may have additional rights; please see https://rosmilitary.org/faq/?category=ros-2-license Signed-off-by: Jacob Hassold <[email protected]>
1 parent a9e817c commit 86867ec

File tree

14 files changed

+1238
-205
lines changed

14 files changed

+1238
-205
lines changed

rclrs/Cargo.toml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@ authors = ["Esteve Fernandez <[email protected]>"]
55
edition = "2018"
66

77
[dependencies]
8-
anyhow = {version = "1", features = ["backtrace"]}
98
libc = "0.2.43"
10-
parking_lot = "0.11"
11-
thiserror = "1"
9+
lock_api = "0.4.5"
10+
cstr_core = "0.2"
11+
cty = "0.2"
12+
core-error = "0.0.0"
13+
parking_lot = {version = "0.11.2", optional = true}
14+
spin = "0.9.2"
1215

1316
[build-dependencies]
14-
bindgen = "0.59.1"
17+
bindgen = "0.59.1"
18+
19+
[features]
20+
default = ["std"]
21+
std = ["parking_lot"]

rclrs/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::path::PathBuf;
66
fn main() {
77
let mut builder = bindgen::Builder::default()
88
.header("src/rcl_wrapper.h")
9+
.use_core()
10+
.ctypes_prefix("cty")
911
.derive_copy(false)
1012
.size_t_is_usize(true)
1113
.default_enum_style(bindgen::EnumVariation::Rust {

rclrs/src/context.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use crate::error::ToResult;
22
use crate::rcl_bindings::*;
33
use crate::Node;
4+
use alloc::sync::Arc;
5+
use alloc::vec::Vec;
6+
use cstr_core::{c_char, CString};
7+
use rclrs_common::error::RclReturnCode;
8+
9+
#[cfg(not(feature = "std"))]
10+
use spin::{Mutex, MutexGuard};
11+
12+
#[cfg(feature = "std")]
413
use parking_lot::{Mutex, MutexGuard};
5-
use rclrs_common::error::RclError;
6-
use std::env;
7-
use std::ffi::CString;
8-
use std::os::raw::c_char;
9-
use std::sync::Arc;
1014

1115
pub struct ContextHandle(Mutex<rcl_context_t>);
1216

@@ -37,12 +41,8 @@ pub struct Context {
3741
}
3842

3943
impl Context {
40-
fn init(&self) -> Result<(), RclError> {
41-
let args: Vec<CString> = env::args()
42-
.filter_map(|arg| CString::new(arg).ok())
43-
.collect();
44-
45-
let c_args: Vec<*const c_char> = args.iter().map(|arg| arg.as_ptr()).collect();
44+
fn init(&self, context_env_args: Vec<CString>) -> Result<(), RclReturnCode> {
45+
let c_args: Vec<*const c_char> = context_env_args.iter().map(|arg| arg.as_ptr()).collect();
4646
let handle = &mut *self.handle.lock();
4747

4848
unsafe {
@@ -62,24 +62,22 @@ impl Context {
6262
Ok(())
6363
}
6464

65-
pub fn ok(&self) -> Result<bool, RclError> {
66-
let handle = &mut *self.handle.lock();
67-
unsafe { Ok(rcl_context_is_valid(handle as *mut _)) }
68-
}
69-
70-
pub fn create_node(&self, node_name: &str) -> Result<Node, RclError> {
71-
Ok(Node::new(node_name, self)?)
72-
}
73-
}
74-
75-
impl Default for Context {
76-
fn default() -> Self {
65+
pub fn default(args: Vec<CString>) -> Self {
7766
let context = Self {
7867
handle: Arc::new(ContextHandle(Mutex::new(unsafe {
7968
rcl_get_zero_initialized_context()
8069
}))),
8170
};
82-
context.init().unwrap();
71+
context.init(args).unwrap(); // If we can't initialize the context, ROS 2 cannot function
8372
context
8473
}
74+
75+
pub fn ok(&self) -> Result<bool, RclReturnCode> {
76+
let handle = &mut *self.handle.lock();
77+
unsafe { Ok(rcl_context_is_valid(handle as *mut _)) }
78+
}
79+
80+
pub fn create_node(&self, node_name: &str) -> Result<Node, RclReturnCode> {
81+
Ok(Node::new(node_name, self)?)
82+
}
8583
}

rclrs/src/error.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use crate::rcl_bindings::*;
2-
pub use rclrs_common::error::{to_rcl_result, RclError};
2+
pub use rclrs_common::error::{to_rcl_result, RclReturnCode};
33

44
pub(crate) trait ToResult {
5-
fn ok(&self) -> Result<(), RclError>;
5+
fn ok(&self) -> Result<(), RclReturnCode>;
66

77
fn unwrap(&self) {
88
self.ok().unwrap();
99
}
1010
}
1111

1212
impl ToResult for rcl_ret_t {
13-
fn ok(&self) -> Result<(), RclError> {
13+
fn ok(&self) -> Result<(), RclReturnCode> {
1414
to_rcl_result(*self as i32)
1515
}
1616
}

rclrs/src/lib.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1+
#![no_std]
2+
extern crate alloc;
3+
extern crate core_error;
4+
5+
#[cfg(feature = "std")]
6+
extern crate std;
7+
8+
#[cfg(feature = "std")]
9+
extern crate parking_lot;
10+
11+
#[cfg(not(feature = "std"))]
12+
extern crate spin;
13+
114
pub mod context;
215
pub mod error;
316
pub mod node;
417
pub mod qos;
18+
// pub mod spinlock;
519
pub mod wait;
620

721
mod rcl_bindings;
@@ -12,9 +26,8 @@ pub use self::node::*;
1226
pub use self::qos::*;
1327

1428
use self::rcl_bindings::*;
15-
use rclrs_common::error::WaitSetError;
16-
use std::ops::{Deref, DerefMut};
17-
use wait::WaitSet;
29+
use core::ops::{Deref, DerefMut};
30+
use wait::{WaitSet, WaitSetErrorResponse};
1831

1932
pub trait Handle<T> {
2033
type DerefT: Deref<Target = T>;
@@ -25,13 +38,12 @@ pub trait Handle<T> {
2538
}
2639

2740
/// Wrapper around [`spin_once`]
28-
pub fn spin<'node>(node: &'node node::Node) -> Result<(), WaitSetError> {
41+
pub fn spin<'node>(node: &'node node::Node) -> Result<(), WaitSetErrorResponse> {
2942
while unsafe { rcl_context_is_valid(&mut *node.context.lock() as *mut _) } {
3043
if let Some(error) = spin_once(node, 500).err() {
3144
match error {
32-
WaitSetError::DroppedSubscription | WaitSetError::RclError(RclError::Timeout) => {
33-
continue
34-
}
45+
WaitSetErrorResponse::DroppedSubscription
46+
| WaitSetErrorResponse::ReturnCode(RclReturnCode::Timeout) => continue,
3547
error => return Err(error),
3648
};
3749
}
@@ -77,7 +89,7 @@ pub fn spin<'node>(node: &'node node::Node) -> Result<(), WaitSetError> {
7789
/// +--------------------+
7890
///
7991
///
80-
pub fn spin_once<'node>(node: &'node Node, timeout: i64) -> Result<(), WaitSetError> {
92+
pub fn spin_once<'node>(node: &'node Node, timeout: i64) -> Result<(), WaitSetErrorResponse> {
8193
let number_of_subscriptions = node.subscriptions.len();
8294
let number_of_guard_conditions = 0;
8395
let number_of_timers = 0;
@@ -100,7 +112,7 @@ pub fn spin_once<'node>(node: &'node Node, timeout: i64) -> Result<(), WaitSetEr
100112
for subscription in &node.subscriptions {
101113
match wait_set.add_subscription(subscription) {
102114
Ok(()) => (),
103-
Err(WaitSetError::DroppedSubscription) => (),
115+
Err(WaitSetErrorResponse::DroppedSubscription) => (),
104116
Err(err) => return Err(err),
105117
};
106118
}

rclrs/src/node/mod.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1+
use alloc::{
2+
sync::{Arc, Weak},
3+
vec::Vec,
4+
};
5+
6+
use crate::error::ToResult;
17
use crate::qos::QoSProfile;
28
use crate::rcl_bindings::*;
3-
use crate::ToResult;
4-
use crate::{Context, ContextHandle};
5-
use rclrs_common::error::RclError;
6-
use std::ffi::CString;
7-
use std::sync::{Arc, Weak};
89

9-
use parking_lot::{Mutex, MutexGuard};
10+
use crate::{Context, ContextHandle};
11+
use cstr_core::CString;
12+
use rclrs_common::error::RclReturnCode;
1013

1114
pub mod publisher;
1215
pub use self::publisher::*;
1316
pub mod subscription;
1417
pub use self::subscription::*;
1518

19+
#[cfg(not(feature = "std"))]
20+
use spin::{Mutex, MutexGuard};
21+
22+
#[cfg(feature = "std")]
23+
use parking_lot::{Mutex, MutexGuard};
24+
1625
pub struct NodeHandle(Mutex<rcl_node_t>);
1726

1827
impl NodeHandle {
@@ -44,15 +53,15 @@ pub struct Node {
4453

4554
impl Node {
4655
#[allow(clippy::new_ret_no_self)]
47-
pub fn new<'ctxt>(node_name: &str, context: &Context) -> Result<Node, RclError> {
56+
pub fn new<'ctxt>(node_name: &str, context: &Context) -> Result<Node, RclReturnCode> {
4857
Self::new_with_namespace(node_name, "", context)
4958
}
5059

5160
pub fn new_with_namespace<'ctxt>(
5261
node_name: &str,
5362
node_ns: &str,
5463
context: &Context,
55-
) -> Result<Node, RclError> {
64+
) -> Result<Node, RclReturnCode> {
5665
let raw_node_name = CString::new(node_name).unwrap();
5766
let raw_node_ns = CString::new(node_ns).unwrap();
5867

@@ -76,7 +85,7 @@ impl Node {
7685
Ok(Node {
7786
handle,
7887
context: context.handle.clone(),
79-
subscriptions: vec![],
88+
subscriptions: alloc::vec![],
8089
})
8190
}
8291

@@ -85,7 +94,7 @@ impl Node {
8594
&self,
8695
topic: &str,
8796
qos: QoSProfile,
88-
) -> Result<Publisher<T>, RclError>
97+
) -> Result<Publisher<T>, RclReturnCode>
8998
where
9099
T: rclrs_common::traits::MessageDefinition<T>,
91100
{
@@ -98,7 +107,7 @@ impl Node {
98107
topic: &str,
99108
qos: QoSProfile,
100109
callback: F,
101-
) -> Result<Arc<Subscription<T>>, RclError>
110+
) -> Result<Arc<Subscription<T>>, RclReturnCode>
102111
where
103112
T: rclrs_common::traits::MessageDefinition<T> + Default,
104113
F: FnMut(&T) + Sized + 'static,

rclrs/src/node/publisher.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ use crate::error::ToResult;
22
use crate::qos::QoSProfile;
33
use crate::rcl_bindings::*;
44
use crate::{Node, NodeHandle};
5-
use rclrs_common::error::RclError;
6-
use std::borrow::Borrow;
7-
use std::ffi::CString;
8-
use std::marker::PhantomData;
9-
use std::sync::Arc;
5+
use alloc::sync::Arc;
6+
use core::borrow::Borrow;
7+
use core::marker::PhantomData;
8+
use cstr_core::CString;
9+
use rclrs_common::error::RclReturnCode;
1010

11+
#[cfg(not(feature = "std"))]
12+
use spin::{Mutex, MutexGuard};
13+
14+
#[cfg(feature = "std")]
1115
use parking_lot::{Mutex, MutexGuard};
1216

1317
pub struct PublisherHandle {
@@ -56,7 +60,7 @@ impl<T> Publisher<T>
5660
where
5761
T: rclrs_common::traits::MessageDefinition<T>,
5862
{
59-
pub fn new(node: &Node, topic: &str, qos: QoSProfile) -> Result<Self, RclError>
63+
pub fn new(node: &Node, topic: &str, qos: QoSProfile) -> Result<Self, RclReturnCode>
6064
where
6165
T: rclrs_common::traits::MessageDefinition<T>,
6266
{
@@ -90,14 +94,14 @@ where
9094
})
9195
}
9296

93-
pub fn publish(&self, message: &T) -> Result<(), RclError> {
97+
pub fn publish(&self, message: &T) -> Result<(), RclReturnCode> {
9498
let native_message_ptr = message.get_native_message();
9599
let handle = &mut *self.handle.lock();
96100
let ret = unsafe {
97101
rcl_publish(
98102
handle as *mut _,
99103
native_message_ptr as *mut _,
100-
std::ptr::null_mut(),
104+
core::ptr::null_mut(),
101105
)
102106
};
103107
message.destroy_native_message(native_message_ptr);

0 commit comments

Comments
 (0)