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 = 0,
101    /// Pixels encoded as 1-bit, used for monochromatic displays.
102    ///
103    /// The pixel order uses 8-bit (1-byte) pages where each page is displayed
104    /// vertically. That is, buffer[0] bit0 is pixel (0,0), but buffer[0] bit1
105    /// is pixel (0,1). The page continues, so buffer[0] bit 7 is pixel
106    /// (0,7). Then the page advances horizontally, so buffer[1] bit0 is
107    /// pixel (1,0), and buffer[1] bit4 is pixel (1,4).
108    ///
109    /// An example of a screen driver that uses this format is the SSD1306.
110    Mono_8BitPage = 6,
111    /// Pixels encoded as 1-bit blue, 1-bit green, 1-bit red,
112    /// and 1-bit for opaque (1) vs transparent (0)
113    RGB_4BIT = 5,
114    /// Pixels encoded as 3-bit red channel, 3-bit green channel, 2-bit blue
115    /// channel.
116    RGB_332 = 1,
117    /// Pixels encoded as 5-bit red channel, 6-bit green channel, 5-bit blue
118    /// channel.
119    RGB_565 = 2,
120    /// Pixels encoded as 8-bit red channel, 8-bit green channel, 8-bit blue
121    /// channel.
122    RGB_888 = 3,
123    /// Pixels encoded as 8-bit alpha channel, 8-bit red channel, 8-bit green
124    /// channel, 8-bit blue channel.
125    ARGB_8888 = 4,
126    // other pixel formats may be defined.
127}
128
129impl ScreenPixelFormat {
130    pub fn get_bits_per_pixel(&self) -> usize {
131        match self {
132            Self::Mono => 1,
133            Self::Mono_8BitPage => 1,
134            Self::RGB_4BIT => 4,
135            Self::RGB_332 => 8,
136            Self::RGB_565 => 16,
137            Self::RGB_888 => 24,
138            Self::ARGB_8888 => 32,
139        }
140    }
141}
142
143/// Interface to configure the screen.
144pub trait ScreenSetup<'a> {
145    fn set_client(&self, client: &'a dyn ScreenSetupClient);
146
147    /// Set the screen resolution in pixels with `(X, Y)`.
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 resolution change is finished and will provide a `Result<(),
152    /// ErrorCode>` to indicate if the resolution change was successful.
153    ///
154    /// Returns `Err(NOSUPPORT)` if the resolution is not supported. No callback will
155    /// be triggered.
156    fn set_resolution(&self, resolution: (usize, usize)) -> Result<(), ErrorCode>;
157
158    /// Set the pixel format.
159    ///
160    /// Returns `Ok(())` if the request is registered and will be sent to the
161    /// screen. A `command_complete` callback function will be triggered when
162    /// the pixel format change is finished and will provide a `Result<(),
163    /// ErrorCode>` to indicate if the pixel format change was successful.
164    ///
165    /// Returns `Err(NOSUPPORT)` if the pixel format is not supported.
166    fn set_pixel_format(&self, format: ScreenPixelFormat) -> Result<(), ErrorCode>;
167
168    /// Set the rotation of the display.
169    ///
170    /// Returns `Ok(())` if the request is registered and will be sent to the
171    /// screen. A `command_complete` callback function will be triggered when
172    /// the rotation update is finished and will provide a `Result<(),
173    /// ErrorCode>` to indicate if the rotation change was successful.
174    ///
175    /// Note that `Rotated90` or `Rotated270` will swap the width and height.
176    fn set_rotation(&self, rotation: ScreenRotation) -> Result<(), ErrorCode>;
177
178    /// Get the number of supported resolutions.
179    ///
180    /// This must return at least one (the current resolution).
181    ///
182    /// This function is synchronous as the driver should know this value
183    /// without requesting it from the screen (most screens do not support such
184    /// a request, resolutions are described in the data sheet).
185    fn get_num_supported_resolutions(&self) -> usize;
186
187    /// Get the resolution specified by the given index.
188    ///
189    /// `index` is from `0..get_num_supported_resolutions()-1` and this returns
190    /// a tuple `(width, height)` of the associated resolution (in pixels). Note
191    /// that width and height may change due to rotation. Returns `None` if
192    /// `index` is invalid.
193    ///
194    /// This function is synchronous as the driver should know this value
195    /// without requesting it from the screen.
196    fn get_supported_resolution(&self, index: usize) -> Option<(usize, usize)>;
197
198    /// Get the number of the pixel formats supported.
199    ///
200    /// This function is synchronous as the driver should know this value
201    /// without requesting it from the screen (most screens do not support such
202    /// a request, pixel formats are described in the data sheet).
203    fn get_num_supported_pixel_formats(&self) -> usize;
204
205    /// Get the pixel format specified by the given index.
206    ///
207    /// `index` is from `0..get_num_supported_pixel_formats()-1` and this
208    /// returns the associated pixel format. Returns `None` if `index` is
209    /// invalid.
210    ///
211    /// This function is synchronous as the driver should know this value
212    /// without requesting it from the screen.
213    fn get_supported_pixel_format(&self, index: usize) -> Option<ScreenPixelFormat>;
214}
215
216/// Basic interface for screens.
217pub trait Screen<'a> {
218    /// Set the object to receive the asynchronous command callbacks.
219    fn set_client(&self, client: &'a dyn ScreenClient);
220
221    /// Get a tuple `(width, height)` with the current resolution (in pixels).
222    ///
223    /// This function is synchronous as the driver should know this value
224    /// without requesting it from the screen.
225    ///
226    /// Note that width and height may change due to rotation.
227    fn get_resolution(&self) -> (usize, usize);
228
229    /// Get the current pixel format.
230    ///
231    /// This function is synchronous as the driver should know this value
232    /// without requesting it from the screen.
233    fn get_pixel_format(&self) -> ScreenPixelFormat;
234
235    /// Get the current rotation.
236    ///
237    /// This function is synchronous as the driver should know this value
238    /// without requesting it from the screen.
239    fn get_rotation(&self) -> ScreenRotation;
240
241    /// Sets the write frame.
242    ///
243    /// This function has to be called before the first call to the write
244    /// function. This will generate a `command_complete()` callback when
245    /// finished.
246    ///
247    /// Return values:
248    /// - `Ok(())`: The write frame is valid.
249    /// - `INVAL`: The parameters of the write frame are not valid.
250    /// - `BUSY`: Unable to set the write frame on the device.
251    fn set_write_frame(
252        &self,
253        x: usize,
254        y: usize,
255        width: usize,
256        height: usize,
257    ) -> Result<(), ErrorCode>;
258
259    /// Write data from `buffer` to the selected write frame.
260    ///
261    /// When finished, the driver will call the `write_complete()` callback.
262    ///
263    /// This function can be called multiple times if the write frame is larger
264    /// than the size of the available buffer by setting `continue_write` to
265    /// `true`. If `continue_write` is false, the buffer write position will be
266    /// reset before the data are written.
267    ///
268    /// Return values:
269    /// - `Ok(())`: Write is valid and will be sent to the screen.
270    /// - `SIZE`: The buffer is too long for the selected write frame.
271    /// - `BUSY`: Another write is in progress.
272    fn write(
273        &self,
274        buffer: SubSliceMut<'static, u8>,
275        continue_write: bool,
276    ) -> Result<(), ErrorCode>;
277
278    /// Set the display brightness value.
279    ///
280    /// Depending on the display, this may not cause any actual changes
281    /// until and unless power is enabled (see `set_power`).
282    ///
283    /// The following values must be supported:
284    /// - 0: completely no light emitted
285    /// - 1..65536: set brightness to the given level
286    ///
287    /// The display should interpret the brightness value as *lightness* (each
288    /// increment should change perceived brightness the same). 1 shall be the
289    /// minimum supported brightness, 65536 is the maximum brightness. Values in
290    /// between should approximate the intermediate values; minimum and maximum
291    /// included (e.g. when there is only 1 level).
292    fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode>;
293
294    /// Controls the screen power supply.
295    ///
296    /// Use it to initialize the display device.
297    ///
298    /// For screens where display needs nonzero brightness (e.g. LED), this
299    /// shall set brightness to a default value if `set_brightness` was not
300    /// called first.
301    ///
302    /// The device may implement power independently from brightness, so call
303    /// `set_brightness` to turn on/off the module completely.
304    ///
305    /// To allow starting in the correct configuration, the driver is allowed to
306    /// cache values like brightness or invert mode and apply them together when
307    /// power is enabled. If the display cannot use selected configuration, this
308    /// call returns `INVAL`.
309    ///
310    /// When finished, calls `ScreenClient::screen_is_ready`, both when power
311    /// is enabled and disabled.
312    fn set_power(&self, enabled: bool) -> Result<(), ErrorCode>;
313
314    /// Controls the color inversion mode.
315    ///
316    /// Pixels already in the frame buffer, as well as newly submitted, will be
317    /// inverted. What that means depends on the current pixel format. May get
318    /// disabled when switching to another pixel format. Returns `NOSUPPORT` if
319    /// the device does not accelerate color inversion. Returns `INVAL` if the
320    /// current pixel format does not support color inversion.
321    fn set_invert(&self, enabled: bool) -> Result<(), ErrorCode>;
322}
323
324pub trait ScreenAdvanced<'a>: Screen<'a> + ScreenSetup<'a> {}
325// Provide blanket implementations for trait group
326impl<'a, T: Screen<'a> + ScreenSetup<'a>> ScreenAdvanced<'a> for T {}
327
328pub trait ScreenSetupClient {
329    /// The screen will call this function to notify that a command has finished.
330    fn command_complete(&self, r: Result<(), ErrorCode>);
331}
332
333pub trait ScreenClient {
334    /// The screen will call this function to notify that a command (except
335    /// write) has finished.
336    fn command_complete(&self, result: Result<(), ErrorCode>);
337
338    /// The screen will call this function to notify that the write command has
339    /// finished. This is different from `command_complete` as it has to pass
340    /// back the write buffer
341    fn write_complete(&self, buffer: SubSliceMut<'static, u8>, result: Result<(), ErrorCode>);
342
343    /// Some screens need some time to start, this function is called when the
344    /// screen is ready.
345    fn screen_is_ready(&self);
346}