mirror of
https://github.com/danog/libdvb.git
synced 2024-11-30 04:19:00 +01:00
verbosity for FeStatus::display(); FeDevice::new() rename to FeDevice::open(); AsRef for FeDevice::open()
This commit is contained in:
parent
dfe7be0616
commit
68e4f734bb
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libdvb"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["Cesbo Developers Team"]
|
||||
edition = "2018"
|
||||
|
||||
|
48
README.md
Normal file
48
README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# libdvb
|
||||
|
||||
libdvb is an interface library to DVB devices.
|
||||
|
||||
Supports three types of delivery systems:
|
||||
|
||||
- Satellite: DVB-S, DVB-S2
|
||||
- Terretrial: DVB-T, DVB-T2, ATSC, ISDB-T
|
||||
- Cable: DVB-C
|
||||
|
||||
Implements next standards:
|
||||
|
||||
- Linux DVB API version 5
|
||||
|
||||
TODO:
|
||||
|
||||
- Cenelec EN 50221 - Common Interface Specification for Conditional Access and
|
||||
other Digital Video BroadcastingDecoder Applications
|
||||
- DiSEqC 1.0
|
||||
- DiSEqC 1.1
|
||||
- EN 50494 - Unicable I
|
||||
- EN 50607 - Unicable II
|
||||
- ISO/IEC 13818-1 - MPEG-TS
|
||||
- ETSI TS 101 211 - Service Information implementation
|
||||
- ETSI TR 101 290 - Measurements for DVB systems
|
||||
|
||||
## FeDevice
|
||||
|
||||
Example DVB-S2 tune:
|
||||
|
||||
```
|
||||
let cmdseq = vec![
|
||||
DtvProperty::new(DTV_DELIVERY_SYSTEM, SYS_DVBS2),
|
||||
DtvProperty::new(DTV_FREQUENCY, (11044 - 9750) * 1000),
|
||||
DtvProperty::new(DTV_MODULATION, PSK_8),
|
||||
DtvProperty::new(DTV_VOLTAGE, SEC_VOLTAGE_13),
|
||||
DtvProperty::new(DTV_TONE, SEC_TONE_OFF),
|
||||
DtvProperty::new(DTV_INVERSION, INVERSION_AUTO),
|
||||
DtvProperty::new(DTV_SYMBOL_RATE, 27500 * 1000),
|
||||
DtvProperty::new(DTV_INNER_FEC, FEC_AUTO),
|
||||
DtvProperty::new(DTV_PILOT, PILOT_AUTO),
|
||||
DtvProperty::new(DTV_ROLLOFF, ROLLOFF_35),
|
||||
DtvProperty::new(DTV_TUNE, 0),
|
||||
];
|
||||
|
||||
let fe = FeDevice::open("/dev/dvb/adapter0/frontend0", true)?;
|
||||
fe.ioctl_set_property(&mut cmdseq)?;
|
||||
```
|
@ -50,6 +50,7 @@ pub use {
|
||||
};
|
||||
|
||||
|
||||
/// The error type for frontend operations
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FeError {
|
||||
#[error("frontend is not char device")]
|
||||
@ -73,6 +74,7 @@ pub enum FeError {
|
||||
}
|
||||
|
||||
|
||||
/// A reference to the frontend device and device information
|
||||
#[derive(Debug)]
|
||||
pub struct FeDevice {
|
||||
file: File,
|
||||
@ -125,12 +127,14 @@ impl AsRawFd for FeDevice {
|
||||
|
||||
|
||||
impl FeDevice {
|
||||
/// System call for frontend device
|
||||
#[inline]
|
||||
pub fn ioctl<T>(&self, request: IoctlInt, argp: T) -> Result<()> {
|
||||
ioctl(self.as_raw_fd(), request, argp).context("fe ioctl")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears frontend settings and event queue
|
||||
pub fn clear(&self) -> Result<()> {
|
||||
let mut cmdseq = [
|
||||
DtvProperty::new(DTV_VOLTAGE, SEC_VOLTAGE_OFF),
|
||||
@ -261,12 +265,14 @@ impl FeDevice {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(path: &Path, write: bool) -> Result<FeDevice> {
|
||||
/// Attempts to open frontend device and get frontend information
|
||||
/// If `write` is true opens frontend in Read-Write mode
|
||||
pub fn open<P: AsRef<Path>>(path: P, write: bool) -> Result<FeDevice> {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(write)
|
||||
.custom_flags(::libc::O_NONBLOCK)
|
||||
.open(path)
|
||||
.open(path.as_ref())
|
||||
.context("fe open")?;
|
||||
|
||||
let mut fe = FeDevice {
|
||||
@ -344,6 +350,7 @@ impl FeDevice {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets properties on frontend device
|
||||
pub fn ioctl_set_property(&self, cmdseq: &mut [DtvProperty]) -> Result<()> {
|
||||
self.check_cmdseq(cmdseq).context("fe property check")?;
|
||||
|
||||
@ -351,11 +358,15 @@ impl FeDevice {
|
||||
self.ioctl(FE_SET_PROPERTY, cmd.as_ptr())
|
||||
}
|
||||
|
||||
/// Gets properties from frontend device
|
||||
pub fn ioctl_get_property(&self, cmdseq: &mut [DtvProperty]) -> Result<()> {
|
||||
let mut cmd = DtvProperties::new(cmdseq);
|
||||
self.ioctl(FE_GET_PROPERTY, cmd.as_mut_ptr())
|
||||
}
|
||||
|
||||
/// Returns the current API version
|
||||
/// major - first byte
|
||||
/// minor - second byte
|
||||
#[inline]
|
||||
pub fn get_api_version(&self) -> u16 {
|
||||
self.api_version
|
||||
|
@ -10,9 +10,10 @@ use {
|
||||
};
|
||||
|
||||
|
||||
/// Frontend status
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub struct FeStatus {
|
||||
/// sys::frontend::fe_status
|
||||
/// `sys::frontend::fe_status`
|
||||
status: u32,
|
||||
|
||||
/// signal level in dBm
|
||||
@ -29,13 +30,75 @@ pub struct FeStatus {
|
||||
}
|
||||
|
||||
|
||||
/// Helper struct for displaying frontend status
|
||||
pub struct FeStatusDisplay<'a> {
|
||||
inner: &'a FeStatus,
|
||||
verbose: u32,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> fmt::Display for FeStatusDisplay<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl<'a> FeStatusDisplay<'a> {
|
||||
fn display_0(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Status:")?;
|
||||
|
||||
if self.inner.status == FE_NONE {
|
||||
write!(f, "OFF")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
const STATUS_MAP: &[char] = &['S', 'C', 'V', 'Y', 'L'];
|
||||
for (i, s) in STATUS_MAP.iter().enumerate() {
|
||||
let c = if self.inner.status & (1 << i) != 0 { *s } else { '_' };
|
||||
write!(f, "{}", c)?;
|
||||
}
|
||||
|
||||
if self.inner.status & FE_HAS_SIGNAL == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, " S:")?;
|
||||
if let Some(signal) = self.inner.signal {
|
||||
// TODO: config for lo/hi
|
||||
let lo: f64 = -85.0;
|
||||
let hi: f64 = -6.0;
|
||||
let relative = 100.0 - (signal - hi) * 100.0 / (lo - hi);
|
||||
write!(f, "{:.0}% ({:.02}dBm)", relative, signal)?;
|
||||
} else {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
|
||||
if self.inner.status & FE_HAS_CARRIER == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, " Q:")?;
|
||||
if let Some(snr) = self.inner.snr {
|
||||
let relative = 5 * snr as u32;
|
||||
write!(f, "{}% ({:.02}dB)", relative, snr)?;
|
||||
} else {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
|
||||
if self.inner.status & FE_HAS_LOCK == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, " BER: ")?;
|
||||
if let Some(ber) = self.inner.ber {
|
||||
write!(f, "{}", ber & 0xFFFF)?;
|
||||
} else {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
|
||||
write!(f, " UNC: ")?;
|
||||
if let Some(unc) = self.inner.unc {
|
||||
write!(f, "{}", unc & 0xFFFF)
|
||||
} else {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
|
||||
fn display_1(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Status:")?;
|
||||
|
||||
if self.inner.status == FE_NONE {
|
||||
@ -90,8 +153,6 @@ impl<'a> fmt::Display for FeStatusDisplay<'a> {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
|
||||
// Last line without new line
|
||||
|
||||
write!(f, "\nUNC: ")?;
|
||||
if let Some(unc) = self.inner.unc {
|
||||
write!(f, "{}", unc & 0xFFFF)
|
||||
@ -102,13 +163,29 @@ impl<'a> fmt::Display for FeStatusDisplay<'a> {
|
||||
}
|
||||
|
||||
|
||||
impl<'a> fmt::Display for FeStatusDisplay<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.verbose {
|
||||
1 => self.display_1(f),
|
||||
_ => self.display_0(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl FeStatus {
|
||||
pub fn display(&self) -> FeStatusDisplay {
|
||||
/// Returns an object that implements `Display` for different verbosity levels
|
||||
/// Verbosity levels:
|
||||
/// 0 - single line status
|
||||
/// 1 - full report
|
||||
pub fn display(&self, verbose: u32) -> FeStatusDisplay {
|
||||
FeStatusDisplay {
|
||||
inner: self,
|
||||
verbose,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads frontend status
|
||||
pub fn read(&mut self, fe: &FeDevice) -> Result<()> {
|
||||
self.status = FE_NONE;
|
||||
fe.ioctl(FE_READ_STATUS, &mut self.status as *mut _)?;
|
||||
|
Loading…
Reference in New Issue
Block a user