Skip to content

Commit 0709ae9

Browse files
committed
depanic
1 parent 74e5a4d commit 0709ae9

File tree

2 files changed

+111
-56
lines changed

2 files changed

+111
-56
lines changed

time-alarm-service/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ impl Service {
205205

206206
// TODO [POWER_SOURCE] we need to subscribe to messages that tell us if we're on AC or DC power so we can decide which alarms to trigger, but those notifications are not yet implemented - revisit when they are.
207207
// TODO [POWER_SOURCE] if it's possible to learn which power source is active at init time, we should set that one active rather than defaulting to the AC timer.
208-
service.timers.ac_timer.start(&service.clock_state, true);
209-
service.timers.dc_timer.start(&service.clock_state, false);
208+
service.timers.ac_timer.start(&service.clock_state, true)?;
209+
service.timers.dc_timer.start(&service.clock_state, false)?;
210210

211211
comms::register_endpoint(service, &service.endpoint).await?;
212212

@@ -256,7 +256,8 @@ impl Service {
256256
// TODO [SPEC] section 9.18.7 indicates that when a timer expires, both timers have their wake policies reset,
257257
// but I can't find any similar rule for the actual timer value - that seems odd to me, verify that's actually how
258258
// it's supposed to work
259-
self.timers
259+
let _ = self
260+
.timers
260261
.get_timer(timer_id.get_other_timer_id())
261262
.set_timer_wake_policy(&self.clock_state, AlarmExpiredWakePolicy::NEVER);
262263

@@ -305,7 +306,7 @@ impl Service {
305306
AcpiTimeAlarmRequest::SetExpiredTimerPolicy(timer_id, timer_policy) => {
306307
self.timers
307308
.get_timer(timer_id)
308-
.set_timer_wake_policy(&self.clock_state, timer_policy);
309+
.set_timer_wake_policy(&self.clock_state, timer_policy)?;
309310
Ok(AcpiTimeAlarmResponse::OkNoData)
310311
}
311312
AcpiTimeAlarmRequest::SetTimerValue(timer_id, timer_value) => {
@@ -324,7 +325,7 @@ impl Service {
324325

325326
self.timers
326327
.get_timer(timer_id)
327-
.set_expiration_time(&self.clock_state, new_expiration_time);
328+
.set_expiration_time(&self.clock_state, new_expiration_time)?;
328329
Ok(AcpiTimeAlarmResponse::OkNoData)
329330
}
330331
AcpiTimeAlarmRequest::GetExpiredTimerPolicy(timer_id) => Ok(AcpiTimeAlarmResponse::WakePolicy(

time-alarm-service/src/timer.rs

Lines changed: 105 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::cell::RefCell;
33
use embassy_futures::select::{Either, select};
44
use embassy_sync::{blocking_mutex::Mutex, signal::Signal};
55
use embedded_mcu_hal::NvramStorage;
6-
use embedded_mcu_hal::time::Datetime;
6+
use embedded_mcu_hal::time::{Datetime, DatetimeClockError};
77
use embedded_services::{GlobalRawMutex, error};
88

99
/// Represents where in the timer lifecycle the current timer is
@@ -114,20 +114,26 @@ impl Timer {
114114
}
115115
}
116116

117-
pub fn start(&self, clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>, active: bool) {
117+
pub fn start(
118+
&self,
119+
clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>,
120+
active: bool,
121+
) -> Result<(), DatetimeClockError> {
118122
self.set_timer_wake_policy(
119123
clock_state,
120124
self.timer_state
121125
.lock(|timer_state| timer_state.borrow().persistent_storage.get_timer_wake_policy()),
122-
);
126+
)?;
123127

124128
self.set_expiration_time(
125129
clock_state,
126130
self.timer_state
127131
.lock(|timer_state| timer_state.borrow().persistent_storage.get_expiration_time()),
128-
);
132+
)?;
129133

130134
self.set_active(clock_state, active);
135+
136+
Ok(())
131137
}
132138

133139
pub fn get_wake_status(&self) -> TimerStatus {
@@ -153,24 +159,26 @@ impl Timer {
153159
&self,
154160
clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>,
155161
wake_policy: AlarmExpiredWakePolicy,
156-
) {
162+
) -> Result<(), DatetimeClockError> {
157163
self.timer_state.lock(|timer_state| {
158164
let mut timer_state = timer_state.borrow_mut();
159-
timer_state.persistent_storage.set_timer_wake_policy(wake_policy);
160-
161165
if let WakeState::ExpiredWaitingForPolicyDelay(_, _) = timer_state.wake_state {
162166
timer_state.wake_state =
163-
WakeState::ExpiredWaitingForPolicyDelay(Self::get_current_datetime(clock_state), 0);
167+
WakeState::ExpiredWaitingForPolicyDelay(Self::get_current_datetime(clock_state)?, 0);
164168
self.timer_signal.signal(Some(wake_policy.0));
165169
}
170+
171+
timer_state.persistent_storage.set_timer_wake_policy(wake_policy);
172+
173+
Ok(())
166174
})
167175
}
168176

169177
pub fn set_expiration_time(
170178
&self,
171179
clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>,
172180
expiration_time: Option<Datetime>,
173-
) {
181+
) -> Result<(), DatetimeClockError> {
174182
self.timer_state.lock(|timer_state| {
175183
let mut timer_state = timer_state.borrow_mut();
176184

@@ -179,19 +187,21 @@ impl Timer {
179187

180188
match expiration_time {
181189
Some(dt) => {
182-
timer_state.persistent_storage.set_expiration_time(expiration_time);
183-
timer_state.wake_state = WakeState::Armed;
184-
185190
// Note: If the expiration time was in the past, this will immediately trigger the timer to expire.
186191
self.timer_signal.signal(Some(
187192
dt.to_unix_time_seconds()
188-
.saturating_sub(Self::get_current_datetime(clock_state).to_unix_time_seconds())
193+
.saturating_sub(Self::get_current_datetime(clock_state)?.to_unix_time_seconds())
189194
as u32, // The ACPI spec doesn't provide a facility to program a timer more than u32::MAX seconds in the future, so this cast is safe
190195
));
196+
197+
timer_state.persistent_storage.set_expiration_time(expiration_time);
198+
timer_state.wake_state = WakeState::Armed;
191199
}
192200
None => self.clear_expiration_time(&mut timer_state),
193201
}
194-
});
202+
203+
Ok(())
204+
})
195205
}
196206

197207
pub fn get_expiration_time(&self) -> Option<Datetime> {
@@ -212,25 +222,54 @@ impl Timer {
212222

213223
if !was_active {
214224
if let WakeState::ExpiredWaitingForPowerSource(seconds_already_elapsed) = timer_state.wake_state {
215-
timer_state.wake_state = WakeState::ExpiredWaitingForPolicyDelay(
216-
Self::get_current_datetime(clock_state),
217-
seconds_already_elapsed,
218-
);
219-
self.timer_signal.signal(Some(
220-
timer_state
221-
.persistent_storage
222-
.get_timer_wake_policy()
223-
.0
224-
.saturating_sub(seconds_already_elapsed),
225-
));
225+
match Self::get_current_datetime(clock_state) {
226+
Ok(now) => {
227+
timer_state.wake_state =
228+
WakeState::ExpiredWaitingForPolicyDelay(now, seconds_already_elapsed);
229+
self.timer_signal.signal(Some(
230+
timer_state
231+
.persistent_storage
232+
.get_timer_wake_policy()
233+
.0
234+
.saturating_sub(seconds_already_elapsed),
235+
));
236+
}
237+
Err(_) => {
238+
// This should never happen, because it means the clock is not working after we've successfully initialized (which
239+
// requires the clock to be working).
240+
// If it does, though, we don't have a way to communicate failure to the host PC at this point, so we'll just
241+
// forego the power source policy and wake the device immediately.
242+
error!(
243+
"[Time/Alarm] Failed to get current datetime when transitioning timer to active state"
244+
);
245+
timer_state.wake_state = WakeState::Armed;
246+
self.timer_signal.signal(Some(0));
247+
}
248+
}
226249
}
227250
} else if let WakeState::ExpiredWaitingForPolicyDelay(wait_start_time, seconds_elapsed_before_wait) =
228251
timer_state.wake_state
229252
{
230-
let total_seconds_elapsed_on_policy_delay: u32 = seconds_elapsed_before_wait
231-
+ (Self::get_current_datetime(clock_state)
232-
.to_unix_time_seconds()
233-
.saturating_sub(wait_start_time.to_unix_time_seconds()) as u32); // The ACPI spec expresses timeouts in terms of u32s - it's impossible to schedule a timer u32::MAX seconds in the future
253+
let total_seconds_elapsed_on_policy_delay = match Self::get_current_datetime(clock_state) {
254+
Ok(now) => {
255+
seconds_elapsed_before_wait
256+
+ (now
257+
.to_unix_time_seconds()
258+
.saturating_sub(wait_start_time.to_unix_time_seconds())
259+
as u32) // The ACPI spec expresses timeouts in terms of u32s - it's impossible to schedule a timer u32::MAX seconds in the future
260+
}
261+
Err(_) => {
262+
// This should never happen, because it means the clock is not working after we've successfully initialized (which
263+
// requires the clock to be working).
264+
// If it does, though, we don't have a way to communicate failure to the host PC at this point, so we'll just
265+
// pretend that the entire policy delay has elapsed. This will trigger an immediate wake when the power source becomes active again.
266+
error!(
267+
"[Time/Alarm] Failed to get current datetime when transitioning expired timer waiting for policy delay to inactive state"
268+
);
269+
u32::MAX
270+
}
271+
};
272+
234273
timer_state.wake_state = WakeState::ExpiredWaitingForPowerSource(total_seconds_elapsed_on_policy_delay);
235274
self.timer_signal.signal(None);
236275
}
@@ -283,20 +322,39 @@ impl Timer {
283322
}
284323

285324
WakeState::Armed | WakeState::ExpiredWaitingForPolicyDelay(_, _) => {
286-
let now = Self::get_current_datetime(clock_state);
287-
let expiration_time = timer_state.persistent_storage.get_expiration_time().unwrap_or_else(|| {
288-
error!("[Time/Alarm] Timer expired when no expiration time was set - this should never happen");
289-
Datetime::from_unix_time_seconds(0)
290-
});
291-
if now.to_unix_time_seconds() < expiration_time.to_unix_time_seconds() {
292-
// Time hasn't actually passed the mark yet - this can happen if we were reprogrammed with a different time right as the old timer was expiring. Reset the timer.
293-
timer_state.wake_state = WakeState::Armed;
294-
self.timer_signal.signal(Some(
295-
expiration_time
296-
.to_unix_time_seconds()
297-
.saturating_sub(now.to_unix_time_seconds()) as u32,
298-
));
299-
return false;
325+
let expiration_time = match timer_state.persistent_storage.get_expiration_time() {
326+
Some(now) => now,
327+
None => {
328+
error!(
329+
"[Time/Alarm] Timer expired when no expiration time was set - this should never happen"
330+
);
331+
return false;
332+
}
333+
};
334+
335+
match Self::get_current_datetime(clock_state) {
336+
Ok(now) => {
337+
if now.to_unix_time_seconds() < expiration_time.to_unix_time_seconds() {
338+
// Time hasn't actually passed the mark yet - this can happen if we were reprogrammed with a different time right as the old timer was expiring. Reset the timer.
339+
timer_state.wake_state = WakeState::Armed;
340+
self.timer_signal.signal(Some(
341+
expiration_time
342+
.to_unix_time_seconds()
343+
.saturating_sub(now.to_unix_time_seconds())
344+
as u32,
345+
));
346+
return false;
347+
}
348+
}
349+
Err(_) => {
350+
// This should never happen, because it means the clock is not working after we've successfully initialized (which
351+
// requires the clock to be working).
352+
// If it does, though, we don't have a way to communicate failure to the host PC at this point, so we'll just
353+
// wake the device immediately on the assumption that the alarm has actually expired. This gets it wrong in the case
354+
// where the timer is reprogrammed immediately as it expires, but that's an extremely rare case and we can't do better
355+
// than that if our clock is broken.
356+
error!("[Time/Alarm] Failed to get current datetime when processing expired timer");
357+
}
300358
}
301359

302360
timer_state.timer_status.set_timer_expired(true);
@@ -334,13 +392,9 @@ impl Timer {
334392
self.timer_signal.signal(None);
335393
}
336394

337-
fn get_current_datetime(clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>) -> Datetime {
338-
clock_state.lock(|clock_state| {
339-
clock_state
340-
.borrow()
341-
.datetime_clock
342-
.get_current_datetime()
343-
.expect("Datetime clock should have already been initialized before we were constructed")
344-
})
395+
fn get_current_datetime(
396+
clock_state: &'static Mutex<GlobalRawMutex, RefCell<ClockState>>,
397+
) -> Result<Datetime, DatetimeClockError> {
398+
clock_state.lock(|clock_state| clock_state.borrow().datetime_clock.get_current_datetime())
345399
}
346400
}

0 commit comments

Comments
 (0)