1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
45//! Provide multiple Timers on top of a single underlying Alarm.
67use core::cell::Cell;
8use core::cmp;
910use kernel::collections::list::{List, ListLink, ListNode};
11use kernel::hil::time::{self, Alarm, Ticks, Time, Timer};
12use kernel::utilities::cells::{NumericCellExt, OptionalCell};
13use kernel::ErrorCode;
1415use crate::virtualizers::virtual_alarm::VirtualMuxAlarm;
1617#[derive(Copy, Clone, Debug, PartialEq)]
18enum Mode {
19 Disabled,
20 OneShot,
21 Repeating,
22}
2324/// An object to multiplex multiple "virtual" timers over a single underlying alarm. A
25/// `VirtualTimer` is a node in a linked list of timers that share the same underlying alarm.
26pub struct VirtualTimer<'a, A: Alarm<'a>> {
27/// Underlying alarm which multiplexes all these virtual timers.
28mux: &'a MuxTimer<'a, A>,
29/// Reference time point when this timer was setup.
30when: Cell<A::Ticks>,
31/// Interval between events reported by this timer.
32interval: Cell<A::Ticks>,
33/// Current mode of this timer.
34mode: Cell<Mode>,
35/// Next timer in the list.
36next: ListLink<'a, VirtualTimer<'a, A>>,
37/// Timer client for this node in the list.
38client: OptionalCell<&'a dyn time::TimerClient>,
39}
4041impl<'a, A: Alarm<'a>> ListNode<'a, VirtualTimer<'a, A>> for VirtualTimer<'a, A> {
42fn next(&self) -> &'a ListLink<VirtualTimer<'a, A>> {
43&self.next
44 }
45}
4647impl<'a, A: Alarm<'a>> VirtualTimer<'a, A> {
48/// After calling new, always call setup()
49pub fn new(mux_timer: &'a MuxTimer<'a, A>) -> VirtualTimer<'a, A> {
50let zero = A::Ticks::from(0);
51let v = VirtualTimer {
52 mux: mux_timer,
53 when: Cell::new(zero),
54 interval: Cell::new(zero),
55 mode: Cell::new(Mode::Disabled),
56 next: ListLink::empty(),
57 client: OptionalCell::empty(),
58 };
59 v
60 }
6162/// Call this method immediately after new() to link this to the mux, otherwise timers won't
63 /// fire
64pub fn setup(&'a self) {
65self.mux.timers.push_head(self);
66 }
6768// Start a new timer, configuring its mode and adjusting the underlying alarm if needed.
69fn start_timer(&self, interval: A::Ticks, mode: Mode) -> A::Ticks {
70if self.mode.get() == Mode::Disabled {
71self.mux.enabled.increment();
72 }
73self.mode.set(mode);
7475// We can't fire faster than the minimum dt of the alarm.
76let real_interval: A::Ticks = A::Ticks::from(cmp::max(
77 interval.into_u32(),
78self.mux.alarm.minimum_dt().into_u32(),
79 ));
8081let now = self.mux.alarm.now();
82self.interval.set(real_interval);
83self.when.set(now.wrapping_add(real_interval));
84self.mux.calculate_alarm(now, real_interval);
8586 real_interval
87 }
88}
8990impl<'a, A: Alarm<'a>> Time for VirtualTimer<'a, A> {
91type Frequency = A::Frequency;
92type Ticks = A::Ticks;
9394fn now(&self) -> A::Ticks {
95self.mux.alarm.now()
96 }
97}
9899impl<'a, A: Alarm<'a>> Timer<'a> for VirtualTimer<'a, A> {
100fn set_timer_client(&self, client: &'a dyn time::TimerClient) {
101self.client.set(client);
102 }
103104fn cancel(&self) -> Result<(), ErrorCode> {
105match self.mode.get() {
106 Mode::Disabled => Ok(()),
107 Mode::OneShot | Mode::Repeating => {
108self.mode.set(Mode::Disabled);
109self.mux.enabled.decrement();
110111// If there are not more enabled timers, disable the
112 // underlying alarm.
113if self.mux.enabled.get() == 0 {
114let _ = self.mux.alarm.disarm();
115 }
116Ok(())
117 }
118 }
119 }
120121fn interval(&self) -> Option<Self::Ticks> {
122match self.mode.get() {
123 Mode::Disabled => None,
124 Mode::OneShot | Mode::Repeating => Some(self.interval.get()),
125 }
126 }
127128fn is_oneshot(&self) -> bool {
129self.mode.get() == Mode::OneShot
130 }
131132fn is_repeating(&self) -> bool {
133self.mode.get() == Mode::Repeating
134 }
135136fn is_enabled(&self) -> bool {
137match self.mode.get() {
138 Mode::Disabled => false,
139 Mode::OneShot | Mode::Repeating => true,
140 }
141 }
142143fn oneshot(&self, interval: Self::Ticks) -> Self::Ticks {
144self.start_timer(interval, Mode::OneShot)
145 }
146147fn repeating(&self, interval: Self::Ticks) -> Self::Ticks {
148self.start_timer(interval, Mode::Repeating)
149 }
150151fn time_remaining(&self) -> Option<Self::Ticks> {
152match self.mode.get() {
153 Mode::Disabled => None,
154 Mode::OneShot | Mode::Repeating => {
155let when = self.when.get();
156let now = self.mux.alarm.now();
157Some(when.wrapping_sub(now))
158 }
159 }
160 }
161}
162163impl<'a, A: Alarm<'a>> time::AlarmClient for VirtualTimer<'a, A> {
164fn alarm(&self) {
165match self.mode.get() {
166 Mode::Disabled => {} // Do nothing
167Mode::OneShot => {
168self.mode.set(Mode::Disabled);
169self.client.map(|client| client.timer());
170 }
171 Mode::Repeating => {
172// By setting the 'now' to be 'when', this ensures
173 // the the repeating timer fires at a fixed interval:
174 // it'll fire at when + (k * interval), for k=0...n.
175let when = self.when.get();
176let interval = self.interval.get();
177self.when.set(when.wrapping_add(interval));
178self.mux.calculate_alarm(when, interval);
179self.client.map(|client| client.timer());
180 }
181 }
182 }
183}
184185/// Structure to control a set of virtual timers multiplexed together on top of a single alarm.
186pub struct MuxTimer<'a, A: Alarm<'a>> {
187/// Head of the linked list of virtual timers multiplexed together.
188timers: List<'a, VirtualTimer<'a, A>>,
189/// Number of virtual timers that are currently enabled.
190enabled: Cell<usize>,
191/// Underlying alarm, over which the virtual timers are multiplexed.
192alarm: &'a VirtualMuxAlarm<'a, A>,
193}
194195impl<'a, A: Alarm<'a>> MuxTimer<'a, A> {
196pub const fn new(alarm: &'a VirtualMuxAlarm<'a, A>) -> MuxTimer<'a, A> {
197 MuxTimer {
198 timers: List::new(),
199 enabled: Cell::new(0),
200 alarm,
201 }
202 }
203204fn calculate_alarm(&self, now: A::Ticks, interval: A::Ticks) {
205if self.enabled.get() == 1 {
206// First alarm, to just set it
207self.alarm.set_alarm(now, interval);
208 } else {
209// If the current alarm doesn't fall within the range of
210 // [now, now + interval), this means this new alarm
211 // will fire sooner. This covers the case when the current
212 // alarm is in the past, because it must have already fired
213 // and the bottom half is pending. -pal
214let cur_alarm = self.alarm.get_alarm();
215let when = now.wrapping_add(interval);
216if !cur_alarm.within_range(now, when) {
217// This alarm is earlier: reset alarm to it
218self.alarm.set_alarm(now, interval);
219 } else {
220// current alarm will fire earlier, keep it
221}
222 }
223 }
224}
225226impl<'a, A: Alarm<'a>> time::AlarmClient for MuxTimer<'a, A> {
227fn alarm(&self) {
228// The "now" is when the alarm fired, not the current
229 // time; this is case there was some delay. This also
230 // ensures that all other timers are >= now.
231let now = self.alarm.get_alarm();
232// Check whether to fire each timer. At this level, alarms are one-shot,
233 // so a repeating timer will reset its `when` in the alarm() callback.
234self.timers
235 .iter()
236 .filter(|cur| {
237 cur.is_enabled()
238 && !now.within_range(
239 cur.when.get().wrapping_sub(cur.interval.get()),
240 cur.when.get(),
241 )
242 })
243 .for_each(|cur| {
244 cur.alarm();
245 });
246247// Find the soonest alarm client (if any) and set the "next" underlying
248 // alarm based on it. This needs to happen after firing all expired
249 // alarms since those may have reset new alarms.
250let next = self
251.timers
252 .iter()
253 .filter(|cur| cur.is_enabled())
254 .min_by_key(|cur| cur.when.get().wrapping_sub(now).into_u32());
255256// Set the alarm.
257if let Some(valrm) = next {
258self.alarm
259 .set_alarm(now, valrm.when.get().wrapping_sub(now));
260 } else {
261let _ = self.alarm.disarm();
262 }
263 }
264}