@@ -134,6 +134,21 @@ pub struct Rtc<EV: RtcEvents> {
134
134
events : EV ,
135
135
}
136
136
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
+
137
152
fn get_current_time ( ) -> u32 {
138
153
let epoch_time = SystemTime :: now ( )
139
154
. duration_since ( UNIX_EPOCH )
@@ -147,55 +162,82 @@ fn get_current_time() -> u32 {
147
162
epoch_time. as_secs ( ) as u32
148
163
}
149
164
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
-
163
165
impl Default for Rtc < NoEvents > {
164
166
fn default ( ) -> Self {
165
167
Self :: new ( )
166
168
}
167
169
}
168
170
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 {
178
175
// The load register is initialized to 0.
179
176
lr : 0 ,
180
-
181
177
offset : 0 ,
182
-
183
178
// The match register is initialised to zero (not currently used).
184
179
// TODO: Implement the match register functionality.
185
180
mr : 0 ,
186
-
187
181
// The interrupt mask is initialised as not set.
188
182
imsc : 0 ,
189
-
190
183
// The raw interrupt is initialised as not asserted.
191
184
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
+ }
192
196
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
194
215
// significant events.
195
216
events : rtc_events,
196
217
}
197
218
}
198
219
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
+
199
241
/// Provides a reference to the RTC events object.
200
242
pub fn events ( & self ) -> & EV {
201
243
& self . events
@@ -854,4 +896,63 @@ mod tests {
854
896
assert_eq ! ( rtc. events. invalid_read_count. count( ) , 2 ) ;
855
897
assert_eq ! ( rtc. events. invalid_write_count. count( ) , 0 ) ;
856
898
}
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
+ }
857
958
}
0 commit comments