components/
gpio.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Components for GPIO pins.
//!
//! Usage
//! -----
//!
//! The `gpio_component_helper!` macro takes 'static references to GPIO pins.
//! When GPIO instances are owned values, the `gpio_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 gpio = components::gpio::GpioComponent::new(
//!     board_kernel,
//!     components::gpio_component_helper!(
//!         nrf52840::gpio::GPIOPin,
//!         // left side of the USB plug
//!         0 => &nrf52840::gpio::PORT[Pin::P0_13],
//!         1 => &nrf52840::gpio::PORT[Pin::P0_15],
//!         2 => &nrf52840::gpio::PORT[Pin::P0_17],
//!         3 => &nrf52840::gpio::PORT[Pin::P0_20],
//!         4 => &nrf52840::gpio::PORT[Pin::P0_22],
//!         5 => &nrf52840::gpio::PORT[Pin::P0_24],
//!         6 => &nrf52840::gpio::PORT[Pin::P1_00],
//!         7 => &nrf52840::gpio::PORT[Pin::P0_09],
//!         8 => &nrf52840::gpio::PORT[Pin::P0_10],
//!         // right side of the USB plug
//!         9 => &nrf52840::gpio::PORT[Pin::P0_31],
//!         10 => &nrf52840::gpio::PORT[Pin::P0_29],
//!         11 => &nrf52840::gpio::PORT[Pin::P0_02],
//!         12 => &nrf52840::gpio::PORT[Pin::P1_15],
//!         13 => &nrf52840::gpio::PORT[Pin::P1_13],
//!         14 => &nrf52840::gpio::PORT[Pin::P1_10],
//!         // Below the PCB
//!         15 => &nrf52840::gpio::PORT[Pin::P0_26],
//!         16 => &nrf52840::gpio::PORT[Pin::P0_04],
//!         17 => &nrf52840::gpio::PORT[Pin::P0_11],
//!         18 => &nrf52840::gpio::PORT[Pin::P0_14],
//!         19 => &nrf52840::gpio::PORT[Pin::P1_11],
//!         20 => &nrf52840::gpio::PORT[Pin::P1_07],
//!         21 => &nrf52840::gpio::PORT[Pin::P1_01],
//!         22 => &nrf52840::gpio::PORT[Pin::P1_04],
//!         23 => &nrf52840::gpio::PORT[Pin::P1_02]
//!     ),
//! ).finalize(components::gpio_component_static!(nrf52840::gpio::GPIOPin));
//! ```

use capsules_core::gpio::GPIO;
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! gpio_component_helper_max_pin {
    () => { 0usize };
    ($a:expr, $b:expr, $($tail:expr),* $(,)?) => { $crate::gpio_component_helper_max_pin! (max ($a, $b), $($tail,)*) };
    ($a:expr $(,)?) => { $a };
}

#[macro_export]
macro_rules! gpio_component_helper_owned {
    (
        $Pin:ty,
        $($nr:literal => $pin:expr),* $(,)?
    ) => {
        $crate::gpio_component_helper!(
            $Pin,
            $(
                $nr => static_init!($Pin, $pin),
            )*
        )
    };
}

#[macro_export]
/// Pins are declared using the following format:
///     number => pin
///
/// Any pin numbers that are skipped will be declared as None
/// and using them from user space will return NODEVICE
macro_rules! gpio_component_helper {
    (
        $Pin:ty,
        $($nr:literal => $pin:expr),* $(,)?
    ) => {{
        use kernel::count_expressions;
        use kernel::hil::gpio::InterruptValueWrapper;
        use kernel::static_init;

        const fn max (a: usize, b: usize) -> usize {
            [a, b][(a < b) as usize]
        }

        const NUM_PINS: usize = $crate::gpio_component_helper_max_pin! ($($nr,)*) + 1;

        let mut pins = static_init!(
            [Option<&'static InterruptValueWrapper<'static, $Pin>>; NUM_PINS],
            [None; NUM_PINS]
        );

        $(
            pins[$nr] = Some(static_init!(InterruptValueWrapper<$Pin>, InterruptValueWrapper::new($pin)).finalize());
        )*

        pins
    };};
}

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

pub type GpioComponentType<IP> = GPIO<'static, IP>;

pub struct GpioComponent<IP: 'static + gpio::InterruptPin<'static>> {
    board_kernel: &'static kernel::Kernel,
    driver_num: usize,
    gpio_pins: &'static [Option<&'static gpio::InterruptValueWrapper<'static, IP>>],
}

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

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

    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
        let gpio = static_buffer.write(GPIO::new(
            self.gpio_pins,
            self.board_kernel.create_grant(self.driver_num, &grant_cap),
        ));
        for maybe_pin in self.gpio_pins.iter() {
            if let Some(pin) = maybe_pin {
                pin.set_client(gpio);
            }
        }

        gpio
    }
}