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}