components/
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//! Components for hardware timer Alarms.
6//!
7//! This provides two components, `AlarmMuxComponent`, which provides a
8//! multiplexed interface to a hardware alarm, and `AlarmDriverComponent`,
9//! which provides an alarm system call interface.
10//!
11//! Usage
12//! -----
13//! ```rust
14//! let ast = &sam4l::ast::AST;
15//! let mux_alarm = components::alarm::AlarmMuxComponent::new(ast)
16//!     .finalize(components::alarm_mux_component_static!(sam4l::ast::Ast));
17//! ast.configure(mux_alarm);
18//! let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
19//!     .finalize(components::alarm_component_static!(sam4l::ast::Ast));
20//! ```
21
22// Author: Philip Levis <pal@cs.stanford.edu>
23// Last modified: 12/21/2019
24
25use core::mem::MaybeUninit;
26
27use capsules_core::alarm::AlarmDriver;
28use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
29use kernel::capabilities;
30use kernel::component::Component;
31use kernel::create_capability;
32use kernel::hil::time::{self, Alarm};
33
34// Setup static space for the objects.
35#[macro_export]
36macro_rules! alarm_mux_component_static {
37    ($A:ty $(,)?) => {{
38        kernel::static_buf!(capsules_core::virtualizers::virtual_alarm::MuxAlarm<'static, $A>)
39    };};
40}
41
42// Setup static space for the objects.
43#[macro_export]
44macro_rules! alarm_component_static {
45    ($A:ty $(,)?) => {{
46        let mux_alarm = kernel::static_buf!(
47            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>
48        );
49        let alarm_driver = kernel::static_buf!(
50            capsules_core::alarm::AlarmDriver<
51                'static,
52                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
53            >
54        );
55
56        (mux_alarm, alarm_driver)
57    };};
58}
59
60pub type AlarmDriverComponentType<A> = capsules_core::alarm::AlarmDriver<
61    'static,
62    capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, A>,
63>;
64
65pub struct AlarmMuxComponent<A: 'static + time::Alarm<'static>> {
66    alarm: &'static A,
67}
68
69impl<A: 'static + time::Alarm<'static>> AlarmMuxComponent<A> {
70    pub fn new(alarm: &'static A) -> AlarmMuxComponent<A> {
71        AlarmMuxComponent { alarm }
72    }
73}
74
75impl<A: 'static + time::Alarm<'static>> Component for AlarmMuxComponent<A> {
76    type StaticInput = &'static mut MaybeUninit<MuxAlarm<'static, A>>;
77    type Output = &'static MuxAlarm<'static, A>;
78
79    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
80        let mux_alarm = static_buffer.write(MuxAlarm::new(self.alarm));
81
82        self.alarm.set_alarm_client(mux_alarm);
83        mux_alarm
84    }
85}
86
87pub struct AlarmDriverComponent<A: 'static + time::Alarm<'static>> {
88    board_kernel: &'static kernel::Kernel,
89    driver_num: usize,
90    alarm_mux: &'static MuxAlarm<'static, A>,
91}
92
93impl<A: 'static + time::Alarm<'static>> AlarmDriverComponent<A> {
94    pub fn new(
95        board_kernel: &'static kernel::Kernel,
96        driver_num: usize,
97        mux: &'static MuxAlarm<'static, A>,
98    ) -> AlarmDriverComponent<A> {
99        AlarmDriverComponent {
100            board_kernel,
101            driver_num,
102            alarm_mux: mux,
103        }
104    }
105}
106
107impl<A: 'static + time::Alarm<'static>> Component for AlarmDriverComponent<A> {
108    type StaticInput = (
109        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
110        &'static mut MaybeUninit<AlarmDriver<'static, VirtualMuxAlarm<'static, A>>>,
111    );
112    type Output = &'static AlarmDriver<'static, VirtualMuxAlarm<'static, A>>;
113
114    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
115        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
116
117        let virtual_alarm1 = static_buffer.0.write(VirtualMuxAlarm::new(self.alarm_mux));
118        virtual_alarm1.setup();
119
120        let alarm = static_buffer.1.write(AlarmDriver::new(
121            virtual_alarm1,
122            self.board_kernel.create_grant(self.driver_num, &grant_cap),
123        ));
124
125        virtual_alarm1.set_alarm_client(alarm);
126        alarm
127    }
128}