components/
button.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//! Component for Buttons.
6//!
7//! Usage
8//! -----
9//!
10//! The `button_component_helper!` macro takes 'static references to GPIO pins.
11//! When GPIO instances are owned values, the `button_component_helper_owned!`
12//! can be used, indicating that the passed values are owned values. This macro
13//! will perform static allocation of the passed in GPIO pins internally.
14//!
15//! ```rust
16//! let button = components::button::ButtonComponent::new(
17//!     board_kernel,
18//!     components::button_component_helper!(
19//!         sam4l::gpio::GPIOPin,
20//!         (
21//!             &sam4l::gpio::PC[24],
22//!             kernel::hil::gpio::ActivationMode::ActiveLow,
23//!             kernel::hil::gpio::FloatingState::PullUp
24//!         )
25//!     ),
26//! )
27//! .finalize(button_component_static!(sam4l::gpio::GPIOPin));
28//! ```
29//!
30//! Typically, `ActivationMode::ActiveLow` will be associated with
31//! `FloatingState::PullUp` whereas `ActivationMode::ActiveHigh` will be paired
32//! with `FloatingState::PullDown`. `FloatingState::None` will be used when the
33//! board provides external pull-up/pull-down resistors.
34
35use capsules_core::button::Button;
36use core::mem::MaybeUninit;
37use kernel::capabilities;
38use kernel::component::Component;
39use kernel::create_capability;
40use kernel::hil::gpio;
41use kernel::hil::gpio::InterruptWithValue;
42
43#[macro_export]
44macro_rules! button_component_helper_owned {
45    ($Pin:ty, $(($P:expr, $M:expr, $F:expr)),+ $(,)?) => {
46        $crate::button_component_helper!(
47            $Pin,
48            $((
49                static_init!($Pin, $P),
50                $M,
51                $F
52            ),)*
53        )
54    };
55}
56
57#[macro_export]
58macro_rules! button_component_helper {
59    ($Pin:ty, $(($P:expr, $M:expr, $F:expr)),+ $(,)?) => {{
60        use kernel::static_init;
61        use kernel::count_expressions;
62        use kernel::hil::gpio::InterruptValueWrapper;
63        const NUM_BUTTONS: usize = count_expressions!($($P),+);
64
65        static_init!(
66            [(&'static InterruptValueWrapper<'static, $Pin>, kernel::hil::gpio::ActivationMode, kernel::hil::gpio::FloatingState); NUM_BUTTONS],
67            [
68                $(
69                    (static_init!(InterruptValueWrapper<$Pin>, InterruptValueWrapper::new($P))
70                    .finalize(),
71                    $M,
72                    $F
73                    ),
74                )*
75            ]
76        )
77    };};
78}
79
80#[macro_export]
81macro_rules! button_component_static {
82    ($Pin:ty $(,)?) => {{
83        kernel::static_buf!(capsules_core::button::Button<'static, $Pin>)
84    };};
85}
86
87pub type ButtonComponentType<IP> = capsules_core::button::Button<'static, IP>;
88
89pub struct ButtonComponent<IP: 'static + gpio::InterruptPin<'static>> {
90    board_kernel: &'static kernel::Kernel,
91    driver_num: usize,
92    button_pins: &'static [(
93        &'static gpio::InterruptValueWrapper<'static, IP>,
94        gpio::ActivationMode,
95        gpio::FloatingState,
96    )],
97}
98
99impl<IP: 'static + gpio::InterruptPin<'static>> ButtonComponent<IP> {
100    pub fn new(
101        board_kernel: &'static kernel::Kernel,
102        driver_num: usize,
103        button_pins: &'static [(
104            &'static gpio::InterruptValueWrapper<'static, IP>,
105            gpio::ActivationMode,
106            gpio::FloatingState,
107        )],
108    ) -> Self {
109        Self {
110            board_kernel,
111            driver_num,
112            button_pins,
113        }
114    }
115}
116
117impl<IP: 'static + gpio::InterruptPin<'static>> Component for ButtonComponent<IP> {
118    type StaticInput = &'static mut MaybeUninit<Button<'static, IP>>;
119    type Output = &'static Button<'static, IP>;
120
121    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
122        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
123        let button = static_buffer.write(capsules_core::button::Button::new(
124            self.button_pins,
125            self.board_kernel.create_grant(self.driver_num, &grant_cap),
126        ));
127        for (pin, _, _) in self.button_pins.iter() {
128            pin.set_client(button);
129        }
130
131        button
132    }
133}