capsules_core/virtualizers/
virtual_timer.rs

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.
4
5//! Provide multiple Timers on top of a single underlying Alarm.
6
7use core::cell::Cell;
8use core::cmp;
9
10use kernel::collections::list::{List, ListLink, ListNode};
11use kernel::hil::time::{self, Alarm, Ticks, Time, Timer};
12use kernel::utilities::cells::{NumericCellExt, OptionalCell};
13use kernel::ErrorCode;
14
15use crate::virtualizers::virtual_alarm::VirtualMuxAlarm;
16
17#[derive(Copy, Clone, Debug, PartialEq)]
18enum Mode {
19    Disabled,
20    OneShot,
21    Repeating,
22}
23
24/// 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.
28    mux: &'a MuxTimer<'a, A>,
29    /// Reference time point when this timer was setup.
30    when: Cell<A::Ticks>,
31    /// Interval between events reported by this timer.
32    interval: Cell<A::Ticks>,
33    /// Current mode of this timer.
34    mode: Cell<Mode>,
35    /// Next timer in the list.
36    next: ListLink<'a, VirtualTimer<'a, A>>,
37    /// Timer client for this node in the list.
38    client: OptionalCell<&'a dyn time::TimerClient>,
39}
40
41impl<'a, A: Alarm<'a>> ListNode<'a, VirtualTimer<'a, A>> for VirtualTimer<'a, A> {
42    fn next(&self) -> &'a ListLink<VirtualTimer<'a, A>> {
43        &self.next
44    }
45}
46
47impl<'a, A: Alarm<'a>> VirtualTimer<'a, A> {
48    /// After calling new, always call setup()
49    pub fn new(mux_timer: &'a MuxTimer<'a, A>) -> VirtualTimer<'a, A> {
50        let zero = A::Ticks::from(0);
51        let 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    }
61
62    /// Call this method immediately after new() to link this to the mux, otherwise timers won't
63    /// fire
64    pub fn setup(&'a self) {
65        self.mux.timers.push_head(self);
66    }
67
68    // Start a new timer, configuring its mode and adjusting the underlying alarm if needed.
69    fn start_timer(&self, interval: A::Ticks, mode: Mode) -> A::Ticks {
70        if self.mode.get() == Mode::Disabled {
71            self.mux.enabled.increment();
72        }
73        self.mode.set(mode);
74
75        // We can't fire faster than the minimum dt of the alarm.
76        let real_interval: A::Ticks = A::Ticks::from(cmp::max(
77            interval.into_u32(),
78            self.mux.alarm.minimum_dt().into_u32(),
79        ));
80
81        let now = self.mux.alarm.now();
82        self.interval.set(real_interval);
83        self.when.set(now.wrapping_add(real_interval));
84        self.mux.calculate_alarm(now, real_interval);
85
86        real_interval
87    }
88}
89
90impl<'a, A: Alarm<'a>> Time for VirtualTimer<'a, A> {
91    type Frequency = A::Frequency;
92    type Ticks = A::Ticks;
93
94    fn now(&self) -> A::Ticks {
95        self.mux.alarm.now()
96    }
97}
98
99impl<'a, A: Alarm<'a>> Timer<'a> for VirtualTimer<'a, A> {
100    fn set_timer_client(&self, client: &'a dyn time::TimerClient) {
101        self.client.set(client);
102    }
103
104    fn cancel(&self) -> Result<(), ErrorCode> {
105        match self.mode.get() {
106            Mode::Disabled => Ok(()),
107            Mode::OneShot | Mode::Repeating => {
108                self.mode.set(Mode::Disabled);
109                self.mux.enabled.decrement();
110
111                // If there are not more enabled timers, disable the
112                // underlying alarm.
113                if self.mux.enabled.get() == 0 {
114                    let _ = self.mux.alarm.disarm();
115                }
116                Ok(())
117            }
118        }
119    }
120
121    fn interval(&self) -> Option<Self::Ticks> {
122        match self.mode.get() {
123            Mode::Disabled => None,
124            Mode::OneShot | Mode::Repeating => Some(self.interval.get()),
125        }
126    }
127
128    fn is_oneshot(&self) -> bool {
129        self.mode.get() == Mode::OneShot
130    }
131
132    fn is_repeating(&self) -> bool {
133        self.mode.get() == Mode::Repeating
134    }
135
136    fn is_enabled(&self) -> bool {
137        match self.mode.get() {
138            Mode::Disabled => false,
139            Mode::OneShot | Mode::Repeating => true,
140        }
141    }
142
143    fn oneshot(&self, interval: Self::Ticks) -> Self::Ticks {
144        self.start_timer(interval, Mode::OneShot)
145    }
146
147    fn repeating(&self, interval: Self::Ticks) -> Self::Ticks {
148        self.start_timer(interval, Mode::Repeating)
149    }
150
151    fn time_remaining(&self) -> Option<Self::Ticks> {
152        match self.mode.get() {
153            Mode::Disabled => None,
154            Mode::OneShot | Mode::Repeating => {
155                let when = self.when.get();
156                let now = self.mux.alarm.now();
157                Some(when.wrapping_sub(now))
158            }
159        }
160    }
161}
162
163impl<'a, A: Alarm<'a>> time::AlarmClient for VirtualTimer<'a, A> {
164    fn alarm(&self) {
165        match self.mode.get() {
166            Mode::Disabled => {} // Do nothing
167            Mode::OneShot => {
168                self.mode.set(Mode::Disabled);
169                self.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.
175                let when = self.when.get();
176                let interval = self.interval.get();
177                self.when.set(when.wrapping_add(interval));
178                self.mux.calculate_alarm(when, interval);
179                self.client.map(|client| client.timer());
180            }
181        }
182    }
183}
184
185/// 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.
188    timers: List<'a, VirtualTimer<'a, A>>,
189    /// Number of virtual timers that are currently enabled.
190    enabled: Cell<usize>,
191    /// Underlying alarm, over which the virtual timers are multiplexed.
192    alarm: &'a VirtualMuxAlarm<'a, A>,
193}
194
195impl<'a, A: Alarm<'a>> MuxTimer<'a, A> {
196    pub 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    }
203
204    fn calculate_alarm(&self, now: A::Ticks, interval: A::Ticks) {
205        if self.enabled.get() == 1 {
206            // First alarm, to just set it
207            self.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
214            let cur_alarm = self.alarm.get_alarm();
215            let when = now.wrapping_add(interval);
216            if !cur_alarm.within_range(now, when) {
217                // This alarm is earlier: reset alarm to it
218                self.alarm.set_alarm(now, interval);
219            } else {
220                // current alarm will fire earlier, keep it
221            }
222        }
223    }
224}
225
226impl<'a, A: Alarm<'a>> time::AlarmClient for MuxTimer<'a, A> {
227    fn 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.
231        let 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.
234        self.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            });
246
247        // 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.
250        let 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());
255
256        // Set the alarm.
257        if let Some(valrm) = next {
258            self.alarm
259                .set_alarm(now, valrm.when.get().wrapping_sub(now));
260        } else {
261            let _ = self.alarm.disarm();
262        }
263    }
264}