capsules_core/test/
random_alarm.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//! Test that an Alarm implementation is working by trying a few edge
6//! cases on the delay, including delays of 1 and 0 delays. Depends
7//! on a working UART and debug! macro.
8//!
9//! Author: Philip Levis <plevis@google.com>
10//! Last Modified: 6/17/2020
11
12use core::cell::Cell;
13
14use kernel::hil::time::{Alarm, AlarmClient, ConvertTicks, Ticks};
15
16pub struct TestRandomAlarm<'a, A: Alarm<'a>> {
17    alarm: &'a A,
18    pub counter: Cell<usize>,
19    expected: Cell<A::Ticks>,
20    _id: char,
21    print_output: bool,
22    first: Cell<bool>,
23}
24
25impl<'a, A: Alarm<'a>> TestRandomAlarm<'a, A> {
26    pub fn new(alarm: &'a A, value: usize, ch: char, print_output: bool) -> TestRandomAlarm<'a, A> {
27        TestRandomAlarm {
28            alarm,
29            counter: Cell::new(value),
30            expected: Cell::new(alarm.ticks_from_seconds(0)),
31            _id: ch,
32            print_output,
33            first: Cell::new(true),
34        }
35    }
36
37    pub fn run(&self) {
38        self.set_next_alarm();
39    }
40
41    fn set_next_alarm(&self) {
42        let counter = self.counter.get();
43        let mut us: u32 = 3 * ((counter * 668410) % 512507) as u32;
44        if us % 11 == 0 {
45            // Try delays of zero in 1 of 11 cases
46            us = 0;
47        }
48        let delay = self.alarm.ticks_from_us(us);
49        let now = self.alarm.now();
50        // Subtract 0-9 so we are always asking from the past.
51        // If the delay is already 0, don't subtract anything.
52        let start = now.wrapping_sub(A::Ticks::from(us % 10));
53        self.alarm.set_alarm(start, delay);
54        if self.print_output {
55            let diff = now.wrapping_sub(self.expected.get());
56            kernel::debug!(
57                "Test{}@{:?}: Expected at {:?} (diff = {:?}), setting alarm to {:?} (delay = {:?})",
58                self._id,
59                now,
60                self.expected.get(),
61                diff,
62                start.wrapping_add(delay),
63                delay
64            );
65            if !self.first.get() {
66                assert!(self.alarm.ticks_to_ms(diff) < 50);
67            }
68        }
69        self.counter.set(counter + 1);
70        self.expected.set(start.wrapping_add(delay));
71    }
72}
73
74impl<'a, A: Alarm<'a>> AlarmClient for TestRandomAlarm<'a, A> {
75    fn alarm(&self) {
76        if self.print_output {
77            kernel::debug!("Test{}: Alarm fired.", self._id);
78        }
79        self.first.set(false);
80        self.set_next_alarm();
81    }
82}