@@ -134,6 +134,20 @@ pub struct Rtc<EV: RtcEvents> {
134134 events : EV ,
135135}
136136
137+ /// The state of the Rtc device.
138+ pub struct RtcState {
139+ /// The load register.
140+ pub lr : u32 ,
141+ /// The offset applied to the counter to get the RTC value.
142+ pub offset : i64 ,
143+ /// The MR register.
144+ pub mr : u32 ,
145+ /// The interrupt mask.
146+ pub imsc : u32 ,
147+ /// The raw interrupt value.
148+ pub ris : u32 ,
149+ }
150+
137151fn get_current_time ( ) -> u32 {
138152 let epoch_time = SystemTime :: now ( )
139153 . duration_since ( UNIX_EPOCH )
@@ -147,55 +161,82 @@ fn get_current_time() -> u32 {
147161 epoch_time. as_secs ( ) as u32
148162}
149163
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-
163164impl Default for Rtc < NoEvents > {
164165 fn default ( ) -> Self {
165166 Self :: new ( )
166167 }
167168}
168169
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 {
170+ // This is the state from which a fresh Rtc can be created.
171+ impl Default for RtcState {
172+ fn default ( ) -> Self {
173+ RtcState {
178174 // The load register is initialized to 0.
179175 lr : 0 ,
180-
181176 offset : 0 ,
182-
183177 // The match register is initialised to zero (not currently used).
184178 // TODO: Implement the match register functionality.
185179 mr : 0 ,
186-
187180 // The interrupt mask is initialised as not set.
188181 imsc : 0 ,
189-
190182 // The raw interrupt is initialised as not asserted.
191183 ris : 0 ,
184+ }
185+ }
186+ }
187+
188+ impl Rtc < NoEvents > {
189+ /// Creates a new `AMBA PL031 RTC` instance without any metric capabilities. The instance is
190+ /// created from the default state.
191+ pub fn new ( ) -> Self {
192+ Self :: from_state ( & RtcState :: default ( ) , NoEvents )
193+ }
194+ }
192195
193- // A struct implementing RtcEvents for tracking the occurrence of
196+ impl < EV : RtcEvents > Rtc < EV > {
197+ /// Creates a new `AMBA PL031 RTC` instance from a given `state` and that is able to track
198+ /// events during operation using the passed `rtc_events` object.
199+ /// For creating the instance from a fresh state, [`with_events`](#method.with_events) or
200+ /// [`new`](#method.new) methods can be used.
201+ ///
202+ /// # Arguments
203+ /// * `state` - A reference to the state from which the `Rtc` is constructed.
204+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
205+ /// of failure or missed events in the RTC operation.
206+ pub fn from_state ( state : & RtcState , rtc_events : EV ) -> Self {
207+ Rtc {
208+ lr : state. lr ,
209+ offset : state. offset ,
210+ mr : state. mr ,
211+ imsc : state. imsc ,
212+ ris : state. ris ,
213+ // A struct implementing `RtcEvents` for tracking the occurrence of
194214 // significant events.
195215 events : rtc_events,
196216 }
197217 }
198218
219+ /// Creates a new `AMBA PL031 RTC` instance that is able to track events during operation using
220+ /// the passed `rtc_events` object. The instance is created from the default state.
221+ ///
222+ /// # Arguments
223+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
224+ /// of failure or missed events in the RTC operation.
225+ pub fn with_events ( rtc_events : EV ) -> Self {
226+ Self :: from_state ( & RtcState :: default ( ) , rtc_events)
227+ }
228+
229+ /// Returns the state of the RTC.
230+ pub fn state ( & self ) -> RtcState {
231+ RtcState {
232+ lr : self . lr ,
233+ offset : self . offset ,
234+ mr : self . mr ,
235+ imsc : self . imsc ,
236+ ris : self . ris ,
237+ }
238+ }
239+
199240 /// Provides a reference to the RTC events object.
200241 pub fn events ( & self ) -> & EV {
201242 & self . events
@@ -854,4 +895,67 @@ mod tests {
854895 assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855896 assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856897 }
898+
899+ #[ test]
900+ fn test_state ( ) {
901+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
902+ let mut rtc = Rtc :: with_events ( metrics) ;
903+ let mut data = [ 0 ; 4 ] ;
904+
905+ // Get the RTC value with a load register of 0 (the initial value).
906+ rtc. read ( RTCDR , & mut data) ;
907+ let first_read = u32:: from_le_bytes ( data) ;
908+
909+ // Increment LR and verify that the value was updated.
910+ let lr = get_current_time ( ) + 100 ;
911+ data = lr. to_le_bytes ( ) ;
912+ rtc. write ( RTCLR , & data) ;
913+
914+ let state = rtc. state ( ) ;
915+ rtc. read ( RTCLR , & mut data) ;
916+ assert_eq ! ( state. lr. to_le_bytes( ) , data) ;
917+
918+ // Do an invalid `write` in order to increment a metric.
919+ let mut data2 = 123u32 . to_le_bytes ( ) ;
920+ rtc. write ( AMBA_ID_HIGH + 4 , & data2) ;
921+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
922+
923+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
924+ let mut rtc_from_state = Rtc :: from_state ( & state, metrics. clone ( ) ) ;
925+ let state_after_restore = rtc_from_state. state ( ) ;
926+
927+ // Check that the old and the new state are identical.
928+ assert_eq ! ( state. lr, state_after_restore. lr) ;
929+ assert_eq ! ( state. ris, state_after_restore. ris) ;
930+ assert_eq ! ( state. imsc, state_after_restore. imsc) ;
931+ assert_eq ! ( state. offset, state_after_restore. offset) ;
932+ assert_eq ! ( state. mr, state_after_restore. mr) ;
933+
934+ // Read the data register again.
935+ rtc. read ( RTCDR , & mut data) ;
936+ let second_read = u32:: from_le_bytes ( data) ;
937+ // The RTC values should be different.
938+ assert ! ( second_read > first_read) ;
939+
940+ // Reading from the LR register should return the same value as before saving the state.
941+ rtc_from_state. read ( RTCLR , & mut data2) ;
942+ assert_eq ! ( data, data2) ;
943+
944+ // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
945+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 0 ) ;
946+
947+ // Let's increment again a metric, and this time save the state of events as well (separate
948+ // from the base state).
949+ // Do an invalid `write` in order to increment a metric.
950+ let data3 = 123u32 . to_le_bytes ( ) ;
951+ rtc_from_state. write ( AMBA_ID_HIGH + 4 , & data3) ;
952+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 1 ) ;
953+
954+ let state2 = rtc_from_state. state ( ) ;
955+ let metrics2 = metrics;
956+ let rtc = Rtc :: from_state ( & state2, metrics2) ;
957+
958+ // Check that the restored `Rtc` keeps the state of the old `metrics` object.
959+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
960+ }
857961}
0 commit comments