1use crate::api::raii::{Publisher, Service, Subscriber};
2use crate::api::resolve::get_unused_args;
3use crate::api::{Delay, Parameter, Rate, Ros, SystemState, Topic};
4use crate::error::{ErrorKind, Result};
5use crate::rosxmlrpc::Response;
6use crate::tcpros::{Client, Message, ServicePair, ServiceResult};
7use crate::util::FAILED_TO_LOCK;
8use crate::{RawMessageDescription, SubscriptionHandler};
9use crossbeam::sync::ShardedLock;
10use ctrlc;
11use error_chain::bail;
12use lazy_static::lazy_static;
13use ros_message::{Duration, Time};
14use std::collections::HashMap;
15use std::thread;
16use std::time;
17
18lazy_static! {
19 static ref ROS: ShardedLock<Option<Ros>> = ShardedLock::new(None);
20}
21
22#[inline]
23pub fn init(name: &str) {
24 try_init(name).expect("ROS init failed!");
25}
26
27#[inline]
28pub fn loop_init(name: &str, wait_millis: u64) {
29 loop {
30 if try_init(name).is_ok() {
31 break;
32 }
33 log::info!("roscore not found. Will retry until it becomes available...");
34 thread::sleep(std::time::Duration::from_millis(wait_millis));
35 }
36 log::info!("Connected to roscore");
37}
38
39#[inline]
40pub fn try_init(name: &str) -> Result<()> {
41 try_init_with_options(name, true)
42}
43
44pub fn try_init_with_options(name: &str, capture_sigint: bool) -> Result<()> {
45 let mut ros = ROS.write().expect(FAILED_TO_LOCK);
46 if ros.is_some() {
47 bail!(ErrorKind::MultipleInitialization);
48 }
49 let client = Ros::new(name)?;
50 if capture_sigint {
51 let shutdown_sender = client.shutdown_sender();
52 ctrlc::set_handler(move || {
53 shutdown_sender.shutdown();
54 })?;
55 }
56 *ros = Some(client);
57 Ok(())
58}
59
60pub fn is_initialized() -> bool {
61 ROS.read().expect(FAILED_TO_LOCK).is_some()
62}
63
64macro_rules! ros {
65 () => {
66 ROS.read()
67 .expect(FAILED_TO_LOCK)
68 .as_ref()
69 .expect(UNINITIALIZED)
70 };
71}
72
73#[inline]
74pub fn args() -> Vec<String> {
75 get_unused_args()
76}
77
78#[inline]
79pub fn uri() -> String {
80 ros!().uri().into()
81}
82
83#[inline]
84pub fn name() -> String {
85 ros!().name().into()
86}
87
88#[inline]
89pub fn hostname() -> String {
90 ros!().hostname().into()
91}
92
93#[inline]
94pub fn now() -> Time {
95 ros!().now()
96}
97
98#[inline]
99pub fn delay(d: Duration) -> Delay {
100 ros!().delay(d)
101}
102
103#[inline]
104pub fn sleep(d: Duration) {
105 delay(d).sleep();
106}
107
108#[inline]
109pub fn rate(rate: f64) -> Rate {
110 ros!().rate(rate)
111}
112
113#[inline]
114pub fn is_ok() -> bool {
115 ros!().is_ok()
116}
117
118#[inline]
119pub fn spin() {
120 let _spinner = { ros!().spin() };
122}
123
124#[inline]
125pub fn shutdown() {
126 ros!().shutdown_sender().shutdown()
127}
128
129#[inline]
130pub fn param(name: &str) -> Option<Parameter> {
131 ros!().param(name)
132}
133
134#[inline]
135pub fn parameters() -> Response<Vec<String>> {
136 ros!().parameters()
137}
138
139#[inline]
140pub fn state() -> Response<SystemState> {
141 ros!().state()
142}
143
144#[inline]
145pub fn topics() -> Response<Vec<Topic>> {
146 ros!().topics()
147}
148
149#[inline]
150pub fn client<T: ServicePair>(service: &str) -> Result<Client<T>> {
151 ros!().client::<T>(service)
152}
153
154#[inline]
155pub fn wait_for_service(service: &str, timeout: Option<time::Duration>) -> Result<()> {
156 ros!().wait_for_service(service, timeout)
157}
158
159#[inline]
160pub fn service<T, F>(service: &str, handler: F) -> Result<Service>
161where
162 T: ServicePair,
163 F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
164{
165 ros!().service::<T, F>(service, handler)
166}
167
168#[inline]
169pub fn subscribe<T, F>(topic: &str, queue_size: usize, callback: F) -> Result<Subscriber>
170where
171 T: Message,
172 F: Fn(T) + Send + 'static,
173{
174 ros!().subscribe::<T, F>(topic, queue_size, callback)
175}
176
177#[inline]
178pub fn subscribe_with_ids<T, F>(topic: &str, queue_size: usize, callback: F) -> Result<Subscriber>
179where
180 T: Message,
181 F: Fn(T, &str) + Send + 'static,
182{
183 ros!().subscribe_with_ids::<T, F>(topic, queue_size, callback)
184}
185
186#[inline]
187pub fn subscribe_with_ids_and_headers<T, F, G>(
188 topic: &str,
189 queue_size: usize,
190 on_message: F,
191 on_connect: G,
192) -> Result<Subscriber>
193where
194 T: Message,
195 F: Fn(T, &str) + Send + 'static,
196 G: Fn(HashMap<String, String>) + Send + 'static,
197{
198 ros!().subscribe_with_ids_and_headers::<T, F, G>(topic, queue_size, on_message, on_connect)
199}
200
201#[inline]
202pub fn subscribe_with<T, H>(topic: &str, queue_size: usize, handler: H) -> Result<Subscriber>
203where
204 T: Message,
205 H: SubscriptionHandler<T>,
206{
207 ros!().subscribe_with::<T, H>(topic, queue_size, handler)
208}
209
210#[inline]
211pub fn publish<T>(topic: &str, queue_size: usize) -> Result<Publisher<T>>
212where
213 T: Message,
214{
215 ros!().publish::<T>(topic, queue_size)
216}
217
218#[inline]
219pub fn publish_with_description<T>(
220 topic: &str,
221 queue_size: usize,
222 message_description: RawMessageDescription,
223) -> Result<Publisher<T>>
224where
225 T: Message,
226{
227 ros!().publish_with_description::<T>(topic, queue_size, message_description)
228}
229
230#[inline]
231pub fn log(level: i8, msg: String, file: &str, line: u32) {
232 ros!().log(level, msg, file, line)
233}
234
235#[inline]
236pub fn log_once(level: i8, msg: String, file: &str, line: u32) {
237 ros!().log_once(level, msg, file, line)
238}
239
240#[inline]
241pub fn log_throttle(period: f64, level: i8, msg: String, file: &str, line: u32) {
242 ros!().log_throttle(period, level, msg, file, line)
243}
244
245#[inline]
246pub fn log_throttle_identical(period: f64, level: i8, msg: String, file: &str, line: u32) {
247 ros!().log_throttle_identical(period, level, msg, file, line)
248}
249
250static UNINITIALIZED: &str = "ROS uninitialized. Please run ros::init(name) first!";