display_driver/bus/mod.rs
1#[cfg(feature = "display-interface")]
2mod display_interface_impl;
3
4pub mod qspi_flash;
5pub use qspi_flash::QspiFlashBus;
6
7pub mod simple;
8pub use simple::SimpleDisplayBus;
9
10use crate::{Area, DisplayError, SolidColor};
11
12/// Error type trait.
13///
14/// This just defines the error type, to be used by the other traits.
15pub trait ErrorType {
16 /// Error type
17 type Error: core::fmt::Debug;
18}
19
20#[derive(Debug, Clone, Copy, Default)]
21pub struct FrameControl {
22 pub first: bool,
23 pub last: bool,
24}
25
26impl FrameControl {
27 pub fn new_standalone() -> Self {
28 Self {
29 first: true,
30 last: true,
31 }
32 }
33
34 pub fn new_first() -> Self {
35 Self {
36 first: true,
37 last: false,
38 }
39 }
40
41 pub fn new_last() -> Self {
42 Self {
43 first: false,
44 last: true,
45 }
46 }
47}
48
49/// Metadata about the pixel data transfer.
50///
51/// Advanced display buses (like MIPI DSI or QSPI with DMA) often require more context than just the
52/// raw pixel bytes.
53/// This struct carries that side-band information, allowing the bus implementation to orchestrate
54/// the transfer correctly.
55#[derive(Clone, Copy, Debug)]
56pub struct Metadata {
57 /// The rectangular area on the display this data corresponds to.
58 ///
59 /// If `Some`, the bus may use this to set the active window before sending data.
60 /// If `None`, the data is assumed to be a continuation of the previous stream.
61 pub area: Option<Area>,
62 /// Flags for frame synchronization (start/end of frame).
63 pub frame_control: FrameControl,
64}
65
66impl Metadata {
67 /// Creates metadata for a full screen update.
68 ///
69 /// This sets the area to the full display dimensions and marks the transfer as both the start
70 /// and end of a frame.
71 /// Use this for standard full-frame refreshing.
72 pub fn new_full_screen(w: u16, h: u16) -> Self {
73 Self {
74 area: Some(Area::from_origin(w, h)),
75 frame_control: FrameControl {
76 first: true,
77 last: true,
78 },
79 }
80 }
81
82 /// Creates metadata for continuing a stream of pixel data without resetting the area or frame
83 /// markers.
84 ///
85 /// Use this when splitting a large frame into multiple smaller chunks for transfer.
86 pub fn new_continue_stream() -> Self {
87 Self {
88 area: None,
89 frame_control: FrameControl {
90 first: false,
91 last: false,
92 },
93 }
94 }
95
96 /// Creates metadata with specific area and frame control settings.
97 ///
98 /// Use this for partial updates or specialized transfer patterns.
99 pub fn new_from_parts(area: Option<Area>, frame_control: FrameControl) -> Self {
100 Self {
101 area,
102 frame_control,
103 }
104 }
105}
106
107#[allow(async_fn_in_trait)]
108/// The core interface for all display bus implementations.
109///
110/// This trait serves as the abstraction layer between the high-level drawing logic and the
111/// low-level transport protocol. It accommodates a wide range of hardware, from simple 2-wire
112/// interfaces to complex high-speed buses.
113///
114/// The interface distinguishes between two types of traffic:
115/// - **Commands**: Small, latency-sensitive messages used for configuration (handled by `write_cmd`
116/// and `write_cmd_with_params`).
117/// - **Pixels**: Large, throughput-critical data streams used for changing the visual content
118/// (handled by `write_pixels`).
119///
120/// This separation allows for optimizations. For instance, `write_pixels` accepts [`Metadata`],
121/// enabling the underlying implementation to utilize hardware accelerators (like DMA or QSPI
122/// peripherals) that can handle address setting and bulk data transfer efficiently.
123pub trait DisplayBus: ErrorType {
124 /// Writes a command to the display.
125 ///
126 /// This is typically used for setting registers or sending configuration opcodes.
127 async fn write_cmd(&mut self, cmd: &[u8]) -> Result<(), Self::Error>;
128
129 // async fn write_cmds(&mut self, cmds: &[u8]) -> Result<(), Self::Error>;
130
131 /// Writes a command followed immediately by its parameters.
132 ///
133 /// This guarantees an atomic transaction where the command and parameters are sent without
134 /// interruption. This is critical for many display controllers that expect the parameter bytes
135 /// to immediately follow the command byte while the Chip Select (CS) line remains active.
136 async fn write_cmd_with_params(&mut self, cmd: &[u8], params: &[u8])
137 -> Result<(), Self::Error>;
138
139 /// Writes a stream of pixel data to the display.
140 ///
141 /// # Arguments
142 /// * `cmd` - The memory write command (e.g., `0x2C` for standard MIPI DCS).
143 /// * `data` - The raw pixel data bytes.
144 /// * `metadata` - Contextual information about this transfer, including the target area and
145 /// frame boundaries.
146 ///
147 /// Implementations should use the `metadata` to handle frame synchronization (VSYNC/TE) before
148 /// sending the pixel data.
149 async fn write_pixels(
150 &mut self,
151 cmd: &[u8],
152 data: &[u8],
153 metadata: Metadata,
154 ) -> Result<(), DisplayError<Self::Error>>;
155
156 /// Resets the screen via the bus (optional).
157 ///
158 /// Note: This method should only be implemented if the hardware has a physical Reset pin.
159 /// Avoid adding a Pin field to your `DisplayBus` wrapper for this purpose; use `LCDResetOption`
160 /// instead.
161 fn set_reset(&mut self, reset: bool) -> Result<(), DisplayError<Self::Error>> {
162 let _ = reset;
163 Err(DisplayError::Unsupported)
164 }
165}
166
167#[allow(async_fn_in_trait)]
168/// An optional trait for buses that support hardware-accelerated solid color filling.
169///
170/// Filling a large area with a single color is a common operation (e.g., clearing the screen).
171/// If the hardware supports it (e.g., via a 2D GPU or a DMA channel with a non-incrementing source
172/// address), this trait allows the driver to offload that work, significantly reducing CPU usage
173/// and bus traffic.
174pub trait BusHardwareFill: DisplayBus {
175 /// Fills a specific region of the display with a solid color.
176 ///
177 /// The implementation should leverage available hardware acceleration to perform this operation
178 /// efficiently.
179 async fn fill_solid(
180 &mut self,
181 cmd: &[u8],
182 color: SolidColor,
183 area: Area,
184 ) -> Result<(), DisplayError<Self::Error>>;
185}
186
187#[allow(async_fn_in_trait)]
188/// An optional trait for buses that support reading data back from the display.
189///
190/// While most display interactions are write-only, reading is sometimes necessary for:
191/// - Verifying the connection by reading the display ID.
192/// - Checking status registers.
193/// - Reading back frame memory (e.g., for screenshots), though this is less common.
194///
195/// Not all physical interfaces support bi-directional communication (e.g., SPI TFT is often
196/// write-only).
197pub trait BusRead: DisplayBus {
198 /// Reads data from the display.
199 ///
200 /// # Arguments
201 /// * `cmd` - The command to initiate the read operation.
202 /// * `params` - Optional parameters required before the read transaction begins.
203 /// * `buffer` - The destination buffer where the read data will be stored.
204 async fn read_data(
205 &mut self,
206 cmd: &[u8],
207 params: &[u8],
208 buffer: &mut [u8],
209 ) -> Result<(), DisplayError<Self::Error>> {
210 let (_, _, _) = (cmd, params, buffer);
211 Err(DisplayError::Unsupported)
212 }
213}
214
215/// An optional trait for buses that support non-atomic command and data writing.
216///
217/// Some buses, such as SPI, support sending commands and data in a single transaction, while others
218/// require separate transactions for commands and data.
219#[allow(async_fn_in_trait)]
220pub trait BusBytesIo: DisplayBus {
221 /// Writes a sequence of commands to the bus.
222 ///
223 /// This is typically used for sending register addresses or command opcodes.
224 async fn write_cmd_bytes(&mut self, cmd: &[u8]) -> Result<(), Self::Error>;
225
226 /// Writes a sequence of data bytes to the bus.
227 ///
228 /// This is used for sending command parameters or pixel data.
229 async fn write_data_bytes(&mut self, data: &[u8]) -> Result<(), Self::Error>;
230}