1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Interface for screens and displays.
//!
//! The interfaces exposed here cover both configurable (`ScreenSetup`), and
//! less configurable hardware (only `Screen`).
//!
//! It's composed of 4 main kinds of requests:
//! - set power,
//! - read configuration (e.g. `get_resolution`),
//! - configure (e.g. `set_invert`),
//! - write buffer.
//!
//! All requests, except for `Screen::set_power`, can return `OFF` under some
//! circumstances.
//!
//! For buffer writes, it's when the display is powered off.
//!
//! While the display is not powered on, the user could try to configure it. In
//! that case, the driver MUST either cache the value, or return `OFF`. This is
//! to let the user power the display in the desired configuration.
//!
//! Configuration reads shall return the actual state of the display. In
//! situations where a parameter cannot be configured (e.g. fixed resolution),
//! they return value may be hardcoded. Otherwise, the driver should query the
//! hardware directly, and return OFF if it's not powered.
//!
//! Configuration sets cause a `command_complete` callback unless noted
//! otherwise.

use crate::utilities::leasable_buffer::SubSliceMut;
use crate::ErrorCode;
use core::ops::Add;
use core::ops::Sub;

#[derive(Copy, Clone, PartialEq)]
pub enum ScreenRotation {
    Normal,
    Rotated90,
    Rotated180,
    Rotated270,
}

impl Add for ScreenRotation {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        match (self, other) {
            (ScreenRotation::Normal, _) => other,
            (_, ScreenRotation::Normal) => self,
            (ScreenRotation::Rotated90, ScreenRotation::Rotated90) => ScreenRotation::Rotated180,
            (ScreenRotation::Rotated90, ScreenRotation::Rotated180) => ScreenRotation::Rotated270,
            (ScreenRotation::Rotated90, ScreenRotation::Rotated270) => ScreenRotation::Normal,

            (ScreenRotation::Rotated180, ScreenRotation::Rotated90) => ScreenRotation::Rotated270,
            (ScreenRotation::Rotated180, ScreenRotation::Rotated180) => ScreenRotation::Normal,
            (ScreenRotation::Rotated180, ScreenRotation::Rotated270) => ScreenRotation::Rotated90,

            (ScreenRotation::Rotated270, ScreenRotation::Rotated90) => ScreenRotation::Normal,
            (ScreenRotation::Rotated270, ScreenRotation::Rotated180) => ScreenRotation::Rotated90,
            (ScreenRotation::Rotated270, ScreenRotation::Rotated270) => ScreenRotation::Rotated180,
        }
    }
}

impl Sub for ScreenRotation {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        match (self, other) {
            (_, ScreenRotation::Normal) => self,

            (ScreenRotation::Normal, ScreenRotation::Rotated90) => ScreenRotation::Rotated270,
            (ScreenRotation::Normal, ScreenRotation::Rotated180) => ScreenRotation::Rotated180,
            (ScreenRotation::Normal, ScreenRotation::Rotated270) => ScreenRotation::Rotated90,

            (ScreenRotation::Rotated90, ScreenRotation::Rotated90) => ScreenRotation::Normal,
            (ScreenRotation::Rotated90, ScreenRotation::Rotated180) => ScreenRotation::Rotated270,
            (ScreenRotation::Rotated90, ScreenRotation::Rotated270) => ScreenRotation::Rotated180,

            (ScreenRotation::Rotated180, ScreenRotation::Rotated90) => ScreenRotation::Rotated90,
            (ScreenRotation::Rotated180, ScreenRotation::Rotated180) => ScreenRotation::Normal,
            (ScreenRotation::Rotated180, ScreenRotation::Rotated270) => ScreenRotation::Rotated270,

            (ScreenRotation::Rotated270, ScreenRotation::Rotated90) => ScreenRotation::Rotated180,
            (ScreenRotation::Rotated270, ScreenRotation::Rotated180) => ScreenRotation::Rotated90,
            (ScreenRotation::Rotated270, ScreenRotation::Rotated270) => ScreenRotation::Normal,
        }
    }
}

/// How pixels are encoded for the screen.
#[derive(Copy, Clone, PartialEq)]
#[repr(usize)]
#[allow(non_camel_case_types)]
pub enum ScreenPixelFormat {
    /// Pixels encoded as 1-bit, used for monochromatic displays.
    Mono,
    /// Pixels encoded as 2-bit red channel, 3-bit green channel, 3-bit blue
    /// channel.
    RGB_233,
    /// Pixels encoded as 5-bit red channel, 6-bit green channel, 5-bit blue
    /// channel.
    RGB_565,
    /// Pixels encoded as 8-bit red channel, 8-bit green channel, 8-bit blue
    /// channel.
    RGB_888,
    /// Pixels encoded as 8-bit alpha channel, 8-bit red channel, 8-bit green
    /// channel, 8-bit blue channel.
    ARGB_8888,
    // other pixel formats may be defined.
}

impl ScreenPixelFormat {
    pub fn get_bits_per_pixel(&self) -> usize {
        match self {
            Self::Mono => 1,
            Self::RGB_233 => 8,
            Self::RGB_565 => 16,
            Self::RGB_888 => 24,
            Self::ARGB_8888 => 32,
        }
    }
}

/// Interface to configure the screen.
pub trait ScreenSetup<'a> {
    fn set_client(&self, client: &'a dyn ScreenSetupClient);

    /// Set the screen resolution in pixels with `(X, Y)`.
    ///
    /// Returns `Ok(())` if the request is registered and will be sent to the
    /// screen. A `command_complete` callback function will be triggered when
    /// the resolution change is finished and will provide a `Result<(),
    /// ErrorCode>` to indicate if the resolution change was successful.
    ///
    /// Returns `Err(NOSUPPORT)` if the resolution is not supported. No callback will
    /// be triggered.
    fn set_resolution(&self, resolution: (usize, usize)) -> Result<(), ErrorCode>;

    /// Set the pixel format.
    ///
    /// Returns `Ok(())` if the request is registered and will be sent to the
    /// screen. A `command_complete` callback function will be triggered when
    /// the pixel format change is finished and will provide a `Result<(),
    /// ErrorCode>` to indicate if the pixel format change was successful.
    ///
    /// Returns `Err(NOSUPPORT)` if the pixel format is not supported.
    fn set_pixel_format(&self, format: ScreenPixelFormat) -> Result<(), ErrorCode>;

    /// Set the rotation of the display.
    ///
    /// Returns `Ok(())` if the request is registered and will be sent to the
    /// screen. A `command_complete` callback function will be triggered when
    /// the rotation update is finished and will provide a `Result<(),
    /// ErrorCode>` to indicate if the rotation change was successful.
    ///
    /// Note that `Rotated90` or `Rotated270` will swap the width and height.
    fn set_rotation(&self, rotation: ScreenRotation) -> Result<(), ErrorCode>;

    /// Get the number of supported resolutions.
    ///
    /// This must return at least one (the current resolution).
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen (most screens do not support such
    /// a request, resolutions are described in the data sheet).
    fn get_num_supported_resolutions(&self) -> usize;

    /// Get the resolution specified by the given index.
    ///
    /// `index` is from `0..get_num_supported_resolutions()-1` and this returns
    /// a tuple `(width, height)` of the associated resolution (in pixels). Note
    /// that width and height may change due to rotation. Returns `None` if
    /// `index` is invalid.
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen.
    fn get_supported_resolution(&self, index: usize) -> Option<(usize, usize)>;

    /// Get the number of the pixel formats supported.
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen (most screens do not support such
    /// a request, pixel formats are described in the data sheet).
    fn get_num_supported_pixel_formats(&self) -> usize;

    /// Get the pixel format specified by the given index.
    ///
    /// `index` is from `0..get_num_supported_pixel_formats()-1` and this
    /// returns the associated pixel format. Returns `None` if `index` is
    /// invalid.
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen.
    fn get_supported_pixel_format(&self, index: usize) -> Option<ScreenPixelFormat>;
}

/// Basic interface for screens.
pub trait Screen<'a> {
    /// Set the object to receive the asynchronous command callbacks.
    fn set_client(&self, client: &'a dyn ScreenClient);

    /// Get a tuple `(width, height)` with the current resolution (in pixels).
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen.
    ///
    /// Note that width and height may change due to rotation.
    fn get_resolution(&self) -> (usize, usize);

    /// Get the current pixel format.
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen.
    fn get_pixel_format(&self) -> ScreenPixelFormat;

    /// Get the current rotation.
    ///
    /// This function is synchronous as the driver should know this value
    /// without requesting it from the screen.
    fn get_rotation(&self) -> ScreenRotation;

    /// Sets the write frame.
    ///
    /// This function has to be called before the first call to the write
    /// function. This will generate a `command_complete()` callback when
    /// finished.
    ///
    /// Return values:
    /// - `Ok(())`: The write frame is valid.
    /// - `INVAL`: The parameters of the write frame are not valid.
    /// - `BUSY`: Unable to set the write frame on the device.
    fn set_write_frame(
        &self,
        x: usize,
        y: usize,
        width: usize,
        height: usize,
    ) -> Result<(), ErrorCode>;

    /// Write data from `buffer` to the selected write frame.
    ///
    /// When finished, the driver will call the `write_complete()` callback.
    ///
    /// This function can be called multiple times if the write frame is larger
    /// than the size of the available buffer by setting `continue_write` to
    /// `true`. If `continue_write` is false, the buffer write position will be
    /// reset before the data are written.
    ///
    /// Return values:
    /// - `Ok(())`: Write is valid and will be sent to the screen.
    /// - `SIZE`: The buffer is too long for the selected write frame.
    /// - `BUSY`: Another write is in progress.
    fn write(
        &self,
        buffer: SubSliceMut<'static, u8>,
        continue_write: bool,
    ) -> Result<(), ErrorCode>;

    /// Set the display brightness value.
    ///
    /// Depending on the display, this may not cause any actual changes
    /// until and unless power is enabled (see `set_power`).
    ///
    /// The following values must be supported:
    /// - 0: completely no light emitted
    /// - 1..65536: set brightness to the given level
    ///
    /// The display should interpret the brightness value as *lightness* (each
    /// increment should change perceived brightness the same). 1 shall be the
    /// minimum supported brightness, 65536 is the maximum brightness. Values in
    /// between should approximate the intermediate values; minimum and maximum
    /// included (e.g. when there is only 1 level).
    fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode>;

    /// Controls the screen power supply.
    ///
    /// Use it to initialize the display device.
    ///
    /// For screens where display needs nonzero brightness (e.g. LED), this
    /// shall set brightness to a default value if `set_brightness` was not
    /// called first.
    ///
    /// The device may implement power independently from brightness, so call
    /// `set_brightness` to turn on/off the module completely.
    ///
    /// To allow starting in the correct configuration, the driver is allowed to
    /// cache values like brightness or invert mode and apply them together when
    /// power is enabled. If the display cannot use selected configuration, this
    /// call returns `INVAL`.
    ///
    /// When finished, calls `ScreenClient::screen_is_ready`, both when power
    /// is enabled and disabled.
    fn set_power(&self, enabled: bool) -> Result<(), ErrorCode>;

    /// Controls the color inversion mode.
    ///
    /// Pixels already in the frame buffer, as well as newly submitted, will be
    /// inverted. What that means depends on the current pixel format. May get
    /// disabled when switching to another pixel format. Returns `NOSUPPORT` if
    /// the device does not accelerate color inversion. Returns `INVAL` if the
    /// current pixel format does not support color inversion.
    fn set_invert(&self, enabled: bool) -> Result<(), ErrorCode>;
}

pub trait ScreenAdvanced<'a>: Screen<'a> + ScreenSetup<'a> {}
// Provide blanket implementations for trait group
impl<'a, T: Screen<'a> + ScreenSetup<'a>> ScreenAdvanced<'a> for T {}

pub trait ScreenSetupClient {
    /// The screen will call this function to notify that a command has finished.
    fn command_complete(&self, r: Result<(), ErrorCode>);
}

pub trait ScreenClient {
    /// The screen will call this function to notify that a command (except
    /// write) has finished.
    fn command_complete(&self, result: Result<(), ErrorCode>);

    /// The screen will call this function to notify that the write command has
    /// finished. This is different from `command_complete` as it has to pass
    /// back the write buffer
    fn write_complete(&self, buffer: SubSliceMut<'static, u8>, result: Result<(), ErrorCode>);

    /// Some screens need some time to start, this function is called when the
    /// screen is ready.
    fn screen_is_ready(&self);
}