use {
std::{
fmt,
},
crate::error::Result,
super::{
FeDevice,
sys::*,
},
};
#[derive(Debug)]
pub struct FeStatus {
status: u32,
props: [DtvProperty; 6],
}
const IDX_DELIVERY_SYSTEM: usize = 0;
const IDX_MODULATION: usize = 1;
const IDX_SIGNAL_STRENGTH: usize = 2;
const IDX_SNR: usize = 3;
const IDX_BER: usize = 4;
const IDX_UNC: usize = 5;
impl Default for FeStatus {
fn default() -> FeStatus {
FeStatus {
status: 0,
props: [
DtvProperty::new(DTV_DELIVERY_SYSTEM, FE_NONE),
DtvProperty::new(DTV_MODULATION, QPSK),
DtvProperty::new(DTV_STAT_SIGNAL_STRENGTH, 0),
DtvProperty::new(DTV_STAT_CNR, 0),
DtvProperty::new(DTV_STAT_PRE_ERROR_BIT_COUNT, 0),
DtvProperty::new(DTV_STAT_ERROR_BLOCK_COUNT, 0),
],
}
}
}
impl fmt::Display for FeStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.status == FE_NONE {
write!(f, "OFF")?;
return Ok(());
}
if self.status & FE_HAS_LOCK != 0 {
write!(f, "LOCK {}", DeliverySystemDisplay(self.get_delivery_system()))?;
} else {
write!(f, "NO-LOCK 0x{:02X}", self.status)?;
}
if self.status & FE_HAS_SIGNAL == 0 {
return Ok(());
}
write!(
f,
" | Signal {:.02}dBm ({}%)",
self.get_signal_strength_decibel().unwrap_or(0.0),
self.get_signal_strength().unwrap_or(0)
)?;
if self.status & FE_HAS_CARRIER == 0 {
return Ok(());
}
write!(
f,
" | Quality {:.02}dB ({}%)",
self.get_snr_decibel().unwrap_or(0.0),
self.get_snr().unwrap_or(0)
)?;
if self.status & FE_HAS_LOCK == 0 {
return Ok(());
}
write!(f, " | BER:")?;
if let Some(ber) = self.get_ber() {
write!(f, "{}", ber)?;
} else {
write!(f, "-")?;
}
write!(f, " | UNC:")?;
if let Some(unc) = self.get_unc() {
write!(f, "{}", unc)?;
} else {
write!(f, "-")?;
}
Ok(())
}
}
impl FeStatus {
#[inline]
pub fn get_delivery_system(&self) -> u32 { unsafe { self.props[IDX_DELIVERY_SYSTEM].u.data } }
#[inline]
pub fn get_modulation(&self) -> u32 { unsafe { self.props[IDX_MODULATION].u.data } }
pub fn get_signal_strength_decibel(&self) -> Option<f64> {
let stat = unsafe { &self.props[IDX_SIGNAL_STRENGTH].u.st.stat[0] };
if stat.scale == FE_SCALE_DECIBEL {
Some((stat.value as f64) / 1000.0)
} else {
None
}
}
pub fn get_signal_strength(&self) -> Option<u32> {
let stat = unsafe { &self.props[IDX_SIGNAL_STRENGTH].u.st.stat[1] };
if stat.scale == FE_SCALE_RELATIVE {
Some(((stat.value & 0xFFFF) * 100 / 65535) as u32)
} else {
None
}
}
pub fn get_snr_decibel(&self) -> Option<f64> {
let stat = unsafe { &self.props[IDX_SNR].u.st.stat[0] };
if stat.scale == FE_SCALE_DECIBEL {
Some((stat.value as f64) / 1000.0)
} else {
None
}
}
pub fn get_snr(&self) -> Option<u32> {
let stat = unsafe { &self.props[IDX_SNR].u.st.stat[1] };
if stat.scale == FE_SCALE_RELATIVE {
Some(((stat.value & 0xFFFF) * 100 / 65535) as u32)
} else {
None
}
}
pub fn get_ber(&self) -> Option<u32> {
let stat = unsafe { &self.props[IDX_BER].u.st.stat[0] };
if stat.scale == FE_SCALE_COUNTER {
Some((stat.value & 0xFFFF_FFFF) as u32)
} else {
None
}
}
pub fn get_unc(&self) -> Option<u32> {
let stat = unsafe { &self.props[IDX_UNC].u.st.stat[0] };
if stat.scale == FE_SCALE_COUNTER {
Some((stat.value & 0xFFFF_FFFF) as u32)
} else {
None
}
}
fn normalize_signal_strength(&mut self) -> Result<()> {
let stats = unsafe { &mut self.props[IDX_SIGNAL_STRENGTH].u.st };
for i in usize::from(stats.len) .. 2 {
stats.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
stats.stat[i].value = 0;
}
stats.len = 2;
if stats.stat[0].scale == FE_SCALE_RELATIVE {
stats.stat.swap(0, 1);
return Ok(())
}
if stats.stat[1].scale == FE_SCALE_RELATIVE || (self.status & FE_HAS_SIGNAL) == 0 {
return Ok(())
}
if stats.stat[0].scale == FE_SCALE_DECIBEL {
let lo: i64 = -85000;
let hi: i64 = -6000;
stats.stat[1].scale = FE_SCALE_RELATIVE;
stats.stat[1].value = {
if stats.stat[0].value > hi {
65545
} else if stats.stat[0].value < lo {
0
} else {
65545 * (lo - stats.stat[0].value) / (lo - hi)
}
};
}
Ok(())
}
fn normalize_snr(&mut self) -> Result<()> {
let delivery_system = self.get_delivery_system();
let modulation = self.get_modulation();
let stats = unsafe { &mut self.props[IDX_SNR].u.st };
for i in usize::from(stats.len) .. 2 {
stats.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
stats.stat[i].value = 0;
}
stats.len = 2;
if stats.stat[0].scale == FE_SCALE_RELATIVE {
stats.stat.swap(0, 1);
return Ok(())
}
if stats.stat[1].scale == FE_SCALE_RELATIVE || (self.status & FE_HAS_CARRIER) == 0 {
return Ok(())
}
if stats.stat[0].scale == FE_SCALE_DECIBEL {
let hi = match delivery_system {
SYS_DVBS |
SYS_DVBS2 => 15000,
SYS_DVBC_ANNEX_A |
SYS_DVBC_ANNEX_B |
SYS_DVBC_ANNEX_C |
SYS_DVBC2 => 28000,
SYS_DVBT |
SYS_DVBT2 => 19000,
SYS_ATSC => {
match modulation {
VSB_8 | VSB_16 => 19000,
_ => 28000,
}
}
_ => return Ok(()),
};
stats.stat[1].scale = FE_SCALE_RELATIVE;
stats.stat[1].value = {
if stats.stat[0].value >= hi {
65535
} else if stats.stat[0].value <= 0 {
0
} else {
65535 * stats.stat[0].value / hi
}
};
}
Ok(())
}
fn normalize_ber(&mut self, fe: &FeDevice) -> Result<()> {
let stats = unsafe { &mut self.props[IDX_BER].u.st };
if stats.len == 0 {
stats.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
stats.stat[0].value = 0;
stats.len = 1;
}
if stats.stat[0].scale == FE_SCALE_COUNTER || (self.status & FE_HAS_LOCK) == 0 {
return Ok(())
}
if let Ok(value) = fe.read_ber() {
stats.stat[0].scale = FE_SCALE_COUNTER;
stats.stat[0].value = i64::from(value);
}
Ok(())
}
fn normalize_unc(&mut self, fe: &FeDevice) -> Result<()> {
let stats = unsafe { &mut self.props[IDX_UNC].u.st };
if stats.len == 0 {
stats.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
stats.stat[0].value = 0;
stats.len = 1;
}
if stats.stat[0].scale == FE_SCALE_COUNTER || (self.status & FE_HAS_LOCK) == 0 {
return Ok(())
}
if let Ok(value) = fe.read_unc() {
stats.stat[0].scale = FE_SCALE_COUNTER;
stats.stat[0].value = i64::from(value);
}
Ok(())
}
fn normalize_props(&mut self, fe: &FeDevice) -> Result<()> {
self.normalize_signal_strength()?;
self.normalize_snr()?;
self.normalize_ber(fe)?;
self.normalize_unc(fe)?;
Ok(())
}
pub fn read(&mut self, fe: &FeDevice) -> Result<()> {
self.status = fe.read_status()?;
if self.status == FE_NONE {
return Ok(());
}
fe.get_properties(&mut self.props)?;
self.normalize_props(fe)
}
}