@@ -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,52 +161,77 @@ 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+ }
192187
188+ impl Rtc < NoEvents > {
189+ /// Creates a new `AMBA PL031 RTC` instance without any metric
190+ /// capabilities.
191+ pub fn new ( ) -> Self {
192+ Self :: from_state ( & RtcState :: default ( ) , NoEvents )
193+ }
194+ }
195+
196+ impl < EV : RtcEvents > Rtc < EV > {
197+ /// Creates a new `AMBA PL031 RTC` instance from a given `state` and invokes the `rtc_events`
198+ /// implementation of `RtcEvents` during operation.
199+ ///
200+ /// # Arguments
201+ /// * `state` - A reference to the state from which the `Rtc` is constructed.
202+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
203+ /// of failure or missed events in the RTC operation.
204+ pub fn from_state ( state : & RtcState , events : EV ) -> Self {
205+ Rtc {
206+ lr : state. lr ,
207+ offset : state. offset ,
208+ mr : state. mr ,
209+ imsc : state. imsc ,
210+ ris : state. ris ,
193211 // A struct implementing RtcEvents for tracking the occurrence of
194212 // significant events.
195- events : rtc_events,
213+ events,
214+ }
215+ }
216+
217+ /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
218+ /// implementation of `RtcEvents` during operation.
219+ ///
220+ /// # Arguments
221+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
222+ /// of failure or missed events in the RTC operation.
223+ pub fn with_events ( rtc_events : EV ) -> Self {
224+ Self :: from_state ( & RtcState :: default ( ) , rtc_events)
225+ }
226+
227+ /// Returns the state of the RTC.
228+ pub fn state ( & self ) -> RtcState {
229+ RtcState {
230+ lr : self . lr ,
231+ offset : self . offset ,
232+ mr : self . mr ,
233+ imsc : self . imsc ,
234+ ris : self . ris ,
196235 }
197236 }
198237
@@ -854,4 +893,53 @@ mod tests {
854893 assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855894 assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856895 }
896+
897+ #[ test]
898+ fn test_state ( ) {
899+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
900+ let mut rtc = Rtc :: with_events ( metrics) ;
901+ let mut data = [ 0 ; 4 ] ;
902+
903+ // Get the RTC value with a load register of 0 (the initial value).
904+ rtc. read ( RTCDR , & mut data) ;
905+ let first_read = u32:: from_le_bytes ( data) ;
906+
907+ // Increment LR and verify that the value was updated.
908+ let lr = get_current_time ( ) + 100 ;
909+ data = lr. to_le_bytes ( ) ;
910+ rtc. write ( RTCLR , & data) ;
911+
912+ let state = rtc. state ( ) ;
913+ rtc. read ( RTCLR , & mut data) ;
914+ assert_eq ! ( state. lr. to_le_bytes( ) , data) ;
915+
916+ // Do an invalid `write` in order to increment a metric.
917+ let mut data2 = 123u32 . to_le_bytes ( ) ;
918+ rtc. write ( AMBA_ID_HIGH + 4 , & data2) ;
919+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
920+
921+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
922+ let mut rtc_from_state = Rtc :: from_state ( & state, metrics) ;
923+ let state_after_restore = rtc_from_state. state ( ) ;
924+
925+ // Check that the old and the new state are identical.
926+ assert_eq ! ( state. lr, state_after_restore. lr) ;
927+ assert_eq ! ( state. ris, state_after_restore. ris) ;
928+ assert_eq ! ( state. imsc, state_after_restore. imsc) ;
929+ assert_eq ! ( state. offset, state_after_restore. offset) ;
930+ assert_eq ! ( state. mr, state_after_restore. mr) ;
931+
932+ // Read the data register again.
933+ rtc. read ( RTCDR , & mut data) ;
934+ let second_read = u32:: from_le_bytes ( data) ;
935+ // The RTC values should be different.
936+ assert ! ( second_read > first_read) ;
937+
938+ // Reading from the LR register should return the same value as before saving the state.
939+ rtc_from_state. read ( RTCLR , & mut data2) ;
940+ assert_eq ! ( data, data2) ;
941+
942+ // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
943+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 0 ) ;
944+ }
857945}
0 commit comments