@@ -134,6 +134,21 @@ pub struct Rtc<EV: RtcEvents> {
134134 events : EV ,
135135}
136136
137+ /// RTC State.
138+ #[ derive( Default ) ]
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,52 +162,69 @@ 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
171+ impl Rtc < NoEvents > {
172+ /// Creates a new `AMBA PL031 RTC` instance without any metric
173+ /// capabilities.
174+ pub fn new ( ) -> Self {
175+ Self :: from_state ( & RtcState :: default ( ) , NoEvents )
176+ }
177+ }
178+
169179impl < EV : RtcEvents > Rtc < EV > {
170- /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
180+ /// Creates a new `AMBA PL031 RTC` instance from a given `state` and invokes the `rtc_events`
171181 /// implementation of `RtcEvents` during operation.
172182 ///
173183 /// # Arguments
184+ /// * `state` - A reference to the state from which the `Rtc` is constructed.
174185 /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
175186 /// of failure or missed events in the RTC operation.
176- pub fn with_events ( rtc_events : EV ) -> Self {
187+ pub fn from_state ( state : & RtcState , events : EV ) -> Self {
177188 Rtc {
178189 // The load register is initialized to 0.
179- lr : 0 ,
190+ lr : state . lr ,
180191
181- offset : 0 ,
192+ offset : state . offset ,
182193
183194 // The match register is initialised to zero (not currently used).
184195 // TODO: Implement the match register functionality.
185- mr : 0 ,
196+ mr : state . mr ,
186197
187198 // The interrupt mask is initialised as not set.
188- imsc : 0 ,
199+ imsc : state . imsc ,
189200
190201 // The raw interrupt is initialised as not asserted.
191- ris : 0 ,
202+ ris : state . ris ,
192203
193204 // A struct implementing RtcEvents for tracking the occurrence of
194205 // significant events.
195- events : rtc_events,
206+ events,
207+ }
208+ }
209+
210+ /// Creates a new `AMBA PL031 RTC` instance and invokes the `rtc_events`
211+ /// implementation of `RtcEvents` during operation.
212+ ///
213+ /// # Arguments
214+ /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence
215+ /// of failure or missed events in the RTC operation.
216+ pub fn with_events ( rtc_events : EV ) -> Self {
217+ Self :: from_state ( & RtcState :: default ( ) , rtc_events)
218+ }
219+
220+ /// Returns the state of the RTC.
221+ pub fn state ( & self ) -> RtcState {
222+ RtcState {
223+ lr : self . lr ,
224+ offset : self . offset ,
225+ mr : self . mr ,
226+ imsc : self . imsc ,
227+ ris : self . ris ,
196228 }
197229 }
198230
@@ -854,4 +886,53 @@ mod tests {
854886 assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855887 assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856888 }
889+
890+ #[ test]
891+ fn test_state ( ) {
892+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
893+ let mut rtc = Rtc :: with_events ( metrics) ;
894+ let mut data = [ 0 ; 4 ] ;
895+
896+ // Get the RTC value with a load register of 0 (the initial value).
897+ rtc. read ( RTCDR , & mut data) ;
898+ let first_read = u32:: from_le_bytes ( data) ;
899+
900+ // Increment LR and verify that the value was updated.
901+ let lr = get_current_time ( ) + 100 ;
902+ data = lr. to_le_bytes ( ) ;
903+ rtc. write ( RTCLR , & data) ;
904+
905+ let state = rtc. state ( ) ;
906+ rtc. read ( RTCLR , & mut data) ;
907+ assert_eq ! ( state. lr. to_le_bytes( ) , data) ;
908+
909+ // Do an invalid `write` in order to increment a metric.
910+ let mut data2 = 123u32 . to_le_bytes ( ) ;
911+ rtc. write ( AMBA_ID_HIGH + 4 , & data2) ;
912+ assert_eq ! ( rtc. events. invalid_write_count. count( ) , 1 ) ;
913+
914+ let metrics = Arc :: new ( ExampleRtcMetrics :: default ( ) ) ;
915+ let mut rtc_from_state = Rtc :: from_state ( & state, metrics) ;
916+ let state_after_restore = rtc_from_state. state ( ) ;
917+
918+ // Check that the old and the new state are identical.
919+ assert_eq ! ( state. lr, state_after_restore. lr) ;
920+ assert_eq ! ( state. ris, state_after_restore. ris) ;
921+ assert_eq ! ( state. imsc, state_after_restore. imsc) ;
922+ assert_eq ! ( state. offset, state_after_restore. offset) ;
923+ assert_eq ! ( state. mr, state_after_restore. mr) ;
924+
925+ // Read the data register again.
926+ rtc. read ( RTCDR , & mut data) ;
927+ let second_read = u32:: from_le_bytes ( data) ;
928+ // The RTC values should be different.
929+ assert ! ( second_read > first_read) ;
930+
931+ // Reading from the LR register should return the same value as before saving the state.
932+ rtc_from_state. read ( RTCLR , & mut data2) ;
933+ assert_eq ! ( data, data2) ;
934+
935+ // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object.
936+ assert_eq ! ( rtc_from_state. events. invalid_write_count. count( ) , 0 ) ;
937+ }
857938}
0 commit comments