display_types/cea861/vtdb.rs
1use crate::VideoMode;
2#[cfg(any(feature = "alloc", feature = "std"))]
3use crate::prelude::Vec;
4
5/// A decoded DisplayID Type VII Video Timing Data Block (T7VTDB, extended tag `0x22`).
6///
7/// Each CTA T7VTDB carries exactly one 20-byte DisplayID-style timing descriptor.
8/// Unlike an 18-byte EDID DTD, the pixel clock is expressed in kHz (not 10 kHz units)
9/// and all horizontal/vertical fields are 16-bit rather than packed.
10///
11/// Multiple T7VTDBs are permitted per CTA extension block (one timing per block).
12/// Per CTA-861, `interlaced` shall always be `false`; `y420` reflects the T7Y420 flag.
13#[non_exhaustive]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[derive(Debug, Clone, PartialEq)]
16pub struct T7VtdbBlock {
17 /// Block revision (`Block_Rev` field, bits 2:0 of the descriptor header byte).
18 /// CTA-861 expects revision `0x02`.
19 pub version: u8,
20 /// Decoded video timing for this descriptor.
21 pub mode: VideoMode,
22 /// When `true`, this timing also supports YCbCr 4:2:0 sampling (T7Y420 flag).
23 pub y420: bool,
24}
25
26impl T7VtdbBlock {
27 /// Constructs a `T7VtdbBlock`.
28 pub fn new(version: u8, mode: VideoMode, y420: bool) -> Self {
29 Self {
30 version,
31 mode,
32 y420,
33 }
34 }
35}
36
37/// A decoded DisplayID Type VIII Video Timing Data Block (T8VTDB, extended tag `0x23`).
38///
39/// Contains a list of VESA DMT (Display Monitor Timings) ID codes referencing
40/// standardised monitor timings. Only `Code_Type = 0x00` (DMT) is defined by
41/// CTA-861; other code types are returned as `None` by the parser.
42///
43/// Codes whose DMT IDs are not in the standard table are stored in `codes` but
44/// omitted from `timings`.
45#[non_exhaustive]
46#[cfg(any(feature = "alloc", feature = "std"))]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48#[derive(Debug, Clone, PartialEq)]
49pub struct T8VtdbBlock {
50 /// Block revision (`Block_Rev` field, bits 2:0).
51 pub version: u8,
52 /// When `true`, all timings also support YCbCr 4:2:0 sampling (T8Y420 flag).
53 pub y420: bool,
54 /// Raw DMT timing codes as they appear in the block (1-byte or 2-byte each).
55 pub codes: Vec<u16>,
56 /// `VideoMode` values resolved from the DMT codes. Entries for unrecognised
57 /// or reserved DMT IDs are omitted.
58 pub timings: Vec<VideoMode>,
59}
60
61#[cfg(any(feature = "alloc", feature = "std"))]
62impl T8VtdbBlock {
63 /// Constructs a `T8VtdbBlock`.
64 pub fn new(version: u8, y420: bool, codes: Vec<u16>, timings: Vec<VideoMode>) -> Self {
65 Self {
66 version,
67 y420,
68 codes,
69 timings,
70 }
71 }
72}
73
74/// A single timing entry from a T10VTDB block.
75///
76/// Type X timings use a CVT formula to derive the full signal, but only the
77/// display-facing parameters (resolution and refresh rate) are exposed here.
78#[non_exhaustive]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80#[derive(Debug, Clone, PartialEq, Eq)]
81pub struct T10VtdbEntry {
82 /// Horizontal active pixels.
83 pub width: u16,
84 /// Vertical active lines.
85 pub height: u16,
86 /// Vertical refresh rate in Hz (1–1024).
87 ///
88 /// Values above 255 are only possible when the block uses 7- or 8-byte
89 /// descriptors (M ≥ 1 in the `rev` byte).
90 pub refresh_hz: u16,
91 /// When `true`, this timing also supports YCbCr 4:2:0 sampling (YCC420 flag).
92 pub y420: bool,
93}
94
95impl T10VtdbEntry {
96 /// Constructs a `T10VtdbEntry`.
97 pub fn new(width: u16, height: u16, refresh_hz: u16, y420: bool) -> Self {
98 Self {
99 width,
100 height,
101 refresh_hz,
102 y420,
103 }
104 }
105}
106
107/// A decoded DisplayID Type X Video Timing Data Block (T10VTDB, extended tag `0x2A`).
108///
109/// Type X timings are CVT formula-based: each descriptor encodes the active
110/// resolution and refresh rate directly, with blanking derived by the display.
111/// A block may contain 1–4 descriptors (limited by the 30-byte CTA extended
112/// block payload cap).
113#[non_exhaustive]
114#[cfg(any(feature = "alloc", feature = "std"))]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct T10VtdbBlock {
118 /// Decoded timing entries. Each entry corresponds to one descriptor in the block.
119 pub entries: Vec<T10VtdbEntry>,
120}
121
122#[cfg(any(feature = "alloc", feature = "std"))]
123impl T10VtdbBlock {
124 /// Constructs a `T10VtdbBlock`.
125 pub fn new(entries: Vec<T10VtdbEntry>) -> Self {
126 Self { entries }
127 }
128}
129
130/// Decoded VESA Video Timing Block Extension (extended tag `0x03`).
131///
132/// Carries additional video timing modes beyond what fits in the base EDID block.
133/// Each block may contain Detailed Timing Descriptors (DTBs), Coordinated Video
134/// Timings (CVTs), and Standard Timing (ST) entries, per the VESA VTB-EXT Standard,
135/// Release A.
136#[non_exhaustive]
137#[cfg(any(feature = "alloc", feature = "std"))]
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139#[derive(Debug, Clone, PartialEq)]
140pub struct VtbExtBlock {
141 /// VTB-EXT version byte (expected `0x01`).
142 pub version: u8,
143 /// All video modes decoded from this block (DTBs, CVTs, and STs combined).
144 pub timings: Vec<VideoMode>,
145}
146
147#[cfg(any(feature = "alloc", feature = "std"))]
148impl VtbExtBlock {
149 /// Constructs a `VtbExtBlock`.
150 pub fn new(version: u8, timings: Vec<VideoMode>) -> Self {
151 Self { version, timings }
152 }
153}