kernel/hil/
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//! Interface for screens and displays.
6//!
7//! The interfaces exposed here cover both configurable (`ScreenSetup`), and
8//! less configurable hardware (only `Screen`).
9//!
10//! It's composed of 4 main kinds of requests:
11//! - set power,
12//! - read configuration (e.g. `get_resolution`),
13//! - configure (e.g. `set_invert`),
14//! - write buffer.
15//!
16//! All requests, except for `Screen::set_power`, can return `OFF` under some
17//! circumstances.
18//!
19//! For buffer writes, it's when the display is powered off.
20//!
21//! While the display is not powered on, the user could try to configure it. In
22//! that case, the driver MUST either cache the value, or return `OFF`. This is
23//! to let the user power the display in the desired configuration.
24//!
25//! Configuration reads shall return the actual state of the display. In
26//! situations where a parameter cannot be configured (e.g. fixed resolution),
27//! they return value may be hardcoded. Otherwise, the driver should query the
28//! hardware directly, and return OFF if it's not powered.
29//!
30//! Configuration sets cause a `command_complete` callback unless noted
31//! otherwise.
32
33use crate::utilities::leasable_buffer::SubSliceMut;
34use crate::ErrorCode;
35use core::ops::Add;
36use core::ops::Sub;
37
38#[derive(Copy, Clone, PartialEq)]
39pub enum ScreenRotation {
40    Normal,
41    Rotated90,
42    Rotated180,
43    Rotated270,
44}
45
46impl Add for ScreenRotation {
47    type Output = Self;
48
49    fn add(self, other: Self) -> Self {
50        match (self, other) {
51            (ScreenRotation::Normal, _) => other,
52            (_, ScreenRotation::Normal) => self,
53            (ScreenRotation::Rotated90, ScreenRotation::Rotated90) => ScreenRotation::Rotated180,
54            (ScreenRotation::Rotated90, ScreenRotation::Rotated180) => ScreenRotation::Rotated270,
55            (ScreenRotation::Rotated90, ScreenRotation::Rotated270) => ScreenRotation::Normal,
56
57            (ScreenRotation::Rotated180, ScreenRotation::Rotated90) => ScreenRotation::Rotated270,
58            (ScreenRotation::Rotated180, ScreenRotation::Rotated180) => ScreenRotation::Normal,
59            (ScreenRotation::Rotated180, ScreenRotation::Rotated270) => ScreenRotation::Rotated90,
60
61            (ScreenRotation::Rotated270, ScreenRotation::Rotated90) => ScreenRotation::Normal,
62            (ScreenRotation::Rotated270, ScreenRotation::Rotated180) => ScreenRotation::Rotated90,
63            (ScreenRotation::Rotated270, ScreenRotation::Rotated270) => ScreenRotation::Rotated180,
64        }
65    }
66}
67
68impl Sub for ScreenRotation {
69    type Output = Self;
70
71    fn sub(self, other: Self) -> Self {
72        match (self, other) {
73            (_, ScreenRotation::Normal) => self,
74
75            (ScreenRotation::Normal, ScreenRotation::Rotated90) => ScreenRotation::Rotated270,
76            (ScreenRotation::Normal, ScreenRotation::Rotated180) => ScreenRotation::Rotated180,
77            (ScreenRotation::Normal, ScreenRotation::Rotated270) => ScreenRotation::Rotated90,
78
79            (ScreenRotation::Rotated90, ScreenRotation::Rotated90) => ScreenRotation::Normal,
80            (ScreenRotation::Rotated90, ScreenRotation::Rotated180) => ScreenRotation::Rotated270,
81            (ScreenRotation::Rotated90, ScreenRotation::Rotated270) => ScreenRotation::Rotated180,
82
83            (ScreenRotation::Rotated180, ScreenRotation::Rotated90) => ScreenRotation::Rotated90,
84            (ScreenRotation::Rotated180, ScreenRotation::Rotated180) => ScreenRotation::Normal,
85            (ScreenRotation::Rotated180, ScreenRotation::Rotated270) => ScreenRotation::Rotated270,
86
87            (ScreenRotation::Rotated270, ScreenRotation::Rotated90) => ScreenRotation::Rotated180,
88            (ScreenRotation::Rotated270, ScreenRotation::Rotated180) => ScreenRotation::Rotated90,
89            (ScreenRotation::Rotated270, ScreenRotation::Rotated270) => ScreenRotation::Normal,
90        }
91    }
92}
93
94/// How pixels are encoded for the screen.
95#[derive(Copy, Clone, PartialEq)]
96#[repr(usize)]
97#[allow(non_camel_case_types)]
98pub enum ScreenPixelFormat {
99    /// Pixels encoded as 1-bit, used for monochromatic displays.
100    Mono,
101    /// Pixels encoded as 1-bit blue, 1-bit green, 1-bit red,
102    /// and 1-bit for opaque (1) vs transparent (0)
103    RGB_4BIT,
104    /// Pixels encoded as 3-bit red channel, 3-bit green channel, 2-bit blue
105    /// channel.
106    RGB_332,
107    /// Pixels encoded as 5-bit red channel, 6-bit green channel, 5-bit blue
108    /// channel.
109    RGB_565,
110    /// Pixels encoded as 8-bit red channel, 8-bit green channel, 8-bit blue
111    /// channel.
112    RGB_888,
113    /// Pixels encoded as 8-bit alpha channel, 8-bit red channel, 8-bit green
114    /// channel, 8-bit blue channel.
115    ARGB_8888,
116    // other pixel formats may be defined.
117}
118
119impl ScreenPixelFormat {
120    pub fn get_bits_per_pixel(&self) -> usize {
121        match self {
122            Self::Mono => 1,
123            Self::RGB_4BIT => 4,
124            Self::RGB_332 => 8,
125            Self::RGB_565 => 16,
126            Self::RGB_888 => 24,
127            Self::ARGB_8888 => 32,
128        }
129    }
130}
131
132/// Interface to configure the screen.
133pub trait ScreenSetup<'a> {
134    fn set_client(&self, client: &'a dyn ScreenSetupClient);
135
136    /// Set the screen resolution in pixels with `(X, Y)`.
137    ///
138    /// Returns `Ok(())` if the request is registered and will be sent to the
139    /// screen. A `command_complete` callback function will be triggered when
140    /// the resolution change is finished and will provide a `Result<(),
141    /// ErrorCode>` to indicate if the resolution change was successful.
142    ///
143    /// Returns `Err(NOSUPPORT)` if the resolution is not supported. No callback will
144    /// be triggered.
145    fn set_resolution(&self, resolution: (usize, usize)) -> Result<(), ErrorCode>;
146
147    /// Set the pixel format.
148    ///
149    /// Returns `Ok(())` if the request is registered and will be sent to the
150    /// screen. A `command_complete` callback function will be triggered when
151    /// the pixel format change is finished and will provide a `Result<(),
152    /// ErrorCode>` to indicate if the pixel format change was successful.
153    ///
154    /// Returns `Err(NOSUPPORT)` if the pixel format is not supported.
155    fn set_pixel_format(&self, format: ScreenPixelFormat) -> Result<(), ErrorCode>;
156
157    /// Set the rotation of the display.
158    ///
159    /// Returns `Ok(())` if the request is registered and will be sent to the
160    /// screen. A `command_complete` callback function will be triggered when
161    /// the rotation update is finished and will provide a `Result<(),
162    /// ErrorCode>` to indicate if the rotation change was successful.
163    ///
164    /// Note that `Rotated90` or `Rotated270` will swap the width and height.
165    fn set_rotation(&self, rotation: ScreenRotation) -> Result<(), ErrorCode>;
166
167    /// Get the number of supported resolutions.
168    ///
169    /// This must return at least one (the current resolution).
170    ///
171    /// This function is synchronous as the driver should know this value
172    /// without requesting it from the screen (most screens do not support such
173    /// a request, resolutions are described in the data sheet).
174    fn get_num_supported_resolutions(&self) -> usize;
175
176    /// Get the resolution specified by the given index.
177    ///
178    /// `index` is from `0..get_num_supported_resolutions()-1` and this returns
179    /// a tuple `(width, height)` of the associated resolution (in pixels). Note
180    /// that width and height may change due to rotation. Returns `None` if
181    /// `index` is invalid.
182    ///
183    /// This function is synchronous as the driver should know this value
184    /// without requesting it from the screen.
185    fn get_supported_resolution(&self, index: usize) -> Option<(usize, usize)>;
186
187    /// Get the number of the pixel formats supported.
188    ///
189    /// This function is synchronous as the driver should know this value
190    /// without requesting it from the screen (most screens do not support such
191    /// a request, pixel formats are described in the data sheet).
192    fn get_num_supported_pixel_formats(&self) -> usize;
193
194    /// Get the pixel format specified by the given index.
195    ///
196    /// `index` is from `0..get_num_supported_pixel_formats()-1` and this
197    /// returns the associated pixel format. Returns `None` if `index` is
198    /// invalid.
199    ///
200    /// This function is synchronous as the driver should know this value
201    /// without requesting it from the screen.
202    fn get_supported_pixel_format(&self, index: usize) -> Option<ScreenPixelFormat>;
203}
204
205/// Basic interface for screens.
206pub trait Screen<'a> {
207    /// Set the object to receive the asynchronous command callbacks.
208    fn set_client(&self, client: &'a dyn ScreenClient);
209
210    /// Get a tuple `(width, height)` with the current resolution (in pixels).
211    ///
212    /// This function is synchronous as the driver should know this value
213    /// without requesting it from the screen.
214    ///
215    /// Note that width and height may change due to rotation.
216    fn get_resolution(&self) -> (usize, usize);
217
218    /// Get the current pixel format.
219    ///
220    /// This function is synchronous as the driver should know this value
221    /// without requesting it from the screen.
222    fn get_pixel_format(&self) -> ScreenPixelFormat;
223
224    /// Get the current rotation.
225    ///
226    /// This function is synchronous as the driver should know this value
227    /// without requesting it from the screen.
228    fn get_rotation(&self) -> ScreenRotation;
229
230    /// Sets the write frame.
231    ///
232    /// This function has to be called before the first call to the write
233    /// function. This will generate a `command_complete()` callback when
234    /// finished.
235    ///
236    /// Return values:
237    /// - `Ok(())`: The write frame is valid.
238    /// - `INVAL`: The parameters of the write frame are not valid.
239    /// - `BUSY`: Unable to set the write frame on the device.
240    fn set_write_frame(
241        &self,
242        x: usize,
243        y: usize,
244        width: usize,
245        height: usize,
246    ) -> Result<(), ErrorCode>;
247
248    /// Write data from `buffer` to the selected write frame.
249    ///
250    /// When finished, the driver will call the `write_complete()` callback.
251    ///
252    /// This function can be called multiple times if the write frame is larger
253    /// than the size of the available buffer by setting `continue_write` to
254    /// `true`. If `continue_write` is false, the buffer write position will be
255    /// reset before the data are written.
256    ///
257    /// Return values:
258    /// - `Ok(())`: Write is valid and will be sent to the screen.
259    /// - `SIZE`: The buffer is too long for the selected write frame.
260    /// - `BUSY`: Another write is in progress.
261    fn write(
262        &self,
263        buffer: SubSliceMut<'static, u8>,
264        continue_write: bool,
265    ) -> Result<(), ErrorCode>;
266
267    /// Set the display brightness value.
268    ///
269    /// Depending on the display, this may not cause any actual changes
270    /// until and unless power is enabled (see `set_power`).
271    ///
272    /// The following values must be supported:
273    /// - 0: completely no light emitted
274    /// - 1..65536: set brightness to the given level
275    ///
276    /// The display should interpret the brightness value as *lightness* (each
277    /// increment should change perceived brightness the same). 1 shall be the
278    /// minimum supported brightness, 65536 is the maximum brightness. Values in
279    /// between should approximate the intermediate values; minimum and maximum
280    /// included (e.g. when there is only 1 level).
281    fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode>;
282
283    /// Controls the screen power supply.
284    ///
285    /// Use it to initialize the display device.
286    ///
287    /// For screens where display needs nonzero brightness (e.g. LED), this
288    /// shall set brightness to a default value if `set_brightness` was not
289    /// called first.
290    ///
291    /// The device may implement power independently from brightness, so call
292    /// `set_brightness` to turn on/off the module completely.
293    ///
294    /// To allow starting in the correct configuration, the driver is allowed to
295    /// cache values like brightness or invert mode and apply them together when
296    /// power is enabled. If the display cannot use selected configuration, this
297    /// call returns `INVAL`.
298    ///
299    /// When finished, calls `ScreenClient::screen_is_ready`, both when power
300    /// is enabled and disabled.
301    fn set_power(&self, enabled: bool) -> Result<(), ErrorCode>;
302
303    /// Controls the color inversion mode.
304    ///
305    /// Pixels already in the frame buffer, as well as newly submitted, will be
306    /// inverted. What that means depends on the current pixel format. May get
307    /// disabled when switching to another pixel format. Returns `NOSUPPORT` if
308    /// the device does not accelerate color inversion. Returns `INVAL` if the
309    /// current pixel format does not support color inversion.
310    fn set_invert(&self, enabled: bool) -> Result<(), ErrorCode>;
311}
312
313pub trait ScreenAdvanced<'a>: Screen<'a> + ScreenSetup<'a> {}
314// Provide blanket implementations for trait group
315impl<'a, T: Screen<'a> + ScreenSetup<'a>> ScreenAdvanced<'a> for T {}
316
317pub trait ScreenSetupClient {
318    /// The screen will call this function to notify that a command has finished.
319    fn command_complete(&self, r: Result<(), ErrorCode>);
320}
321
322pub trait ScreenClient {
323    /// The screen will call this function to notify that a command (except
324    /// write) has finished.
325    fn command_complete(&self, result: Result<(), ErrorCode>);
326
327    /// The screen will call this function to notify that the write command has
328    /// finished. This is different from `command_complete` as it has to pass
329    /// back the write buffer
330    fn write_complete(&self, buffer: SubSliceMut<'static, u8>, result: Result<(), ErrorCode>);
331
332    /// Some screens need some time to start, this function is called when the
333    /// screen is ready.
334    fn screen_is_ready(&self);
335}