components/
screen.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 the Screen.
6//!
7//! Buffer Size
8//! -----------
9//!
10//! Displays can receive a large amount of data and having larger transfer buffers
11//! optimizes the number of bus writes.
12//!
13//! As memory is limited on some MCUs, the `components::screen_buffer_size``
14//! macro allows users to define the size of the screen buffer.
15//!
16//! Usage
17//! -----
18//!
19//! // Screen
20//! ```rust
21//! let screen =
22//!     components::screen::ScreenComponent::new(board_kernel, tft, None)
23//!         .finalize(components::screen_component_static!(40960));
24//! ```
25//!
26//! // Screen with Setup
27//! ```rust
28//! let screen =
29//!     components::screen::ScreenComponent::new(board_kernel, tft, Some(tft))
30//!         .finalize(components::screen_component_static!(40960));
31//! ```
32
33use capsules_extra::screen::screen::Screen;
34use capsules_extra::screen::screen_shared::ScreenShared;
35use capsules_extra::virtualizers::screen::virtual_screen_split;
36use core::mem::MaybeUninit;
37use kernel::capabilities;
38use kernel::component::Component;
39use kernel::create_capability;
40use kernel::hil;
41
42#[macro_export]
43macro_rules! screen_split_mux_component_static {
44    ($S:ty $(,)?) => {{
45        kernel::static_buf!(
46            capsules_extra::virtualizers::screen::virtual_screen_split::ScreenSplitMux<'static, $S>
47        )
48    };};
49}
50
51#[macro_export]
52macro_rules! screen_split_user_component_static {
53    ($S:ty $(,)?) => {{
54        kernel::static_buf!(
55            capsules_extra::virtualizers::screen::virtual_screen_split::ScreenSplitUser<
56                'static,
57                $S,
58            >
59        )
60    };};
61}
62
63pub type ScreenSplitMuxComponentType<S> = virtual_screen_split::ScreenSplitMux<'static, S>;
64
65pub struct ScreenSplitMuxComponent<S: hil::screen::Screen<'static> + 'static> {
66    screen: &'static S,
67}
68
69impl<S: hil::screen::Screen<'static>> ScreenSplitMuxComponent<S> {
70    pub fn new(screen: &'static S) -> Self {
71        Self { screen }
72    }
73}
74
75impl<S: hil::screen::Screen<'static> + 'static> Component for ScreenSplitMuxComponent<S> {
76    type StaticInput = &'static mut MaybeUninit<virtual_screen_split::ScreenSplitMux<'static, S>>;
77    type Output = &'static virtual_screen_split::ScreenSplitMux<'static, S>;
78
79    fn finalize(self, static_input: Self::StaticInput) -> Self::Output {
80        let mux = static_input.write(virtual_screen_split::ScreenSplitMux::new(self.screen));
81
82        kernel::hil::screen::Screen::set_client(self.screen, mux);
83        kernel::deferred_call::DeferredCallClient::register(mux);
84
85        mux
86    }
87}
88
89pub type ScreenSplitUserComponentType<S> = virtual_screen_split::ScreenSplitUser<'static, S>;
90
91pub struct ScreenSplitUserComponent<S: hil::screen::Screen<'static> + 'static> {
92    mux: &'static virtual_screen_split::ScreenSplitMux<'static, S>,
93    x: usize,
94    y: usize,
95    width: usize,
96    height: usize,
97}
98
99impl<S: hil::screen::Screen<'static>> ScreenSplitUserComponent<S> {
100    pub fn new(
101        mux: &'static virtual_screen_split::ScreenSplitMux<'static, S>,
102        x: usize,
103        y: usize,
104        width: usize,
105        height: usize,
106    ) -> Self {
107        Self {
108            mux,
109            x,
110            y,
111            width,
112            height,
113        }
114    }
115}
116
117impl<S: hil::screen::Screen<'static> + 'static> Component for ScreenSplitUserComponent<S> {
118    type StaticInput = &'static mut MaybeUninit<virtual_screen_split::ScreenSplitUser<'static, S>>;
119    type Output = &'static virtual_screen_split::ScreenSplitUser<'static, S>;
120
121    fn finalize(self, static_input: Self::StaticInput) -> Self::Output {
122        let split = static_input.write(virtual_screen_split::ScreenSplitUser::new(
123            self.mux,
124            self.x,
125            self.y,
126            self.width,
127            self.height,
128        ));
129
130        split.add_to_mux();
131
132        split
133    }
134}
135
136#[macro_export]
137macro_rules! screen_component_static {
138    ($s:literal $(,)?) => {{
139        let buffer = kernel::static_buf!([u8; $s]);
140        let screen = kernel::static_buf!(capsules_extra::screen::screen::Screen);
141
142        (buffer, screen)
143    };};
144}
145
146pub type ScreenComponentType = capsules_extra::screen::screen::Screen<'static>;
147
148pub struct ScreenComponent<const SCREEN_BUF_LEN: usize> {
149    board_kernel: &'static kernel::Kernel,
150    driver_num: usize,
151    screen: &'static dyn kernel::hil::screen::Screen<'static>,
152    screen_setup: Option<&'static dyn kernel::hil::screen::ScreenSetup<'static>>,
153}
154
155impl<const SCREEN_BUF_LEN: usize> ScreenComponent<SCREEN_BUF_LEN> {
156    pub fn new(
157        board_kernel: &'static kernel::Kernel,
158        driver_num: usize,
159        screen: &'static dyn kernel::hil::screen::Screen,
160        screen_setup: Option<&'static dyn kernel::hil::screen::ScreenSetup>,
161    ) -> ScreenComponent<SCREEN_BUF_LEN> {
162        ScreenComponent {
163            board_kernel,
164            driver_num,
165            screen,
166            screen_setup,
167        }
168    }
169}
170
171impl<const SCREEN_BUF_LEN: usize> Component for ScreenComponent<SCREEN_BUF_LEN> {
172    type StaticInput = (
173        &'static mut MaybeUninit<[u8; SCREEN_BUF_LEN]>,
174        &'static mut MaybeUninit<Screen<'static>>,
175    );
176    type Output = &'static Screen<'static>;
177
178    fn finalize(self, static_input: Self::StaticInput) -> Self::Output {
179        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
180        let grant_screen = self.board_kernel.create_grant(self.driver_num, &grant_cap);
181
182        let buffer = static_input.0.write([0; SCREEN_BUF_LEN]);
183
184        let screen = static_input.1.write(Screen::new(
185            self.screen,
186            self.screen_setup,
187            buffer,
188            grant_screen,
189        ));
190
191        kernel::hil::screen::Screen::set_client(self.screen, screen);
192        if let Some(screen_setup) = self.screen_setup {
193            kernel::hil::screen::ScreenSetup::set_client(screen_setup, screen);
194        }
195
196        screen
197    }
198}
199
200#[macro_export]
201macro_rules! screen_shared_component_static {
202    ($s:literal, $S:ty $(,)?) => {{
203        let buffer = kernel::static_buf!([u8; $s]);
204        let screen = kernel::static_buf!(capsules_extra::screen::screen_shared::ScreenShared<$S>);
205
206        (buffer, screen)
207    };};
208}
209
210pub type ScreenSharedComponentType<S> =
211    capsules_extra::screen::screen_shared::ScreenShared<'static, S>;
212
213pub struct ScreenSharedComponent<
214    const SCREEN_BUF_LEN: usize,
215    S: hil::screen::Screen<'static> + 'static,
216> {
217    board_kernel: &'static kernel::Kernel,
218    driver_num: usize,
219    screen: &'static S,
220    apps_regions: &'static [capsules_extra::screen::screen_shared::AppScreenRegion],
221}
222
223impl<const SCREEN_BUF_LEN: usize, S: hil::screen::Screen<'static>>
224    ScreenSharedComponent<SCREEN_BUF_LEN, S>
225{
226    pub fn new(
227        board_kernel: &'static kernel::Kernel,
228        driver_num: usize,
229        screen: &'static S,
230        apps_regions: &'static [capsules_extra::screen::screen_shared::AppScreenRegion],
231    ) -> ScreenSharedComponent<SCREEN_BUF_LEN, S> {
232        ScreenSharedComponent {
233            board_kernel,
234            driver_num,
235            screen,
236            apps_regions,
237        }
238    }
239}
240
241impl<const SCREEN_BUF_LEN: usize, S: hil::screen::Screen<'static>> Component
242    for ScreenSharedComponent<SCREEN_BUF_LEN, S>
243{
244    type StaticInput = (
245        &'static mut MaybeUninit<[u8; SCREEN_BUF_LEN]>,
246        &'static mut MaybeUninit<ScreenShared<'static, S>>,
247    );
248    type Output = &'static ScreenShared<'static, S>;
249
250    fn finalize(self, static_input: Self::StaticInput) -> Self::Output {
251        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
252        let grant_screen = self.board_kernel.create_grant(self.driver_num, &grant_cap);
253
254        let buffer = static_input.0.write([0; SCREEN_BUF_LEN]);
255
256        let screen = static_input.1.write(ScreenShared::new(
257            self.screen,
258            grant_screen,
259            buffer,
260            self.apps_regions,
261        ));
262
263        kernel::hil::screen::Screen::set_client(self.screen, screen);
264
265        screen
266    }
267}