components/
bus.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//! Bus Components for Intel8080 Parallel Interface, I2C, SPI
6//!
7//! Example
8//!
9//! Intel 8080 Parallel Interface
10//!
11//! let bus = components::bus::Bus8080BusComponent::new(&stm32f412g::fsmc::FSMC).finalize(
12//!     components::bus8080_bus_component_static!(stm32f412g::fsmc::Fsmc)
13//! );
14//!
15//! SPI
16//!
17//! ```rust
18//! let bus = components::bus::SpiMasterBusComponent::new(spi_mux,
19//!                                                       chip_select,
20//!                                                       baud_rate,
21//!                                                       clock_phase,
22//!                                                       clock_polarity).finalize(
23//!     components::spi_bus_component_static!(nrf52840::spi::SPIM)
24//! );
25//! ```
26
27use capsules_core::virtualizers::virtual_i2c::{I2CDevice, MuxI2C};
28use capsules_core::virtualizers::virtual_spi::MuxSpiMaster;
29use capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice;
30use capsules_extra::bus::{Bus8080Bus, I2CMasterBus, SpiMasterBus};
31use core::mem::MaybeUninit;
32use kernel::component::Component;
33use kernel::hil::bus8080;
34use kernel::hil::i2c;
35use kernel::hil::spi::{self, ClockPhase, ClockPolarity, SpiMasterDevice};
36
37// Setup static space for the objects.
38#[macro_export]
39macro_rules! bus8080_bus_component_static {
40    ($B:ty $(,)?) => {{
41        kernel::static_buf!(capsules_extra::bus::Bus8080Bus<'static, $B>)
42    };};
43}
44
45#[macro_export]
46macro_rules! spi_bus_component_static {
47    ($S:ty $(,)?) => {{
48        let spi = kernel::static_buf!(
49            capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<'static, $S>
50        );
51        let address_buffer = kernel::static_buf!([u8; core::mem::size_of::<usize>()]);
52        let bus = kernel::static_buf!(
53            capsules_extra::bus::SpiMasterBus<
54                'static,
55                capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<'static, $S>,
56            >
57        );
58
59        (spi, bus, address_buffer)
60    };};
61}
62
63#[macro_export]
64macro_rules! i2c_master_bus_component_static {
65    ($D:ty $(,)?) => {{
66        let address_buffer = kernel::static_buf!([u8; 1]);
67        let bus = kernel::static_buf!(capsules_extra::bus::I2CMasterBus<'static, $D>);
68        let i2c_device = kernel::static_buf!(
69            capsules_core::virtualizers::virtual_i2c::I2CDevice<
70                'static,
71                capsules_extra::bus::I2CMasterBus<'static, $D>,
72            >
73        );
74
75        (bus, i2c_device, address_buffer)
76    };};
77}
78
79pub struct Bus8080BusComponent<B: 'static + bus8080::Bus8080<'static>> {
80    bus: &'static B,
81}
82
83impl<B: 'static + bus8080::Bus8080<'static>> Bus8080BusComponent<B> {
84    pub fn new(bus: &'static B) -> Bus8080BusComponent<B> {
85        Bus8080BusComponent { bus }
86    }
87}
88
89impl<B: 'static + bus8080::Bus8080<'static>> Component for Bus8080BusComponent<B> {
90    type StaticInput = &'static mut MaybeUninit<Bus8080Bus<'static, B>>;
91    type Output = &'static Bus8080Bus<'static, B>;
92
93    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
94        let bus = static_buffer.write(Bus8080Bus::new(self.bus));
95        self.bus.set_client(bus);
96
97        bus
98    }
99}
100
101pub struct SpiMasterBusComponent<S: 'static + spi::SpiMaster<'static>> {
102    spi_mux: &'static MuxSpiMaster<'static, S>,
103    chip_select: S::ChipSelect,
104    baud_rate: u32,
105    clock_phase: ClockPhase,
106    clock_polarity: ClockPolarity,
107}
108
109impl<S: 'static + spi::SpiMaster<'static>> SpiMasterBusComponent<S> {
110    pub fn new(
111        spi_mux: &'static MuxSpiMaster<'static, S>,
112        chip_select: S::ChipSelect,
113        baud_rate: u32,
114        clock_phase: ClockPhase,
115        clock_polarity: ClockPolarity,
116    ) -> SpiMasterBusComponent<S> {
117        SpiMasterBusComponent {
118            spi_mux,
119            chip_select,
120            baud_rate,
121            clock_phase,
122            clock_polarity,
123        }
124    }
125}
126
127impl<S: 'static + spi::SpiMaster<'static>> Component for SpiMasterBusComponent<S> {
128    type StaticInput = (
129        &'static mut MaybeUninit<VirtualSpiMasterDevice<'static, S>>,
130        &'static mut MaybeUninit<SpiMasterBus<'static, VirtualSpiMasterDevice<'static, S>>>,
131        &'static mut MaybeUninit<[u8; core::mem::size_of::<usize>()]>,
132    );
133    type Output = &'static SpiMasterBus<'static, VirtualSpiMasterDevice<'static, S>>;
134
135    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
136        let spi_device = static_buffer
137            .0
138            .write(VirtualSpiMasterDevice::new(self.spi_mux, self.chip_select));
139        spi_device.setup();
140
141        if let Err(error) =
142            spi_device.configure(self.clock_polarity, self.clock_phase, self.baud_rate)
143        {
144            panic!("Failed to setup SPI Bus ({:?})", error);
145        }
146
147        let buffer = static_buffer.2.write([0; core::mem::size_of::<usize>()]);
148
149        let bus = static_buffer.1.write(SpiMasterBus::new(spi_device, buffer));
150        spi_device.set_client(bus);
151
152        bus
153    }
154}
155
156pub struct I2CMasterBusComponent<I: 'static + i2c::I2CMaster<'static>> {
157    i2c_mux: &'static MuxI2C<'static, I>,
158    address: u8,
159}
160
161impl<I: 'static + i2c::I2CMaster<'static>> I2CMasterBusComponent<I> {
162    pub fn new(i2c_mux: &'static MuxI2C<'static, I>, address: u8) -> I2CMasterBusComponent<I> {
163        I2CMasterBusComponent { i2c_mux, address }
164    }
165}
166
167impl<I: 'static + i2c::I2CMaster<'static>> Component for I2CMasterBusComponent<I> {
168    type StaticInput = (
169        &'static mut MaybeUninit<I2CMasterBus<'static, I2CDevice<'static, I>>>,
170        &'static mut MaybeUninit<I2CDevice<'static, I>>,
171        &'static mut MaybeUninit<[u8; 1]>,
172    );
173    type Output = &'static I2CMasterBus<'static, I2CDevice<'static, I>>;
174
175    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
176        let i2c_device = static_buffer
177            .1
178            .write(I2CDevice::new(self.i2c_mux, self.address));
179        let buffer = static_buffer.2.write([0; 1]);
180
181        let bus = static_buffer.0.write(I2CMasterBus::new(i2c_device, buffer));
182        i2c_device.set_client(bus);
183
184        bus
185    }
186}