@@ -134,6 +134,21 @@ pub struct Rtc<EV: RtcEvents> {
134134 events : EV ,
135135}
136136
137+ /// The state of the Rtc device.
138+ #[ derive( Clone , Debug , PartialEq ) ]
139+ pub struct RtcState {
140+ /// The load register.
141+ pub lr : u32 ,
142+ /// The offset applied to the counter to get the RTC value.
143+ pub offset : i64 ,
144+ /// The MR register.
145+ pub mr : u32 ,
146+ /// The interrupt mask.
147+ pub imsc : u32 ,
148+ /// The raw interrupt value.
149+ pub ris : u32 ,
150+ }
151+
137152fn get_current_time ( ) -> u32 {
138153 let epoch_time = SystemTime :: now ( )
139154 . duration_since ( UNIX_EPOCH )
@@ -147,55 +162,82 @@ fn get_current_time() -> u32 {
147162 epoch_time. as_secs ( ) as u32
148163}
149164
150- impl Rtc < NoEvents > {
151- /// Creates a new `AMBA PL031 RTC` instance without any metric
152- /// capabilities.
153- ///
154- /// # Example
155- ///
156- /// You can see an example of how to use this function in the
157- /// [`Example` section from `Rtc`](struct.Rtc.html#example).
158- pub fn new ( ) -> Rtc < NoEvents > {
159- Self :: with_events ( NoEvents )
160- }
161- }
162-
163165impl Default for Rtc < NoEvents > {
164166 fn default ( ) -> Self {
165167 Self :: new ( )
166168 }
167169}
168170
169- impl < EV : RtcEvents > Rtc < EV > {
170- /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
171- /// implementation of `RtcEvents` during operation.
172- ///
173- /// # Arguments
174- /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
175- /// of failure or missed events in the RTC operation.
176- pub fn with_events ( rtc_events : EV ) -> Self {
177- Rtc {
171+ // This is the state from which a fresh Rtc can be created.
172+ impl Default for RtcState {
173+ fn default ( ) -> Self {
174+ RtcState {
178175 // The load register is initialized to 0.
179176 lr : 0 ,
180-
181177 offset : 0 ,
182-
183178 // The match register is initialised to zero (not currently used).
184179 // TODO: Implement the match register functionality.
185180 mr : 0 ,
186-
187181 // The interrupt mask is initialised as not set.
188182 imsc : 0 ,
189-
190183 // The raw interrupt is initialised as not asserted.
191184 ris : 0 ,
185+ }
186+ }
187+ }
188+
189+ impl Rtc < NoEvents > {
190+ /// Creates a new `AMBA PL031 RTC` instance without any metric capabilities. The instance is
191+ /// created from the default state.
192+ pub fn new ( ) -> Self {
193+ Self :: from_state ( & RtcState :: default ( ) , NoEvents )
194+ }
195+ }
192196
193- // A struct implementing RtcEvents for tracking the occurrence of
197+ impl < EV : RtcEvents > Rtc < EV > {
198+ /// Creates a new `AMBA PL031 RTC` instance from a given `state` and that is able to track
199+ /// events during operation using the passed `rtc_events` object.
200+ /// For creating the instance from a fresh state, [`with_events`](#method.with_events) or
201+ /// [`new`](#method.new) methods can be used.
202+ ///
203+ /// # Arguments
204+ /// * `state` - A reference to the state from which the `Rtc` is constructed.
205+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
206+ /// of failure or missed events in the RTC operation.
207+ pub fn from_state ( state : & RtcState , rtc_events : EV ) -> Self {
208+ Rtc {
209+ lr : state. lr ,
210+ offset : state. offset ,
211+ mr : state. mr ,
212+ imsc : state. imsc ,
213+ ris : state. ris ,
214+ // A struct implementing `RtcEvents` for tracking the occurrence of
194215 // significant events.
195216 events : rtc_events,
196217 }
197218 }
198219
220+ /// Creates a new `AMBA PL031 RTC` instance that is able to track events during operation using
221+ /// the passed `rtc_events` object. The instance is created from the default state.
222+ ///
223+ /// # Arguments
224+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
225+ /// of failure or missed events in the RTC operation.
226+ pub fn with_events ( rtc_events : EV ) -> Self {
227+ Self :: from_state ( & RtcState :: default ( ) , rtc_events)
228+ }
229+
230+ /// Returns the state of the RTC.
231+ pub fn state ( & self ) -> RtcState {
232+ RtcState {
233+ lr : self . lr ,
234+ offset : self . offset ,
235+ mr : self . mr ,
236+ imsc : self . imsc ,
237+ ris : self . ris ,
238+ }
239+ }
240+
199241 /// Provides a reference to the RTC events object.
200242 pub fn events ( & self ) -> & EV {
201243 & self . events
@@ -854,4 +896,63 @@ mod tests {
854896 assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855897 assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856898 }
899+
900+ #[ test]
901+ fn test_state ( ) {
902+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
903+ let mut rtc = Rtc :: with_events ( metrics) ;
904+ let mut data = [ 0 ; 4 ] ;
905+
906+ // Get the RTC value with a load register of 0 (the initial value).
907+ rtc. read ( RTCDR , & mut data) ;
908+ let first_read = u32:: from_le_bytes ( data) ;
909+
910+ // Increment LR and verify that the value was updated.
911+ let lr = get_current_time ( ) + 100 ;
912+ data = lr. to_le_bytes ( ) ;
913+ rtc. write ( RTCLR , & data) ;
914+
915+ let state = rtc. state ( ) ;
916+ rtc. read ( RTCLR , & mut data) ;
917+ assert_eq ! ( state. lr. to_le_bytes( ) , data) ;
918+
919+ // Do an invalid `write` in order to increment a metric.
920+ let mut data2 = 123u32 . to_le_bytes ( ) ;
921+ rtc. write ( AMBA_ID_HIGH + 4 , & data2) ;
922+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
923+
924+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
925+ let mut rtc_from_state = Rtc :: from_state ( & state, metrics. clone ( ) ) ;
926+ let state_after_restore = rtc_from_state. state ( ) ;
927+
928+ // Check that the old and the new state are identical.
929+ assert_eq ! ( state, state_after_restore) ;
930+
931+ // Read the data register again.
932+ rtc. read ( RTCDR , & mut data) ;
933+ let second_read = u32:: from_le_bytes ( data) ;
934+ // The RTC values should be different.
935+ assert ! ( second_read > first_read) ;
936+
937+ // Reading from the LR register should return the same value as before saving the state.
938+ rtc_from_state. read ( RTCLR , & mut data2) ;
939+ assert_eq ! ( data, data2) ;
940+
941+ // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
942+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 0 ) ;
943+
944+ // Let's increment again a metric, and this time save the state of events as well (separate
945+ // from the base state).
946+ // Do an invalid `write` in order to increment a metric.
947+ let data3 = 123u32 . to_le_bytes ( ) ;
948+ rtc_from_state. write ( AMBA_ID_HIGH + 4 , & data3) ;
949+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 1 ) ;
950+
951+ let state2 = rtc_from_state. state ( ) ;
952+ let metrics2 = metrics;
953+ let rtc = Rtc :: from_state ( & state2, metrics2) ;
954+
955+ // Check that the restored `Rtc` keeps the state of the old `metrics` object.
956+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
957+ }
857958}
0 commit comments