1- use crate :: rcl_bindings:: * ;
21use crate :: {
32 clock:: { Clock , ClockType } ,
43 RclrsError ,
@@ -8,7 +7,9 @@ use rosgraph_msgs::msg::Clock as ClockMsg;
87use std:: fmt;
98use std:: sync:: { Arc , Mutex } ;
109
11- /// Time source for a node that subscribes to the /clock node, if the use_sim_time parameter is set
10+ /// Time source for a node that drives the attached clocks.
11+ /// If the node's `use_sim_time` parameter is set to `true`, the `TimeSource` will subscribe
12+ /// to the `/clock` topic and drive the attached clocks
1213pub struct TimeSource {
1314 _node : Arc < Node > ,
1415 _clocks : Arc < Mutex < Vec < Arc < Mutex < Clock > > > > > ,
@@ -21,6 +22,19 @@ pub struct TimeSource {
2122 _last_time_msg : Arc < Mutex < Option < ClockMsg > > > ,
2223}
2324
25+ /// A builder for creating a [`TimeSource`][1].
26+ ///
27+ /// The builder pattern allows selectively setting some fields, and leaving all others at their default values.
28+ /// This struct instance can be created via [`TimeSource::builder()`][2].
29+ ///
30+ /// The default values for optional fields are:
31+ /// - `clock_qos: QOS_PROFILE_CLOCK`[3]
32+ /// - `use_clock_thread: true`
33+ ///
34+ ///
35+ /// [1]: crate::TimeSource
36+ /// [2]: crate::TimeSource::builder
37+ /// [3]: crate::QOS_PROFILE_CLOCK
2438pub struct TimeSourceBuilder {
2539 node : Arc < Node > ,
2640 clock_qos : QoSProfile ,
@@ -29,6 +43,9 @@ pub struct TimeSourceBuilder {
2943}
3044
3145impl TimeSourceBuilder {
46+ /// Creates a builder for a time source that drives the given clock for the given node.
47+ /// The clock's ClockType must be set to `RosTime` to allow updates based on the `/clock`
48+ /// topic.
3249 pub fn new ( node : Arc < Node > , clock : Arc < Mutex < Clock > > ) -> Self {
3350 Self {
3451 node,
@@ -38,16 +55,22 @@ impl TimeSourceBuilder {
3855 }
3956 }
4057
58+ /// Sets the QoS for the `/clock` topic.
4159 pub fn clock_qos ( mut self , clock_qos : QoSProfile ) -> Self {
4260 self . clock_qos = clock_qos;
4361 self
4462 }
4563
64+ /// Sets use_clock_thread.
65+ ///
66+ /// If set to `true`, the clock callbacks will run in a separate thread.
67+ /// NOTE: Currently unimplemented
4668 pub fn use_clock_thread ( mut self , use_clock_thread : bool ) -> Self {
4769 self . use_clock_thread = use_clock_thread;
4870 self
4971 }
5072
73+ /// Builds the `TimeSource` and attaches the provided `Node` and `Clock`.
5174 pub fn build ( self ) -> TimeSource {
5275 let mut source = TimeSource {
5376 _node : self . node . clone ( ) ,
@@ -64,6 +87,7 @@ impl TimeSourceBuilder {
6487 }
6588}
6689
90+ #[ derive( Debug ) ]
6791pub struct ClockMismatchError ( ClockType ) ;
6892
6993impl fmt:: Display for ClockMismatchError {
@@ -77,6 +101,12 @@ impl fmt::Display for ClockMismatchError {
77101}
78102
79103impl TimeSource {
104+ /// Creates a new time source with default parameters.
105+ pub fn new ( node : Arc < Node > , clock : Arc < Mutex < Clock > > ) -> Self {
106+ TimeSourceBuilder :: new ( node, clock) . build ( )
107+ }
108+
109+ /// Attaches the given clock to the `TimeSource`, enabling the `TimeSource` to control it.
80110 pub fn attach_clock ( & self , clock : Arc < Mutex < Clock > > ) -> Result < ( ) , ClockMismatchError > {
81111 let clock_type = clock. clone ( ) . lock ( ) . unwrap ( ) . clock_type ( ) ;
82112 if !matches ! ( clock_type, ClockType :: RosTime ) && * self . _ros_time_active . lock ( ) . unwrap ( ) {
@@ -93,6 +123,7 @@ impl TimeSource {
93123 Ok ( ( ) )
94124 }
95125
126+ /// Detaches the given clock from the `TimeSource`.
96127 // TODO(luca) should we return a result to denote whether the clock was removed?
97128 pub fn detach_clock ( & self , clock : Arc < Mutex < Clock > > ) {
98129 self . _clocks
@@ -101,25 +132,19 @@ impl TimeSource {
101132 . retain ( |c| !Arc :: ptr_eq ( c, & clock) ) ;
102133 }
103134
135+ /// Attaches the given node to to the `TimeSource`, using its interface to read the
136+ /// `use_sim_time` parameter and create the clock subscription.
104137 pub fn attach_node ( & mut self , node : Arc < Node > ) -> Result < ( ) , RclrsError > {
105138 self . _node = node;
106- println ! ( "Checking for use sim time" ) ;
107139 // TODO*luca) REMOVE THIS
108- self . _clock_subscription = Some ( self . create_clock_sub ( ) ?) ;
109- self . set_ros_time ( true ) ;
140+ self . set_ros_time ( true ) ?;
110141 return Ok ( ( ) ) ;
111142
143+ // TODO(luca) register a parameter callback
112144 if let Some ( sim_param) = node. get_parameter ( "use_sim_time" ) {
113145 match sim_param {
114146 ParameterValue :: Bool ( val) => {
115- if val {
116- println ! ( "use sim time set" ) ;
117- self . _clock_subscription = Some ( self . create_clock_sub ( ) ?) ;
118- self . set_ros_time ( true ) ;
119- } else {
120- self . _clock_subscription = None ;
121- self . set_ros_time ( false ) ;
122- }
147+ self . set_ros_time ( val) ?;
123148 }
124149 // TODO(luca) more graceful error handling
125150 _ => panic ! ( "use_sim_time parameter must be boolean" ) ,
@@ -128,11 +153,20 @@ impl TimeSource {
128153 Ok ( ( ) )
129154 }
130155
131- fn set_ros_time ( & self , enable : bool ) {
132- * self . _ros_time_active . lock ( ) . unwrap ( ) = enable;
133- for clock in self . _clocks . lock ( ) . unwrap ( ) . iter ( ) {
134- clock. lock ( ) . unwrap ( ) . set_ros_time ( enable) ;
156+ fn set_ros_time ( & mut self , enable : bool ) -> Result < ( ) , RclrsError > {
157+ let mut ros_time_active = self . _ros_time_active . lock ( ) . unwrap ( ) ;
158+ if enable != * ros_time_active {
159+ * ros_time_active = enable;
160+ for clock in self . _clocks . lock ( ) . unwrap ( ) . iter ( ) {
161+ clock. lock ( ) . unwrap ( ) . set_ros_time ( enable) ;
162+ }
163+ if enable {
164+ self . _clock_subscription = Some ( self . create_clock_sub ( ) ?) ;
165+ } else {
166+ self . _clock_subscription = None ;
167+ }
135168 }
169+ Ok ( ( ) )
136170 }
137171
138172 fn update_clock ( clock : & Arc < Mutex < Clock > > , nanoseconds : i64 ) {
@@ -165,3 +199,20 @@ impl TimeSource {
165199 )
166200 }
167201}
202+
203+ #[ cfg( test) ]
204+ mod tests {
205+ use super :: * ;
206+ use crate :: create_node;
207+ use crate :: Context ;
208+
209+ #[ test]
210+ fn time_source_attach_clock ( ) {
211+ let clock = Arc :: new ( Mutex :: new ( Clock :: new ( ClockType :: RosTime ) . unwrap ( ) ) ) ;
212+ let node = create_node ( & Context :: new ( [ ] ) . unwrap ( ) , "test_node" ) . unwrap ( ) ;
213+ let time_source = TimeSource :: new ( node, clock) ;
214+ let clock = Arc :: new ( Mutex :: new ( Clock :: new ( ClockType :: RosTime ) . unwrap ( ) ) ) ;
215+ // Attaching additional clocks should be OK
216+ time_source. attach_clock ( clock) . unwrap ( ) ;
217+ }
218+ }
0 commit comments