use crate::capabilities::cea861::{dmt_to_mode, vic_to_mode};
use crate::model::capabilities::{ModeSink, VideoMode};
pub(super) fn decode_type_iv_block(payload: &[u8], code_type: u8, sink: &mut dyn ModeSink) {
for &code in payload {
let mode = match code_type {
0 => dmt_to_mode(code as u16),
1 => vic_to_mode(code),
2 => hdmi_vic_to_mode(code),
_ => None,
};
if let Some(m) = mode {
sink.push_mode(m);
}
}
}
fn hdmi_vic_to_mode(code: u8) -> Option<VideoMode> {
let (w, h, r): (u16, u16, u8) = match code {
1 => (3840, 2160, 30),
2 => (3840, 2160, 25),
3 => (3840, 2160, 24),
4 => (4096, 2160, 24),
_ => return None,
};
Some(VideoMode::new(w, h, r, false))
}
pub(super) fn decode_vesa_video_timing_block(payload: &[u8], sink: &mut dyn ModeSink) {
for (byte_idx, &byte) in payload.iter().take(10).enumerate() {
for bit in 0u16..8 {
if byte & (1 << bit) != 0 {
let dmt_id = (byte_idx as u16) * 8 + bit + 1;
if let Some(mode) = dmt_to_mode(dmt_id) {
sink.push_mode(mode);
}
}
}
}
}
pub(super) fn decode_cta_video_timing_block(payload: &[u8], sink: &mut dyn ModeSink) {
for (byte_idx, &byte) in payload.iter().take(8).enumerate() {
for bit in 0u8..8 {
if byte & (1 << bit) != 0 {
let vic = (byte_idx as u8) * 8 + bit + 1;
if let Some(mode) = vic_to_mode(vic) {
sink.push_mode(mode);
}
}
}
}
}
#[cfg(test)]
#[cfg(any(feature = "alloc", feature = "std"))]
mod tests {
use super::*;
use crate::model::capabilities::{DisplayCapabilities, SyncDefinition};
#[test]
fn test_type_iv_dmt_decoded() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0x52], 0, &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);
assert_eq!(mode.h_front_porch, 88);
assert_eq!(mode.h_sync_width, 44);
assert_eq!(mode.v_front_porch, 4);
assert_eq!(mode.v_sync_width, 5);
assert_eq!(
mode.sync,
Some(SyncDefinition::DigitalSeparate {
h_sync_positive: true,
v_sync_positive: true,
})
);
}
#[test]
fn test_type_iv_dmt_interlaced() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0x0F], 0, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
let mode = &caps.supported_modes[0];
assert_eq!(mode.width, 1024);
assert_eq!(mode.height, 768);
assert_eq!(mode.refresh_rate, 43);
assert!(mode.interlaced);
}
#[test]
fn test_type_iv_vic_decoded() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[1], 1, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 640);
assert_eq!(caps.supported_modes[0].height, 480);
assert_eq!(caps.supported_modes[0].refresh_rate, 60);
}
#[test]
fn test_type_iv_hdmi_vic_decoded() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[1], 2, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 3840);
assert_eq!(caps.supported_modes[0].height, 2160);
assert_eq!(caps.supported_modes[0].refresh_rate, 30);
}
#[test]
fn test_type_iv_unknown_dmt_skipped() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0xFF], 0, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_type_iv_multiple_codes() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0x10, 0x23, 0x52], 0, &mut caps);
assert_eq!(caps.supported_modes.len(), 3);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1024 && m.height == 768)
);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1280 && m.height == 1024)
);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 1920 && m.height == 1080)
);
}
#[test]
fn test_type_iv_mixed_known_unknown_dmt_codes() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0xFE, 0x23, 0xFF], 0, &mut caps); assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 1280);
assert_eq!(caps.supported_modes[0].height, 1024);
assert_eq!(caps.supported_modes[0].refresh_rate, 60);
}
#[test]
fn test_type_iv_reserved_code_type_skipped() {
let mut caps = DisplayCapabilities::default();
decode_type_iv_block(&[0x52], 3, &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_vesa_timing_single_bit_set() {
let mut caps = DisplayCapabilities::default();
decode_vesa_video_timing_block(&[0b0000_1000], &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
let mode = &caps.supported_modes[0];
assert_eq!(mode.width, 640);
assert_eq!(mode.height, 480);
assert_eq!(mode.refresh_rate, 60);
assert_eq!(mode.h_front_porch, 16);
assert_eq!(mode.h_sync_width, 96);
assert_eq!(mode.v_front_porch, 10);
assert_eq!(mode.v_sync_width, 2);
assert_eq!(
mode.sync,
Some(SyncDefinition::DigitalSeparate {
h_sync_positive: false,
v_sync_positive: false,
})
);
}
#[test]
fn test_vesa_timing_multiple_modes() {
let mut caps = DisplayCapabilities::default();
decode_vesa_video_timing_block(&[0x01, 0x01], &mut caps);
assert_eq!(caps.supported_modes.len(), 2);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 640 && m.height == 350)
);
assert!(
caps.supported_modes
.iter()
.any(|m| m.width == 800 && m.height == 600)
);
}
#[test]
fn test_vesa_timing_empty_payload() {
let mut caps = DisplayCapabilities::default();
decode_vesa_video_timing_block(&[], &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_vesa_timing_payload_truncated_at_10_bytes() {
let mut bitmap = vec![0u8; 11];
bitmap[10] = 0xFF; bitmap[0] = 0x01; let mut caps = DisplayCapabilities::default();
decode_vesa_video_timing_block(&bitmap, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 640);
assert_eq!(caps.supported_modes[0].height, 350);
}
#[test]
fn test_cta_timing_single_bit_set() {
let mut caps = DisplayCapabilities::default();
decode_cta_video_timing_block(&[0x01], &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
let mode = &caps.supported_modes[0];
assert_eq!(mode.width, 640);
assert_eq!(mode.height, 480);
assert_eq!(mode.refresh_rate, 60);
assert!(mode.h_front_porch != 0 || mode.h_sync_width != 0);
}
#[test]
fn test_cta_timing_multiple_modes() {
let mut caps = DisplayCapabilities::default();
decode_cta_video_timing_block(&[0x03], &mut caps);
assert_eq!(caps.supported_modes.len(), 2);
}
#[test]
fn test_cta_timing_empty_payload() {
let mut caps = DisplayCapabilities::default();
decode_cta_video_timing_block(&[], &mut caps);
assert!(caps.supported_modes.is_empty());
}
#[test]
fn test_cta_timing_payload_truncated_at_8_bytes() {
let mut bitmap = vec![0u8; 9];
bitmap[8] = 0xFF; bitmap[0] = 0x01; let mut caps = DisplayCapabilities::default();
decode_cta_video_timing_block(&bitmap, &mut caps);
assert_eq!(caps.supported_modes.len(), 1);
assert_eq!(caps.supported_modes[0].width, 640);
}
}