components/
button.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Component for Buttons.
//!
//! Usage
//! -----
//!
//! The `button_component_helper!` macro takes 'static references to GPIO pins.
//! When GPIO instances are owned values, the `button_component_helper_owned!`
//! can be used, indicating that the passed values are owned values. This macro
//! will perform static allocation of the passed in GPIO pins internally.
//!
//! ```rust
//! let button = components::button::ButtonComponent::new(
//!     board_kernel,
//!     components::button_component_helper!(
//!         sam4l::gpio::GPIOPin,
//!         (
//!             &sam4l::gpio::PC[24],
//!             kernel::hil::gpio::ActivationMode::ActiveLow,
//!             kernel::hil::gpio::FloatingState::PullUp
//!         )
//!     ),
//! )
//! .finalize(button_component_static!(sam4l::gpio::GPIOPin));
//! ```
//!
//! Typically, `ActivationMode::ActiveLow` will be associated with
//! `FloatingState::PullUp` whereas `ActivationMode::ActiveHigh` will be paired
//! with `FloatingState::PullDown`. `FloatingState::None` will be used when the
//! board provides external pull-up/pull-down resistors.

use capsules_core::button::Button;
use core::mem::MaybeUninit;
use kernel::capabilities;
use kernel::component::Component;
use kernel::create_capability;
use kernel::hil::gpio;
use kernel::hil::gpio::InterruptWithValue;

#[macro_export]
macro_rules! button_component_helper_owned {
    ($Pin:ty, $(($P:expr, $M:expr, $F:expr)),+ $(,)?) => {
        $crate::button_component_helper!(
            $Pin,
            $((
                static_init!($Pin, $P),
                $M,
                $F
            ),)*
        )
    };
}

#[macro_export]
macro_rules! button_component_helper {
    ($Pin:ty, $(($P:expr, $M:expr, $F:expr)),+ $(,)?) => {{
        use kernel::static_init;
        use kernel::count_expressions;
        use kernel::hil::gpio::InterruptValueWrapper;
        const NUM_BUTTONS: usize = count_expressions!($($P),+);

        static_init!(
            [(&'static InterruptValueWrapper<'static, $Pin>, kernel::hil::gpio::ActivationMode, kernel::hil::gpio::FloatingState); NUM_BUTTONS],
            [
                $(
                    (static_init!(InterruptValueWrapper<$Pin>, InterruptValueWrapper::new($P))
                    .finalize(),
                    $M,
                    $F
                    ),
                )*
            ]
        )
    };};
}

#[macro_export]
macro_rules! button_component_static {
    ($Pin:ty $(,)?) => {{
        kernel::static_buf!(capsules_core::button::Button<'static, $Pin>)
    };};
}

pub type ButtonComponentType<IP> = capsules_core::button::Button<'static, IP>;

pub struct ButtonComponent<IP: 'static + gpio::InterruptPin<'static>> {
    board_kernel: &'static kernel::Kernel,
    driver_num: usize,
    button_pins: &'static [(
        &'static gpio::InterruptValueWrapper<'static, IP>,
        gpio::ActivationMode,
        gpio::FloatingState,
    )],
}

impl<IP: 'static + gpio::InterruptPin<'static>> ButtonComponent<IP> {
    pub fn new(
        board_kernel: &'static kernel::Kernel,
        driver_num: usize,
        button_pins: &'static [(
            &'static gpio::InterruptValueWrapper<'static, IP>,
            gpio::ActivationMode,
            gpio::FloatingState,
        )],
    ) -> Self {
        Self {
            board_kernel,
            driver_num,
            button_pins,
        }
    }
}

impl<IP: 'static + gpio::InterruptPin<'static>> Component for ButtonComponent<IP> {
    type StaticInput = &'static mut MaybeUninit<Button<'static, IP>>;
    type Output = &'static Button<'static, IP>;

    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
        let button = static_buffer.write(capsules_core::button::Button::new(
            self.button_pins,
            self.board_kernel.create_grant(self.driver_num, &grant_cap),
        ));
        for (pin, _, _) in self.button_pins.iter() {
            pin.set_client(button);
        }

        button
    }
}