1use crate::get_dtv_properties;
2
3use {
4 super::{sys::*, FeDevice},
5 anyhow::{Result},
6 std::fmt,
7};
8
9#[derive(Debug)]
11pub struct FeStatus {
12 status: fe_status,
14
15 delivery_system: Option<fe_delivery_system>,
16 modulation: Option<fe_modulation>,
17 signal_strength_decibel: Option<f64>,
18 signal_strength_percentage: Option<u8>,
19 snr_decibel: Option<f64>,
20 snr_percentage: Option<u8>,
21 ber: Option<u64>,
23 unc: Option<u64>,
25}
26
27impl Default for FeStatus {
28 fn default() -> FeStatus {
29 FeStatus {
30 status: fe_status::FE_NONE,
31 delivery_system: None,
32 modulation: None,
33 signal_strength_decibel: None,
34 signal_strength_percentage: None,
35 snr_decibel: None,
36 snr_percentage: None,
37 ber: None,
38 unc: None,
39 }
40 }
41}
42
43impl fmt::Display for FeStatus {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 if self.status == fe_status::FE_NONE {
75 write!(f, "OFF")?;
76 return Ok(());
77 }
78
79 if self.status.contains(fe_status::FE_HAS_LOCK) {
80 write!(
81 f,
82 "LOCK {}",
83 self.get_delivery_system()
84 .as_ref()
85 .unwrap_or(&fe_delivery_system::SYS_UNDEFINED)
86 )?;
87 } else {
88 write!(f, "NO-LOCK 0x{:02X}", self.status)?;
89 }
90
91 if !self.status.contains(fe_status::FE_HAS_SIGNAL) {
92 return Ok(());
93 }
94
95 write!(
96 f,
97 " | Signal {:.02}dBm ({}%)",
98 self.get_signal_strength_decibel().unwrap_or(0.0),
99 self.get_signal_strength().unwrap_or(0)
100 )?;
101
102 if !self.status.contains(fe_status::FE_HAS_CARRIER) {
103 return Ok(());
104 }
105
106 write!(
107 f,
108 " | Quality {:.02}dB ({}%)",
109 self.get_snr_decibel().unwrap_or(0.0),
110 self.get_snr().unwrap_or(0)
111 )?;
112
113 if !self.status.contains(fe_status::FE_HAS_LOCK) {
114 return Ok(());
115 }
116
117 write!(f, " | BER:")?;
118 if let Some(ber) = self.get_ber() {
119 write!(f, "{}", ber)?;
120 } else {
121 write!(f, "-")?;
122 }
123
124 write!(f, " | UNC:")?;
125 if let Some(unc) = self.get_unc() {
126 write!(f, "{}", unc)?;
127 } else {
128 write!(f, "-")?;
129 }
130
131 Ok(())
132 }
133}
134
135impl FeStatus {
136 #[inline]
138 pub fn get_delivery_system(&self) -> &Option<fe_delivery_system> {
139 &self.delivery_system
140 }
141
142 #[inline]
144 pub fn get_modulation(&self) -> &Option<fe_modulation> {
145 &self.modulation
146 }
147
148 pub fn get_signal_strength_decibel(&self) -> &Option<f64> {
150 &self.signal_strength_decibel
151 }
152
153 pub fn get_signal_strength(&self) -> &Option<u8> {
155 &self.signal_strength_percentage
156 }
157
158 pub fn get_snr_decibel(&self) -> &Option<f64> {
160 &self.snr_decibel
161 }
162
163 pub fn get_snr(&self) -> &Option<u8> {
165 &self.snr_percentage
166 }
167
168 pub fn get_ber(&self) -> &Option<u64> {
170 &self.ber
171 }
172
173 pub fn get_unc(&self) -> &Option<u64> {
175 &self.unc
176 }
177
178 fn normalize_signal_strength(&mut self, stats: DtvFrontendStats) {
179 self.signal_strength_decibel = stats.get_decibel_float();
180 self.signal_strength_percentage = match (stats.get_relative(), stats.get_decibel()) {
181 (Some(v), _) => Some(((v as u32) * 100 / 65535) as u8),
182 (None, Some(decibel)) if self.status.contains(fe_status::FE_HAS_SIGNAL) => {
183 let lo: i64 = -85000;
186 let hi: i64 = -6000;
187 Some({
188 if decibel > hi {
189 100
190 } else if decibel < lo {
191 0
192 } else {
193 (((lo - decibel) * 100) / (lo - hi)) as u8
194 }
195 })
196 }
197 _ => None,
198 };
199 }
200
201 fn normalize_snr(&mut self, stats: DtvFrontendStats) {
202 self.snr_decibel = stats.get_decibel_float();
203 self.snr_percentage = match (stats.get_relative(), stats.get_decibel()) {
204 (Some(v), _) => Some(((v as u32) * 100 / 65535) as u8),
205 (None, Some(decibel)) if self.status.contains(fe_status::FE_HAS_CARRIER) => {
206 match match self.delivery_system {
207 Some(SYS_DVBS) | Some(SYS_DVBS2) => Some(15000),
208
209 Some(SYS_DVBC_ANNEX_A) | Some(SYS_DVBC_ANNEX_B) | Some(SYS_DVBC_ANNEX_C) | Some(SYS_DVBC2) => {
210 Some(28000)
211 }
212
213 Some(SYS_DVBT) | Some(SYS_DVBT2) => Some(19000),
214
215 Some(SYS_ATSC) => Some(match self.modulation {
216 Some(VSB_8 | VSB_16) => 19000,
217 _ => 28000,
218 }),
219
220 _ => None,
221 } {
222 Some(_) if decibel <= 0 => Some(0),
223 Some(vhi) if decibel >= vhi => Some(100),
224 Some(vhi) => Some(((decibel * 100) / vhi) as u8),
225 _ => None,
226 }
227 }
228 _ => None,
229 };
230 }
231
232 pub fn read(&mut self, fe: &FeDevice) -> Result<()> {
234 self.status = fe.read_status()?;
235
236 if self.status == fe_status::FE_NONE {
237 return Ok(());
238 }
239
240 let (delivery_system, modulation, signal_strength, snr, ber, unc) = get_dtv_properties!(
241 fe,
242 DTV_DELIVERY_SYSTEM,
243 DTV_MODULATION,
244 DTV_STAT_SIGNAL_STRENGTH,
245 DTV_STAT_CNR,
246 DTV_STAT_PRE_ERROR_BIT_COUNT,
247 DTV_STAT_ERROR_BLOCK_COUNT
248 )?;
249 self.delivery_system = Some(delivery_system);
250 self.modulation = Some(modulation);
251 self.normalize_signal_strength(signal_strength);
252 self.normalize_snr(snr);
253 self.ber = match ber.get_counter() {
254 Some(v) => Some(v),
255 None if self.status.contains(fe_status::FE_HAS_LOCK) => fe.read_ber().ok(),
256 None => None,
257 };
258 self.unc = match unc.get_counter() {
259 Some(v) => Some(v),
260 None if self.status.contains(fe_status::FE_HAS_LOCK) => fe.read_unc().ok(),
261 None => None,
262 };
263
264 Ok(())
265 }
266}