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}