use hdmi_hal_async::scdc::ScdcTransport;
use crate::ScdcError;
use crate::{CedCounters, RsCorrectionCount};
use culvert::codec;
use super::Scdc;
impl<T: ScdcTransport> Scdc<T> {
pub async fn read_ced(&mut self) -> Result<CedCounters, ScdcError<T::Error>> {
let mut bytes = [0; 8];
for (byte, reg) in bytes.iter_mut().zip(codec::CED_REGISTERS) {
*byte = self
.transport
.read(reg)
.await
.map_err(ScdcError::Transport)?;
}
Ok(codec::decode_ced(bytes))
}
pub async fn read_rs_correction(
&mut self,
) -> Result<Option<RsCorrectionCount>, ScdcError<T::Error>> {
let low = self
.transport
.read(codec::RS_CORRECTION_L)
.await
.map_err(ScdcError::Transport)?;
let high = self
.transport
.read(codec::RS_CORRECTION_H)
.await
.map_err(ScdcError::Transport)?;
Ok(codec::decode_rs_correction(low, high))
}
}
#[cfg(test)]
mod tests {
use super::super::Scdc;
use super::super::test_transport::{Op, TestTransport};
use crate::CedCount;
use crate::ScdcError;
#[pollster::test]
async fn ced_validity_bit_required() {
let mut sim = TestTransport::new();
sim.set(0x50, 0xFF);
sim.set(0x51, 0x7F); let ced = Scdc::new(sim).read_ced().await.unwrap();
assert_eq!(ced.lane0, None);
}
#[pollster::test]
async fn ced_counter_validity_bit_stripped() {
let mut sim = TestTransport::new();
sim.set(0x50, 0x23);
sim.set(0x51, 0x81);
let ced = Scdc::new(sim).read_ced().await.unwrap();
assert_eq!(ced.lane0, Some(CedCount::new(0x0123)));
}
#[pollster::test]
async fn ced_lane3_independent() {
let mut sim = TestTransport::new();
sim.set(0x56, 0xAA); sim.set(0x57, 0x01);
sim.set(0x58, 0x80); let ced = Scdc::new(sim).read_ced().await.unwrap();
assert_eq!(ced.lane0, None);
assert_eq!(ced.lane3.map(|c| c.value()), Some(0x0001));
}
#[pollster::test]
async fn read_ced_reads_each_counter_register_once_in_order() {
let mut scdc = Scdc::new(TestTransport::new());
scdc.read_ced().await.unwrap();
let reads = [0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x57, 0x58].map(|r| Some(Op::Read(r)));
let log = scdc.into_transport().log();
assert_eq!(log[..8], reads);
assert_eq!(log[8], None);
}
#[pollster::test]
async fn read_rs_correction_reads_low_then_high() {
let mut scdc = Scdc::new(TestTransport::new());
scdc.read_rs_correction().await.unwrap();
assert_eq!(
scdc.into_transport().log()[..3],
[Some(Op::Read(0x59)), Some(Op::Read(0x5A)), None]
);
}
#[pollster::test]
async fn ced_each_lane_from_its_own_registers() {
let mut sim = TestTransport::new();
for (low, value) in [(0x50, 0x02), (0x52, 0x04), (0x54, 0x06)] {
sim.set(low, value);
sim.set(low + 1, 0x80 | (value + 1));
}
sim.set(0x56, 0xFF); sim.set(0x57, 0x08);
sim.set(0x58, 0x89);
let ced = Scdc::new(sim).read_ced().await.unwrap();
assert_eq!(ced.lane0.map(|c| c.value()), Some(0x0302));
assert_eq!(ced.lane1.map(|c| c.value()), Some(0x0504));
assert_eq!(ced.lane2.map(|c| c.value()), Some(0x0706));
assert_eq!(ced.lane3.map(|c| c.value()), Some(0x0908));
}
#[pollster::test]
async fn transport_error_on_any_read() {
for n in 0..8 {
assert!(
Scdc::new(TestTransport::failing_after(n))
.read_ced()
.await
.is_err_and(|error| matches!(error, ScdcError::Transport(())))
);
}
}
#[pollster::test]
async fn rs_correction_valid_and_invalid() {
let mut sim = TestTransport::new();
sim.set(0x59, 0x34);
sim.set(0x5A, 0x81); assert_eq!(
Scdc::new(sim)
.read_rs_correction()
.await
.unwrap()
.map(|c| c.value()),
Some(0x0134)
);
let mut sim = TestTransport::new();
sim.set(0x59, 0xFF);
sim.set(0x5A, 0x7F); assert_eq!(Scdc::new(sim).read_rs_correction().await.unwrap(), None);
}
#[pollster::test]
async fn rs_correction_transport_error() {
for n in 0..2 {
assert!(
Scdc::new(TestTransport::failing_after(n))
.read_rs_correction()
.await
.is_err_and(|error| matches!(error, ScdcError::Transport(())))
);
}
}
}