Skip to main content

display_types/
panel.rs

1/// Display technology type, decoded from Display Device Data Block (0x0C) byte 0 bits 7:4.
2///
3/// Identifies the physical display technology used by an embedded panel.
4#[non_exhaustive]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum DisplayTechnology {
8    /// Thin-film transistor LCD, unspecified sub-type (`0`).
9    Tft,
10    /// DSTN or STN (dual-scan or super-twisted nematic LCD) (`1`).
11    DstnStn,
12    /// TFT-IPS or super-TFT (in-plane switching) (`2`).
13    TftIps,
14    /// TFT-MVA or TFT-PVA (multi-domain / patterned vertical alignment) (`3`).
15    TftMva,
16    /// CRT (cathode ray tube) (`4`).
17    Crt,
18    /// PDP (plasma display panel) (`5`).
19    Pdp,
20    /// OLED or ELED (organic light emitting) (`6`).
21    Oled,
22    /// EL (electroluminescent) (`7`).
23    El,
24    /// FED or SED (field emission / surface-conduction electron emission) (`8`).
25    FedSed,
26    /// LCoS (liquid crystal on silicon) (`9`).
27    Lcos,
28    /// Reserved or undefined value (`10`–`15`).
29    Unknown(u8),
30}
31
32impl DisplayTechnology {
33    /// Decodes the display technology from a 4-bit nibble (bits 7:4 of byte 0).
34    pub fn from_nibble(nibble: u8) -> Self {
35        match nibble & 0x0F {
36            0 => Self::Tft,
37            1 => Self::DstnStn,
38            2 => Self::TftIps,
39            3 => Self::TftMva,
40            4 => Self::Crt,
41            5 => Self::Pdp,
42            6 => Self::Oled,
43            7 => Self::El,
44            8 => Self::FedSed,
45            9 => Self::Lcos,
46            v => Self::Unknown(v),
47        }
48    }
49}
50
51/// Panel operating mode, decoded from Display Device Data Block (0x0C) byte 1 bits 3:0.
52#[non_exhaustive]
53#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum OperatingMode {
56    /// Continuous (free-running) refresh (`0`).
57    Continuous,
58    /// Non-continuous (event-driven or line-at-a-time) refresh (`1`).
59    NonContinuous,
60    /// Reserved or undefined value (`2`–`15`).
61    Unknown(u8),
62}
63
64impl OperatingMode {
65    /// Decodes the operating mode from the lower 4 bits of byte 1.
66    pub fn from_nibble(nibble: u8) -> Self {
67        match nibble & 0x0F {
68            0 => Self::Continuous,
69            1 => Self::NonContinuous,
70            v => Self::Unknown(v),
71        }
72    }
73}
74
75/// Backlight type, decoded from Display Device Data Block (0x0C) byte 1 bits 5:4.
76#[non_exhaustive]
77#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum BacklightType {
80    /// No backlight, or not applicable (`0`).
81    None,
82    /// AC fluorescent (CCFL) backlight (`1`).
83    AcFluorescent,
84    /// DC-powered backlight (LED or other) (`2`).
85    Dc,
86    /// Reserved value (`3`).
87    Unknown(u8),
88}
89
90impl BacklightType {
91    /// Decodes the backlight type from a 2-bit value (bits 5:4 of byte 1).
92    pub fn from_bits(bits: u8) -> Self {
93        match bits & 0x03 {
94            0 => Self::None,
95            1 => Self::AcFluorescent,
96            2 => Self::Dc,
97            v => Self::Unknown(v),
98        }
99    }
100}
101
102/// Physical mounting orientation of the panel, decoded from Display Device Data Block (0x0C)
103/// byte 7 bits 1:0.
104#[non_exhaustive]
105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum PhysicalOrientation {
108    /// Landscape — wider than tall (`0`).
109    Landscape,
110    /// Portrait — taller than wide (`1`).
111    Portrait,
112    /// Orientation not defined; may be freely rotated (`2`).
113    NotDefined,
114    /// Undefined / reserved encoding (`3`).
115    Undefined,
116}
117
118impl PhysicalOrientation {
119    /// Decodes the physical orientation from a 2-bit value (bits 1:0 of byte 7).
120    pub fn from_bits(bits: u8) -> Self {
121        match bits & 0x03 {
122            0 => Self::Landscape,
123            1 => Self::Portrait,
124            2 => Self::NotDefined,
125            _ => Self::Undefined,
126        }
127    }
128}
129
130/// Rotation capability, decoded from Display Device Data Block (0x0C) byte 7 bits 3:2.
131#[non_exhaustive]
132#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub enum RotationCapability {
135    /// No display rotation supported (`0`).
136    None,
137    /// 90° clockwise rotation supported (`1`).
138    Cw90,
139    /// 180° rotation supported (`2`).
140    Deg180,
141    /// 270° clockwise (90° counter-clockwise) rotation supported (`3`).
142    Cw270,
143}
144
145impl RotationCapability {
146    /// Decodes the rotation capability from a 2-bit value (bits 3:2 of byte 7).
147    pub fn from_bits(bits: u8) -> Self {
148        match bits & 0x03 {
149            0 => Self::None,
150            1 => Self::Cw90,
151            2 => Self::Deg180,
152            _ => Self::Cw270,
153        }
154    }
155}
156
157/// Location of the zero pixel (the upper-left pixel in the framebuffer), decoded from
158/// Display Device Data Block (0x0C) byte 7 bits 5:4.
159#[non_exhaustive]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub enum ZeroPixelLocation {
163    /// Zero pixel is at the upper-left corner (`0`).
164    UpperLeft,
165    /// Zero pixel is at the upper-right corner (`1`).
166    UpperRight,
167    /// Zero pixel is at the lower-left corner (`2`).
168    LowerLeft,
169    /// Zero pixel is at the lower-right corner (`3`).
170    LowerRight,
171}
172
173impl ZeroPixelLocation {
174    /// Decodes the zero pixel location from a 2-bit value (bits 5:4 of byte 7).
175    pub fn from_bits(bits: u8) -> Self {
176        match bits & 0x03 {
177            0 => Self::UpperLeft,
178            1 => Self::UpperRight,
179            2 => Self::LowerLeft,
180            _ => Self::LowerRight,
181        }
182    }
183}
184
185/// Scan direction of the fast (horizontal) scan relative to H-sync, decoded from
186/// Display Device Data Block (0x0C) byte 7 bits 7:6.
187#[non_exhaustive]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190pub enum ScanDirection {
191    /// Scan direction not defined (`0`).
192    NotDefined,
193    /// Fast scan follows the H-sync direction; slow scan follows V-sync direction (`1`).
194    Normal,
195    /// Fast scan direction is opposite to H-sync; slow scan opposite to V-sync (`2`).
196    Reversed,
197    /// Reserved value (`3`).
198    Reserved,
199}
200
201impl ScanDirection {
202    /// Decodes the scan direction from a 2-bit value (bits 7:6 of byte 7).
203    pub fn from_bits(bits: u8) -> Self {
204        match bits & 0x03 {
205            0 => Self::NotDefined,
206            1 => Self::Normal,
207            2 => Self::Reversed,
208            _ => Self::Reserved,
209        }
210    }
211}
212
213/// Sub-pixel layout, decoded from Display Device Data Block (0x0C) byte 8.
214#[non_exhaustive]
215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum SubpixelLayout {
218    /// Sub-pixel arrangement not defined (`0x00`).
219    NotDefined,
220    /// RGB vertical stripes (`0x01`).
221    RgbVertical,
222    /// BGR vertical stripes (`0x02`).
223    BgrVertical,
224    /// RGB horizontal stripes (`0x03`).
225    RgbHorizontal,
226    /// BGR horizontal stripes (`0x04`).
227    BgrHorizontal,
228    /// Quad arrangement: RGBG (`0x05`).
229    QuadRgbg,
230    /// Quad arrangement: BGRG (`0x06`).
231    QuadBgrg,
232    /// Delta (triangular) RGB arrangement (`0x07`).
233    DeltaRgb,
234    /// Delta (triangular) BGR arrangement (`0x08`).
235    DeltaBgr,
236    /// Reserved or proprietary layout (`0x09`–`0xFF`).
237    Unknown(u8),
238}
239
240impl SubpixelLayout {
241    /// Decodes the sub-pixel layout from the raw byte 8 value.
242    pub fn from_byte(byte: u8) -> Self {
243        match byte {
244            0x00 => Self::NotDefined,
245            0x01 => Self::RgbVertical,
246            0x02 => Self::BgrVertical,
247            0x03 => Self::RgbHorizontal,
248            0x04 => Self::BgrHorizontal,
249            0x05 => Self::QuadRgbg,
250            0x06 => Self::QuadBgrg,
251            0x07 => Self::DeltaRgb,
252            0x08 => Self::DeltaBgr,
253            v => Self::Unknown(v),
254        }
255    }
256}
257
258/// Physical interface standard type, decoded from Display Interface Data Block (0x0F)
259/// byte 0 bits 3:0.
260#[non_exhaustive]
261#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum DisplayInterfaceType {
264    /// Undefined / not specified (`0x0`).
265    Undefined,
266    /// Analog (VGA) interface (`0x1`).
267    Analog,
268    /// LVDS single link (`0x2`).
269    LvdsSingle,
270    /// LVDS dual link (`0x3`).
271    LvdsDual,
272    /// TMDS single link — DVI-D single or HDMI (`0x4`).
273    TmdsSingle,
274    /// TMDS dual link — DVI-DL or HDMI dual (`0x5`).
275    TmdsDual,
276    /// Embedded DisplayPort (eDP) (`0x6`).
277    EmbeddedDisplayPort,
278    /// External DisplayPort (DP) (`0x7`).
279    DisplayPort,
280    /// Proprietary interface (`0x8`).
281    Proprietary,
282    /// Reserved or unrecognized value (`0x9`–`0xF`).
283    Reserved(u8),
284}
285
286impl DisplayInterfaceType {
287    /// Decodes the interface type from the lower 4 bits of byte 0.
288    pub fn from_nibble(nibble: u8) -> Self {
289        match nibble & 0x0F {
290            0x0 => Self::Undefined,
291            0x1 => Self::Analog,
292            0x2 => Self::LvdsSingle,
293            0x3 => Self::LvdsDual,
294            0x4 => Self::TmdsSingle,
295            0x5 => Self::TmdsDual,
296            0x6 => Self::EmbeddedDisplayPort,
297            0x7 => Self::DisplayPort,
298            0x8 => Self::Proprietary,
299            v => Self::Reserved(v),
300        }
301    }
302}
303
304/// Content protection mechanism supported on the display interface, decoded from Display
305/// Interface Data Block (0x0F) byte 6 bits 1:0.
306#[non_exhaustive]
307#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309pub enum InterfaceContentProtection {
310    /// No content protection (`0`).
311    None,
312    /// High-bandwidth Digital Content Protection (HDCP) (`1`).
313    Hdcp,
314    /// DisplayPort Content Protection (DPCP) (`2`).
315    Dpcp,
316    /// Reserved or unrecognized value (`3`).
317    Reserved(u8),
318}
319
320impl InterfaceContentProtection {
321    /// Decodes the content protection type from a 2-bit value (bits 1:0 of byte 6).
322    pub fn from_bits(bits: u8) -> Self {
323        match bits & 0x03 {
324            0 => Self::None,
325            1 => Self::Hdcp,
326            2 => Self::Dpcp,
327            v => Self::Reserved(v),
328        }
329    }
330}
331
332/// Display interface capabilities, decoded from the Display Interface Data Block
333/// (DisplayID 1.x `0x0F`).
334///
335/// Identifies the physical interface type, link characteristics, pixel clock range,
336/// and supported content protection mechanism.
337///
338/// Stored in [`DisplayCapabilities::display_id_interface`][crate::DisplayCapabilities::display_id_interface].
339#[non_exhaustive]
340#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub struct DisplayIdInterface {
343    /// Physical interface standard (LVDS, eDP, DisplayPort, TMDS, etc.).
344    pub interface_type: DisplayInterfaceType,
345    /// Whether spread-spectrum clocking is supported on this interface.
346    pub spread_spectrum: bool,
347    /// Number of data lanes or LVDS pairs (raw count from byte 1 bits 3:0).
348    pub num_lanes: u8,
349    /// Minimum pixel clock in units of 10 kHz (from bytes 2–3, LE uint16).
350    pub min_pixel_clock_10khz: u32,
351    /// Maximum pixel clock in units of 10 kHz (from bytes 4–5, LE uint16).
352    pub max_pixel_clock_10khz: u32,
353    /// Content protection mechanism supported on this interface.
354    pub content_protection: InterfaceContentProtection,
355}
356
357impl DisplayIdInterface {
358    /// Constructs a [`DisplayIdInterface`] from its decoded fields.
359    pub fn new(
360        interface_type: DisplayInterfaceType,
361        spread_spectrum: bool,
362        num_lanes: u8,
363        min_pixel_clock_10khz: u32,
364        max_pixel_clock_10khz: u32,
365        content_protection: InterfaceContentProtection,
366    ) -> Self {
367        Self {
368            interface_type,
369            spread_spectrum,
370            num_lanes,
371            min_pixel_clock_10khz,
372            max_pixel_clock_10khz,
373            content_protection,
374        }
375    }
376}
377
378/// Behavior when one or more tiles are missing from a tiled display, decoded from Tiled
379/// Display Topology Data Block (0x12) byte 0 bits 5:4.
380#[non_exhaustive]
381#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
383pub enum TileTopologyBehavior {
384    /// Behavior is undefined (`0`).
385    Undefined,
386    /// No image is shown until all tiles are present and operational (`1`).
387    RequireAllTiles,
388    /// The image is scaled to fit whatever tiles are currently present (`2`).
389    ScaleWhenMissing,
390    /// Reserved or unrecognized value (`3`).
391    Reserved(u8),
392}
393
394impl TileTopologyBehavior {
395    /// Decodes the topology behavior from a 2-bit value (bits 5:4 of byte 0).
396    pub fn from_bits(bits: u8) -> Self {
397        match bits & 0x03 {
398            0 => Self::Undefined,
399            1 => Self::RequireAllTiles,
400            2 => Self::ScaleWhenMissing,
401            v => Self::Reserved(v),
402        }
403    }
404}
405
406/// Bezel sizes around a single tile, decoded from the optional bezel bytes of the Tiled
407/// Display Topology Data Block (0x12) when the `has_bezel_info` flag is set.
408///
409/// Each field is the bezel width or height in pixels at the tile's native resolution.
410#[non_exhaustive]
411#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
412#[derive(Debug, Clone, Copy, PartialEq, Eq)]
413pub struct TileBezelInfo {
414    /// Top bezel height in pixels.
415    pub top_px: u8,
416    /// Bottom bezel height in pixels.
417    pub bottom_px: u8,
418    /// Right bezel width in pixels.
419    pub right_px: u8,
420    /// Left bezel width in pixels.
421    pub left_px: u8,
422}
423
424impl TileBezelInfo {
425    /// Constructs a [`TileBezelInfo`] from its decoded fields.
426    pub fn new(top_px: u8, bottom_px: u8, right_px: u8, left_px: u8) -> Self {
427        Self {
428            top_px,
429            bottom_px,
430            right_px,
431            left_px,
432        }
433    }
434}
435
436/// Tiled display topology, decoded from the Tiled Display Topology Data Block
437/// (DisplayID 1.x `0x12`).
438///
439/// A tiled display is composed of multiple physical panels (tiles) arranged in a
440/// rectangular grid. Each tile reports its own position and dimensions; the host
441/// assembles the full image across all tiles.
442///
443/// Stored in [`DisplayCapabilities::tiled_topology`][crate::DisplayCapabilities::tiled_topology].
444#[non_exhaustive]
445#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
446#[derive(Debug, Clone, Copy, PartialEq, Eq)]
447pub struct DisplayIdTiledTopology {
448    /// All tiles are housed in a single physical enclosure.
449    pub single_enclosure: bool,
450    /// How the display behaves when one or more tiles are missing.
451    pub topology_behavior: TileTopologyBehavior,
452    /// Total number of horizontal tiles in the grid (1–16).
453    pub h_tile_count: u8,
454    /// Total number of vertical tiles in the grid (1–16).
455    pub v_tile_count: u8,
456    /// Zero-based column index of this tile within the grid.
457    pub h_tile_location: u8,
458    /// Zero-based row index of this tile within the grid.
459    pub v_tile_location: u8,
460    /// Native pixel width of this tile.
461    pub tile_width_px: u16,
462    /// Native pixel height of this tile.
463    pub tile_height_px: u16,
464    /// Per-edge bezel sizes, present when the block's `has_bezel_info` flag is set.
465    pub bezel: Option<TileBezelInfo>,
466}
467
468impl DisplayIdTiledTopology {
469    /// Constructs a [`DisplayIdTiledTopology`] from its decoded fields.
470    #[allow(clippy::too_many_arguments)]
471    pub fn new(
472        single_enclosure: bool,
473        topology_behavior: TileTopologyBehavior,
474        h_tile_count: u8,
475        v_tile_count: u8,
476        h_tile_location: u8,
477        v_tile_location: u8,
478        tile_width_px: u16,
479        tile_height_px: u16,
480        bezel: Option<TileBezelInfo>,
481    ) -> Self {
482        Self {
483            single_enclosure,
484            topology_behavior,
485            h_tile_count,
486            v_tile_count,
487            h_tile_location,
488            v_tile_location,
489            tile_width_px,
490            tile_height_px,
491            bezel,
492        }
493    }
494}
495
496/// Stereo content format, decoded from Stereo Display Interface Data Block (0x10) byte 0
497/// bits 3:0.
498///
499/// Describes how left-eye and right-eye images are encoded in the video signal.
500#[non_exhaustive]
501#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
502#[derive(Debug, Clone, Copy, PartialEq, Eq)]
503pub enum StereoViewingMode {
504    /// Field sequential — left and right frames alternate at double frame rate (`0`).
505    ///
506    /// Requires an external sync signal to the glasses. The polarity of that signal
507    /// is encoded in [`DisplayIdStereoInterface::sync_polarity_positive`].
508    FieldSequential,
509    /// Side-by-side — left and right images packed horizontally at half width each (`1`).
510    SideBySide,
511    /// Top-and-bottom — left and right images packed vertically at half height each (`2`).
512    TopAndBottom,
513    /// Row interleaved — odd display rows carry the left eye, even rows the right eye (`3`).
514    RowInterleaved,
515    /// Column interleaved — odd display columns carry the left eye, even columns the right (`4`).
516    ColumnInterleaved,
517    /// Pixel interleaved / checkerboard — left and right pixels alternate in a
518    /// checkerboard pattern (`5`).
519    PixelInterleaved,
520    /// Reserved or unrecognized value (`6`–`15`).
521    Reserved(u8),
522}
523
524impl StereoViewingMode {
525    /// Decodes the stereo viewing mode from the lower 4 bits of byte 0.
526    pub fn from_nibble(nibble: u8) -> Self {
527        match nibble & 0x0F {
528            0 => Self::FieldSequential,
529            1 => Self::SideBySide,
530            2 => Self::TopAndBottom,
531            3 => Self::RowInterleaved,
532            4 => Self::ColumnInterleaved,
533            5 => Self::PixelInterleaved,
534            v => Self::Reserved(v),
535        }
536    }
537}
538
539/// Physical interface used to deliver stereo synchronization to the glasses, decoded from
540/// Stereo Display Interface Data Block (0x10) byte 1.
541#[non_exhaustive]
542#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
543#[derive(Debug, Clone, Copy, PartialEq, Eq)]
544pub enum StereoSyncInterface {
545    /// Sync delivered via the display's own video connector — no dedicated stereo port (`0`).
546    DisplayConnector,
547    /// VESA 3-pin DIN stereo connector (`1`).
548    VesaDin,
549    /// Infrared (IR) wireless sync (`2`).
550    Infrared,
551    /// Radio frequency (RF) wireless sync (`3`).
552    RadioFrequency,
553    /// Reserved or unrecognized value (`4`–`255`).
554    Reserved(u8),
555}
556
557impl StereoSyncInterface {
558    /// Decodes the stereo sync interface from the raw byte 1 value.
559    pub fn from_byte(byte: u8) -> Self {
560        match byte {
561            0 => Self::DisplayConnector,
562            1 => Self::VesaDin,
563            2 => Self::Infrared,
564            3 => Self::RadioFrequency,
565            v => Self::Reserved(v),
566        }
567    }
568}
569
570/// Stereo display interface parameters, decoded from the Stereo Display Interface Data Block
571/// (DisplayID 1.x `0x10`).
572///
573/// Describes how stereoscopic 3D content is encoded and how synchronization is delivered
574/// to active-shutter glasses.
575///
576/// Stored in [`DisplayCapabilities::stereo_interface`][crate::DisplayCapabilities::stereo_interface].
577#[non_exhaustive]
578#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
579#[derive(Debug, Clone, Copy, PartialEq, Eq)]
580pub struct DisplayIdStereoInterface {
581    /// How left-eye and right-eye images are encoded in the video signal.
582    pub viewing_mode: StereoViewingMode,
583    /// Polarity of the 3D sync signal sent to the glasses.
584    ///
585    /// `true` = positive (glasses open left eye on high); `false` = negative.
586    /// Only meaningful for [`StereoViewingMode::FieldSequential`].
587    pub sync_polarity_positive: bool,
588    /// Physical channel used to deliver the sync signal to the glasses.
589    pub sync_interface: StereoSyncInterface,
590}
591
592impl DisplayIdStereoInterface {
593    /// Constructs a [`DisplayIdStereoInterface`] from its decoded fields.
594    pub fn new(
595        viewing_mode: StereoViewingMode,
596        sync_polarity_positive: bool,
597        sync_interface: StereoSyncInterface,
598    ) -> Self {
599        Self {
600            viewing_mode,
601            sync_polarity_positive,
602            sync_interface,
603        }
604    }
605}
606
607/// Panel interface power sequencing timing parameters, decoded from the Interface Power
608/// Sequencing Block (DisplayID 1.x `0x0D`).
609///
610/// Describes the minimum delays required when powering the display panel on and off.
611/// All fields are raw counts in **2 ms units** per the DisplayID 1.x §4.11 specification;
612/// multiply by 2 to obtain milliseconds.
613///
614/// The six parameters (T1–T6) follow the standard LVDS/eDP power sequencing model:
615///
616/// ```text
617/// Power-on:   [VCC on] →T1→ [Signal on] →T2→ [Backlight on]
618/// Power-off:  [Backlight off] →T3→ [Signal off] →T4→ [VCC off]
619/// Minimum off time: T5 (VCC), T6 (Backlight)
620/// ```
621#[non_exhaustive]
622#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
623#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
624pub struct PowerSequencing {
625    /// T1: minimum delay from power supply enable to interface signal valid (2 ms units).
626    pub t1_power_to_signal: u8,
627    /// T2: minimum delay from interface signal enable to backlight enable (2 ms units).
628    pub t2_signal_to_backlight: u8,
629    /// T3: minimum delay from backlight disable to interface signal disable (2 ms units).
630    pub t3_backlight_to_signal_off: u8,
631    /// T4: minimum delay from interface signal disable to power supply disable (2 ms units).
632    pub t4_signal_to_power_off: u8,
633    /// T5: minimum power supply off time before power can be re-applied (2 ms units).
634    pub t5_power_off_min: u8,
635    /// T6: minimum backlight off time (2 ms units).
636    pub t6_backlight_off_min: u8,
637}
638
639impl PowerSequencing {
640    /// Constructs a [`PowerSequencing`] from its decoded T1–T6 timing fields.
641    pub fn new(
642        t1_power_to_signal: u8,
643        t2_signal_to_backlight: u8,
644        t3_backlight_to_signal_off: u8,
645        t4_signal_to_power_off: u8,
646        t5_power_off_min: u8,
647        t6_backlight_off_min: u8,
648    ) -> Self {
649        Self {
650            t1_power_to_signal,
651            t2_signal_to_backlight,
652            t3_backlight_to_signal_off,
653            t4_signal_to_power_off,
654            t5_power_off_min,
655            t6_backlight_off_min,
656        }
657    }
658}