use crate::model::capabilities::{ModeSink, VideoMode};
pub(super) fn decode_type_iii_descriptor(d: &[u8; 3], sink: &mut dyn ModeSink) {
let aspect_code = d[0] & 0x0F;
let h_active = ((d[1] as u16) + 1) * 8;
let interlaced = (d[2] & 0x80) != 0;
let refresh_rate = (d[2] & 0x7F) + 1;
let (ar_h, ar_w): (u32, u32) = match aspect_code {
0 => (1, 1), 1 => (4, 5), 2 => (3, 4), 3 => (9, 15), 4 => (9, 16), 5 => (10, 16), 6 => (27, 64), 7 => (135, 256), _ => return, };
let v_raw = (h_active as u32) * ar_h;
if v_raw % ar_w != 0 {
return; }
let v_active = (v_raw / ar_w) as u16;
if v_active == 0 {
return;
}
sink.push_mode(VideoMode::new(h_active, v_active, refresh_rate, interlaced));
}
pub(super) fn decode_type_v_descriptor(d: &[u8; 7], sink: &mut dyn ModeSink) {
let h_active = u16::from_le_bytes([d[1], d[2]]);
let v_active = u16::from_le_bytes([d[3], d[4]]);
let refresh_rate = ((d[5] as u16) + 1).min(255) as u8;
if h_active == 0 || v_active == 0 {
return;
}
sink.push_mode(VideoMode::new(h_active, v_active, refresh_rate, false)); }
#[cfg(test)]
#[cfg(any(feature = "alloc", feature = "std"))]
mod tests {
use super::*;
use crate::model::capabilities::DisplayCapabilities;
fn make_type_iii_descriptor(
preferred: bool,
algo: u8,
aspect: u8,
h_raw: u8,
interlaced: bool,
refresh_raw: u8,
) -> [u8; 3] {
let byte0 = ((preferred as u8) << 7) | ((algo & 0x07) << 4) | (aspect & 0x0F);
let byte2 = ((interlaced as u8) << 7) | (refresh_raw & 0x7F);
[byte0, h_raw, byte2]
}
#[test]
fn test_type_iii_16_9_decoded() {
let d = make_type_iii_descriptor(false, 0, 0x04, 239, false, 59);
let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
let mode = &caps.supported_modes[0];
assert_eq!(mode.width, 1920);
assert_eq!(mode.height, 1080);
assert_eq!(mode.refresh_rate, 60);
assert!(!mode.interlaced);
}
#[test]
fn test_type_iii_4_3_decoded() {
let d = make_type_iii_descriptor(false, 0, 0x02, 127, false, 74);
let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 1024);
assert_eq!(caps.supported_modes[0].height, 768);
assert_eq!(caps.supported_modes[0].refresh_rate, 75);
}
#[test]
fn test_type_iii_interlaced_flag() {
let d = make_type_iii_descriptor(false, 0, 0x04, 239, true, 59);
let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert!(caps.supported_modes[0].interlaced);
}
#[test]
fn test_type_iii_undefined_aspect_skipped() {
let d = make_type_iii_descriptor(false, 0, 0x08, 239, false, 59);
let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_type_iii_non_integer_height_skipped() {
let d = make_type_iii_descriptor(false, 0, 0x04, 0, false, 59);
let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_type_iii_multiple_aspect_ratios() {
let d1 = make_type_iii_descriptor(false, 0, 0x04, 239, false, 59); let d2 = make_type_iii_descriptor(false, 0, 0x02, 159, false, 59); let d3 = make_type_iii_descriptor(false, 0, 0x05, 159, false, 59); let mut caps = DisplayCapabilities::default();
decode_type_iii_descriptor(&d1, &mut caps);
decode_type_iii_descriptor(&d2, &mut caps);
decode_type_iii_descriptor(&d3, &mut caps);
assert_eq!(caps.supported_modes.len(), 3);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1920 && m.height == 1080)
);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1280 && m.height == 960)
);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1280 && m.height == 800)
);
}
fn make_type_v_descriptor(h_active: u16, v_active: u16, refresh_raw: u8) -> [u8; 7] {
let mut d = [0u8; 7];
d[1..3].copy_from_slice(&h_active.to_le_bytes());
d[3..5].copy_from_slice(&v_active.to_le_bytes());
d[5] = refresh_raw;
d
}
#[test]
fn test_type_v_1920x1080_at_60hz() {
let d = make_type_v_descriptor(1920, 1080, 59);
let mut caps = DisplayCapabilities::default();
decode_type_v_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
let mode = &caps.supported_modes[0];
assert_eq!(mode.width, 1920);
assert_eq!(mode.height, 1080);
assert_eq!(mode.refresh_rate, 60);
assert!(!mode.interlaced);
}
#[test]
fn test_type_v_refresh_raw_255_clamped_to_255() {
let d = make_type_v_descriptor(3840, 2160, 255);
let mut caps = DisplayCapabilities::default();
decode_type_v_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].refresh_rate, 255);
}
#[test]
fn test_type_v_zero_width_skipped() {
let d = make_type_v_descriptor(0, 1080, 59);
let mut caps = DisplayCapabilities::default();
decode_type_v_descriptor(&d, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_type_v_zero_height_skipped() {
let d = make_type_v_descriptor(1920, 0, 59);
let mut caps = DisplayCapabilities::default();
decode_type_v_descriptor(&d, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_type_v_large_resolution() {
let d = make_type_v_descriptor(7680, 4320, 119);
let mut caps = DisplayCapabilities::default();
decode_type_v_descriptor(&d, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 7680);
assert_eq!(caps.supported_modes[0].height, 4320);
assert_eq!(caps.supported_modes[0].refresh_rate, 120);
}
}