1use anyhow::Context;
2use std::fmt::Debug;
3use std::str::FromStr;
4use std::{fmt, mem};
5
6pub use {
7 fe_code_rate::*, fe_delivery_system::*, fe_guard_interval::*, fe_hierarchy::*,
8 fe_interleaving::*, fe_modulation::*, fe_pilot::*, fe_rolloff::*, fe_sec_mini_cmd::*,
9 fe_sec_tone_mode::*, fe_sec_voltage::*, fe_spectral_inversion::*, fe_transmit_mode::*,
10 fe_type::*, DtvProperty::*, DtvStat::*,
11};
12
13use bitflags::bitflags;
14use strum::{Display, EnumString, FromRepr};
15
16bitflags! {
17 #[repr(C)]
19 pub struct fe_caps : u32 {
20 const FE_IS_STUPID = 0x0;
22 const FE_CAN_INVERSION_AUTO = 0x1;
24 const FE_CAN_FEC_1_2 = 0x2;
26 const FE_CAN_FEC_2_3 = 0x4;
28 const FE_CAN_FEC_3_4 = 0x8;
30 const FE_CAN_FEC_4_5 = 0x10;
32 const FE_CAN_FEC_5_6 = 0x20;
34 const FE_CAN_FEC_6_7 = 0x40;
36 const FE_CAN_FEC_7_8 = 0x80;
38 const FE_CAN_FEC_8_9 = 0x100;
40 const FE_CAN_FEC_AUTO = 0x200;
42 const FE_CAN_QPSK = 0x400;
44 const FE_CAN_QAM_16 = 0x800;
46 const FE_CAN_QAM_32 = 0x1000;
48 const FE_CAN_QAM_64 = 0x2000;
50 const FE_CAN_QAM_128 = 0x4000;
52 const FE_CAN_QAM_256 = 0x8000;
54 const FE_CAN_QAM_AUTO = 0x10000;
56 const FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000;
58 const FE_CAN_BANDWIDTH_AUTO = 0x40000;
60 const FE_CAN_GUARD_INTERVAL_AUTO = 0x80000;
62 const FE_CAN_HIERARCHY_AUTO = 0x100000;
64 const FE_CAN_8VSB = 0x200000;
66 const FE_CAN_16VSB = 0x400000;
68 const FE_HAS_EXTENDED_CAPS = 0x800000;
70 const FE_CAN_MULTISTREAM = 0x4000000;
72 const FE_CAN_TURBO_FEC = 0x8000000;
74 const FE_CAN_2G_MODULATION = 0x10000000;
76 const FE_NEEDS_BENDING = 0x20000000;
78 const FE_CAN_RECOVER = 0x40000000;
80 const FE_CAN_MUTE_TS = 0x80000000;
82 }
83}
84
85#[repr(u32)]
87#[allow(non_camel_case_types)]
88#[derive(Debug, PartialEq, Eq, FromRepr)]
89pub enum fe_type {
90 FE_QPSK = 0,
91 FE_QAM = 1,
92 FE_OFDM = 2,
93 FE_ATSC = 3,
94}
95
96#[repr(C)]
100#[derive(Debug)]
101pub struct FeInfo {
102 pub name: [std::os::raw::c_char; 128],
104 pub fe_type: fe_type,
106 pub frequency_min: u32,
108 pub frequency_max: u32,
110 pub frequency_stepsize: u32,
112 pub frequency_tolerance: u32,
114 pub symbol_rate_min: u32,
116 pub symbol_rate_max: u32,
118 pub symbol_rate_tolerance: u32,
120 pub notifier_delay: u32,
122 pub caps: fe_caps,
124}
125
126impl Default for FeInfo {
127 #[inline]
128 fn default() -> Self {
129 unsafe { mem::zeroed::<Self>() }
130 }
131}
132
133impl FeInfo {
134 #[inline]
135 pub fn as_mut_ptr(&mut self) -> *mut FeInfo {
136 self as *mut _
137 }
138}
139
140#[repr(C)]
144#[derive(Debug)]
145pub struct DiseqcMasterCmd {
146 pub msg: [u8; 6],
150 pub len: u8,
152}
153
154impl Default for DiseqcMasterCmd {
155 #[inline]
156 fn default() -> Self {
157 unsafe { mem::zeroed::<Self>() }
158 }
159}
160
161#[repr(C)]
163#[derive(Debug)]
164pub struct DiseqcSlaveReply {
165 pub msg: [u8; 4],
169 pub len: u8,
172 pub timeout: u32,
175}
176
177impl Default for DiseqcSlaveReply {
178 #[inline]
179 fn default() -> Self {
180 unsafe { mem::zeroed::<Self>() }
181 }
182}
183
184#[repr(u32)]
186#[allow(non_camel_case_types)]
187#[derive(EnumString, Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
188pub enum fe_sec_voltage {
189 SEC_VOLTAGE_13 = 0,
191 SEC_VOLTAGE_18 = 1,
193 SEC_VOLTAGE_OFF = 2,
195}
196
197#[repr(u32)]
198#[allow(non_camel_case_types)]
199#[derive(EnumString, Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
200pub enum fe_sec_tone_mode {
201 SEC_TONE_ON = 0,
203 SEC_TONE_OFF = 1,
205}
206
207#[repr(u32)]
209#[allow(non_camel_case_types)]
210#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
211pub enum fe_sec_mini_cmd {
212 SEC_MINI_A = 0,
214 SEC_MINI_B = 1,
216}
217
218bitflags! {
219 #[repr(C)]
221 pub struct fe_status : u32 {
222 const FE_NONE = 0x00;
224 const FE_HAS_SIGNAL = 0x01;
226 const FE_HAS_CARRIER = 0x02;
228 const FE_HAS_VITERBI = 0x04;
230 const FE_HAS_SYNC = 0x08;
232 const FE_HAS_LOCK = 0x10;
234 const FE_TIMEDOUT = 0x20;
236 const FE_REINIT = 0x40;
239 }
240}
241
242#[repr(u32)]
244#[allow(non_camel_case_types)]
245#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Clone, Copy)]
246pub enum fe_spectral_inversion {
247 #[strum(serialize = "OFF")]
248 INVERSION_OFF = 0,
249 #[strum(serialize = "ON")]
250 INVERSION_ON = 1,
251 #[strum(serialize = "AUTO")]
252 INVERSION_AUTO = 2,
253}
254
255#[repr(u32)]
256#[allow(non_camel_case_types)]
257#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Clone, Copy)]
258#[strum(ascii_case_insensitive)]
259pub enum fe_code_rate {
260 #[strum(serialize = "NONE")]
261 FEC_NONE = 0,
262 #[strum(serialize = "1/2")]
263 FEC_1_2 = 1,
264 #[strum(serialize = "2/3")]
265 FEC_2_3 = 2,
266 #[strum(serialize = "3/4")]
267 FEC_3_4 = 3,
268 #[strum(serialize = "4/5")]
269 FEC_4_5 = 4,
270 #[strum(serialize = "5/6")]
271 FEC_5_6 = 5,
272 #[strum(serialize = "6/7")]
273 FEC_6_7 = 6,
274 #[strum(serialize = "7/8")]
275 FEC_7_8 = 7,
276 #[strum(serialize = "8/9")]
277 FEC_8_9 = 8,
278 #[strum(serialize = "AUTO")]
279 FEC_AUTO = 9,
280 #[strum(serialize = "3/5")]
281 FEC_3_5 = 10,
282 #[strum(serialize = "9/10")]
283 FEC_9_10 = 11,
284 #[strum(serialize = "2/5")]
285 FEC_2_5 = 12,
286 #[strum(serialize = "1/4")]
287 FEC_1_4 = 13,
288 #[strum(serialize = "1/3")]
289 FEC_1_3 = 14,
290}
291
292#[repr(u32)]
294#[allow(non_camel_case_types)]
295#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
296pub enum fe_modulation {
297 QPSK = 0,
298 #[strum(serialize = "QAM/16")]
299 QAM_16 = 1,
300 #[strum(serialize = "QAM/32")]
301 QAM_32 = 2,
302 #[strum(serialize = "QAM/64")]
303 QAM_64 = 3,
304 #[strum(serialize = "QAM/128")]
305 QAM_128 = 4,
306 #[strum(serialize = "QAM/256")]
307 QAM_256 = 5,
308 #[strum(serialize = "QAM/AUTO")]
309 QAM_AUTO = 6,
310 #[strum(serialize = "VSB/8")]
311 VSB_8 = 7,
312 #[strum(serialize = "VSB/16")]
313 VSB_16 = 8,
314 #[strum(serialize = "PSK/8")]
315 PSK_8 = 9,
316 #[strum(serialize = "APSK/16")]
317 APSK_16 = 10,
318 #[strum(serialize = "APSK/32")]
319 APSK_32 = 11,
320 #[strum(serialize = "DQPSK")]
321 DQPSK = 12,
322 #[strum(serialize = "QAM/4/NR")]
323 QAM_4_NR = 13,
324 #[strum(serialize = "APSK/64")]
325 APSK_64 = 14,
326 #[strum(serialize = "APSK/128")]
327 APSK_128 = 15,
328 #[strum(serialize = "APSK/256")]
329 APSK_256 = 16,
330}
331
332#[repr(u32)]
333#[allow(non_camel_case_types)]
334#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
335pub enum fe_transmit_mode {
336 #[strum(serialize = "2K")]
337 TRANSMISSION_MODE_2K = 0,
338 #[strum(serialize = "8K")]
339 TRANSMISSION_MODE_8K = 1,
340 #[strum(serialize = "AUTO")]
341 TRANSMISSION_MODE_AUTO = 2,
342 #[strum(serialize = "4K")]
343 TRANSMISSION_MODE_4K = 3,
344 #[strum(serialize = "1K")]
345 TRANSMISSION_MODE_1K = 4,
346 #[strum(serialize = "16K")]
347 TRANSMISSION_MODE_16K = 5,
348 #[strum(serialize = "32K")]
349 TRANSMISSION_MODE_32K = 6,
350 #[strum(serialize = "C1")]
351 TRANSMISSION_MODE_C1 = 7,
352 #[strum(serialize = "C3780")]
353 TRANSMISSION_MODE_C3780 = 8,
354}
355
356#[repr(u32)]
357#[allow(non_camel_case_types)]
358#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
359pub enum fe_guard_interval {
360 #[strum(serialize = "1/32")]
361 GUARD_INTERVAL_1_32 = 0,
362 #[strum(serialize = "1/16")]
363 GUARD_INTERVAL_1_16 = 1,
364 #[strum(serialize = "1/8")]
365 GUARD_INTERVAL_1_8 = 2,
366 #[strum(serialize = "1/4")]
367 GUARD_INTERVAL_1_4 = 3,
368 #[strum(serialize = "AUTO")]
369 GUARD_INTERVAL_AUTO = 4,
370 #[strum(serialize = "1/128")]
371 GUARD_INTERVAL_1_128 = 5,
372 #[strum(serialize = "19/128")]
373 GUARD_INTERVAL_19_128 = 6,
374 #[strum(serialize = "19/256")]
375 GUARD_INTERVAL_19_256 = 7,
376 #[strum(serialize = "PN420")]
377 GUARD_INTERVAL_PN420 = 8,
378 #[strum(serialize = "PN595")]
379 GUARD_INTERVAL_PN595 = 9,
380 #[strum(serialize = "PN945")]
381 GUARD_INTERVAL_PN945 = 10,
382}
383
384#[repr(u32)]
385#[allow(non_camel_case_types)]
386#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
387pub enum fe_hierarchy {
388 #[strum(serialize = "NONE")]
389 HIERARCHY_NONE = 0,
390 #[strum(serialize = "1")]
391 HIERARCHY_1 = 1,
392 #[strum(serialize = "2")]
393 HIERARCHY_2 = 2,
394 #[strum(serialize = "4")]
395 HIERARCHY_4 = 3,
396 #[strum(serialize = "AUTO")]
397 HIERARCHY_AUTO = 4,
398}
399
400#[repr(u32)]
401#[allow(non_camel_case_types)]
402#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
403pub enum fe_interleaving {
404 #[strum(serialize = "NONE")]
405 INTERLEAVING_NONE = 0,
406 #[strum(serialize = "AUTO")]
407 INTERLEAVING_AUTO = 1,
408 #[strum(serialize = "240")]
409 INTERLEAVING_240 = 2,
410 #[strum(serialize = "720")]
411 INTERLEAVING_720 = 3,
412}
413
414#[repr(u32)]
415#[allow(non_camel_case_types)]
416#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
417pub enum fe_pilot {
418 PILOT_ON = 0,
419 PILOT_OFF = 1,
420 PILOT_AUTO = 2,
421}
422
423#[repr(u32)]
424#[allow(non_camel_case_types)]
425#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
426pub enum fe_rolloff {
427 ROLLOFF_35 = 0,
428 ROLLOFF_20 = 1,
429 ROLLOFF_25 = 2,
430 ROLLOFF_AUTO = 3,
431 ROLLOFF_15 = 4,
432 ROLLOFF_10 = 5,
433 ROLLOFF_5 = 6,
434}
435
436#[derive(EnumString, Display, FromRepr, Debug, Copy, Clone)]
437#[repr(u32)]
438#[allow(non_camel_case_types)]
439#[strum(ascii_case_insensitive)]
440pub enum fe_delivery_system {
441 #[strum(to_string = "none")]
442 SYS_UNDEFINED = 0,
443 #[strum(to_string = "dbvc/annex_a")]
444 SYS_DVBC_ANNEX_A = 1,
445 #[strum(to_string = "dvbc/annex_b")]
446 SYS_DVBC_ANNEX_B = 2,
447 #[strum(to_string = "dvbt")]
448 SYS_DVBT = 3,
449 #[strum(to_string = "dss")]
450 SYS_DSS = 4,
451 #[strum(to_string = "dvbs")]
452 SYS_DVBS = 5,
453 #[strum(to_string = "dvbs2")]
454 SYS_DVBS2 = 6,
455 #[strum(to_string = "dvbh")]
456 SYS_DVBH = 7,
457 #[strum(to_string = "isdbt")]
458 SYS_ISDBT = 8,
459 #[strum(to_string = "isdbs")]
460 SYS_ISDBS = 9,
461 #[strum(to_string = "isdbc")]
462 SYS_ISDBC = 10,
463 #[strum(to_string = "atsc")]
464 SYS_ATSC = 11,
465 #[strum(to_string = "atsc-m/h")]
466 SYS_ATSCMH = 12,
467 #[strum(to_string = "dtmb")]
468 SYS_DTMB = 13,
469 #[strum(to_string = "cmmb")]
470 SYS_CMMB = 14,
471 #[strum(to_string = "dab")]
472 SYS_DAB = 15,
473 #[strum(to_string = "dvbt2", serialize = "dvbt22")]
474 SYS_DVBT2 = 16,
475 #[strum(to_string = "dvbs/turbo")]
476 SYS_TURBO = 17,
477 #[strum(to_string = "dvbc/annex_c")]
478 SYS_DVBC_ANNEX_C = 18,
479 #[strum(to_string = "dvbc2")]
480 SYS_DVBC2 = 19,
481}
482
483#[repr(u32)]
484#[allow(non_camel_case_types)]
485#[derive(EnumString, Debug, PartialEq, Eq, FromRepr, Copy, Clone)]
486pub enum fe_lna {
487 LNA_OFF = 0,
488 LNA_ON = 1,
489 LNA_AUTO = 0xFFFFFFFF,
490}
491
492pub trait WrappedSlice<T> {
494 fn slice(&self) -> &[T];
495}
496
497pub trait WrappedResult<T> {
498 fn get(&self) -> anyhow::Result<T>;
499}
500
501pub trait DtvStatType {
502 fn get_decibel(&self) -> Option<i64>;
503 fn get_relative(&self) -> Option<u16>;
504 fn get_counter(&self) -> Option<u64>;
505 fn get_decibel_float(&self) -> Option<f64> {
506 Some((self.get_decibel()? as f64) / 1000.0)
507 }
508 fn get_relative_percentage(&self) -> Option<u8> {
509 Some((((self.get_relative()? as u32) * 100) / 65535) as u8)
510 }
511}
512
513#[repr(C, packed)]
514#[derive(Debug, Copy, Clone)]
515pub struct NoScale {
516 __reserved: [u8; 8],
517}
518
519#[repr(C, packed)]
520#[derive(Debug, Copy, Clone)]
521pub struct ScaleDecibel {
522 pub scale: i64,
523}
524
525#[repr(C, packed)]
526#[derive(Debug, Copy, Clone)]
527pub struct ScaleRelative {
528 pub scale: u16,
529 __reserved: [u8; 6],
530}
531
532#[repr(C, packed)]
533#[derive(Debug, Copy, Clone)]
534pub struct ScaleCounter {
535 pub scale: u64,
536}
537
538#[repr(u8)]
540#[allow(non_camel_case_types)]
541#[derive(Debug, Copy, Clone)]
542pub enum DtvStat {
543 FE_SCALE_NOT_AVAILABLE(NoScale),
546 FE_SCALE_DECIBEL(ScaleDecibel),
548 FE_SCALE_RELATIVE(ScaleRelative),
551 FE_SCALE_COUNTER(ScaleCounter),
554}
555
556impl DtvStatType for DtvStat {
557 fn get_decibel(&self) -> Option<i64> {
558 match self {
559 FE_SCALE_DECIBEL(s) => Some(s.scale),
560 _ => None,
561 }
562 }
563 fn get_relative(&self) -> Option<u16> {
564 match self {
565 FE_SCALE_RELATIVE(s) => Some(s.scale),
566 _ => None,
567 }
568 }
569 fn get_counter(&self) -> Option<u64> {
570 match self {
571 FE_SCALE_COUNTER(s) => Some(s.scale),
572 _ => None,
573 }
574 }
575}
576
577pub const MAX_DTV_STATS: usize = 4;
578
579#[repr(C, packed)]
581#[derive(Copy, Clone)]
582pub struct DtvFrontendStats {
583 len: u8,
584 stat: [DtvStat; MAX_DTV_STATS],
585}
586
587impl WrappedSlice<DtvStat> for DtvFrontendStats {
588 fn slice(&self) -> &[DtvStat] {
589 let len = ::std::cmp::min(self.len as usize, self.stat.len());
590 &self.stat[0..len]
591 }
592}
593
594impl Debug for DtvFrontendStats {
595 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
596 f.debug_list().entries(self.slice().into_iter()).finish()
597 }
598}
599
600impl DtvStatType for DtvFrontendStats {
601 fn get_decibel(&self) -> Option<i64> {
602 for stat in self.slice() {
603 if let Some(v) = stat.get_decibel() {
604 return Some(v);
605 }
606 }
607 None
608 }
609 fn get_relative(&self) -> Option<u16> {
610 for stat in self.slice() {
611 if let Some(v) = stat.get_relative() {
612 return Some(v);
613 }
614 }
615 None
616 }
617 fn get_counter(&self) -> Option<u64> {
618 for stat in self.slice() {
619 if let Some(v) = stat.get_counter() {
620 return Some(v);
621 }
622 }
623 None
624 }
625}
626
627#[repr(C, packed)]
628#[derive(Copy, Clone)]
629pub struct DtvPropertyBuffer {
630 data: [u8; 32],
631 len: u32,
632}
633
634impl WrappedSlice<u8> for DtvPropertyBuffer {
635 fn slice(&self) -> &[u8] {
636 let len = ::std::cmp::min(self.len as usize, self.data.len());
637 &self.data[0..len]
638 }
639}
640
641impl Debug for DtvPropertyBuffer {
642 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
643 f.debug_list().entries(self.slice().into_iter()).finish()
644 }
645}
646
647const DATA_SIZE: usize = 56;
648
649#[repr(C, packed)]
650pub struct DtvPropertyRequest<T, const N: usize> {
651 __reserved: [u32; 3],
652 data: T,
653 padding: [u8; N],
654 result: i32, }
656
657impl<T, const N: usize> DtvPropertyRequest<T, N> {
658 #[inline]
659 pub fn new(data: T) -> Self {
660 Self {
661 __reserved: [0; 3],
662 data,
663 padding: [0; N],
664 result: 0,
665 }
666 }
667}
668
669impl<T, const N: usize> Default for DtvPropertyRequest<T, N> {
670 #[inline]
671 fn default() -> Self {
672 unsafe { mem::zeroed::<Self>() }
673 }
674}
675
676pub type DtvPropertyRequestVoid = DtvPropertyRequest<(), DATA_SIZE>;
677
678impl WrappedResult<()> for DtvPropertyRequestVoid {
679 #[inline]
680 fn get(&self) -> anyhow::Result<()> {
681 Ok(())
682 }
683}
684
685impl Debug for DtvPropertyRequestVoid {
686 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
687 f.write_str("()")
688 }
689}
690
691pub type DtvPropertyRequestInt<T> = DtvPropertyRequest<T, { DATA_SIZE - 4 }>;
692
693impl<T: Copy + Debug> WrappedResult<T> for DtvPropertyRequestInt<T> {
694 #[inline]
695 fn get(&self) -> anyhow::Result<T> {
696 Ok(self.data)
697 }
698}
699
700impl<T: Copy + Debug> Debug for DtvPropertyRequestInt<T> {
701 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
702 self.get().unwrap().fmt(f)
703 }
704}
705
706pub type DtvPropertyRequestFrontendStats = DtvPropertyRequest<DtvFrontendStats, { DATA_SIZE - 37 }>;
707
708impl WrappedResult<DtvFrontendStats> for DtvPropertyRequestFrontendStats {
709 #[inline]
710 fn get(&self) -> anyhow::Result<DtvFrontendStats> {
711 Ok(self.data)
712 }
713}
714
715impl Debug for DtvPropertyRequestFrontendStats {
716 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
717 self.data.fmt(f)
718 }
719}
720
721pub type DtvPropertyRequestDeliverySystems =
722 DtvPropertyRequest<DtvPropertyBuffer, { DATA_SIZE - 4 - 32 }>;
723
724impl WrappedResult<Vec<fe_delivery_system>> for DtvPropertyRequestDeliverySystems {
725 #[inline]
726 fn get(&self) -> Result<Vec<fe_delivery_system>, anyhow::Error> {
727 self.data
728 .slice()
729 .into_iter()
730 .map(|&x| fe_delivery_system::from_repr(x as u32).context("Invalid delivery system"))
731 .try_collect()
732 }
733}
734
735impl Debug for DtvPropertyRequestDeliverySystems {
736 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
737 f.debug_list().entries(self.get().unwrap().iter()).finish()
738 }
739}
740
741#[repr(C, packed)]
742pub struct DtvPropertyNotImplementedLinux {
743 __reserved: [u8; DATA_SIZE],
744}
745
746impl Debug for DtvPropertyNotImplementedLinux {
747 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
748 f.write_str("Not implemented")
749 }
750}
751
752#[deprecated(
753 note = "Not implemented, please fork libdvb and provide a correct implementation for this property."
754)]
755type DtvPropertyNotImplemented = DtvPropertyNotImplementedLinux;
756#[deprecated]
757type DtvPropertyDeprecated = DtvPropertyNotImplementedLinux;
758
759#[repr(u32, C)]
761#[allow(non_camel_case_types)]
762#[allow(deprecated)]
763#[derive(Debug)]
764pub enum DtvProperty {
765 DTV_UNDEFINED(DtvPropertyNotImplementedLinux),
766 DTV_TUNE(DtvPropertyRequestVoid),
767 DTV_CLEAR(DtvPropertyRequestVoid),
768 DTV_FREQUENCY(DtvPropertyRequestInt<u32>),
769 DTV_MODULATION(DtvPropertyRequestInt<fe_modulation>),
770 DTV_BANDWIDTH_HZ(DtvPropertyRequestInt<u32>),
771 DTV_INVERSION(DtvPropertyRequestInt<fe_spectral_inversion>),
772 DTV_DISEQC_MASTER(DtvPropertyNotImplementedLinux),
773 DTV_SYMBOL_RATE(DtvPropertyRequestInt<u32>),
774 DTV_INNER_FEC(DtvPropertyRequestInt<fe_code_rate>),
775 DTV_VOLTAGE(DtvPropertyRequestInt<fe_sec_voltage>),
776 DTV_TONE(DtvPropertyRequestInt<fe_sec_tone_mode>),
777 DTV_PILOT(DtvPropertyRequestInt<fe_pilot>),
778 DTV_ROLLOFF(DtvPropertyRequestInt<fe_rolloff>),
779 DTV_DISEQC_SLAVE_REPLY(DtvPropertyNotImplementedLinux),
780
781 DTV_FE_CAPABILITY_COUNT(DtvPropertyNotImplementedLinux),
783 DTV_FE_CAPABILITY(DtvPropertyNotImplementedLinux),
784 DTV_DELIVERY_SYSTEM(DtvPropertyRequestInt<fe_delivery_system>),
785
786 DTV_ISDBT_PARTIAL_RECEPTION(DtvPropertyRequestInt<i32>),
789 DTV_ISDBT_SOUND_BROADCASTING(DtvPropertyRequestInt<i32>),
790
791 DTV_ISDBT_SB_SUBCHANNEL_ID(DtvPropertyRequestInt<i32>),
792 DTV_ISDBT_SB_SEGMENT_IDX(DtvPropertyRequestInt<i32>),
793 DTV_ISDBT_SB_SEGMENT_COUNT(DtvPropertyRequestInt<u32>),
794
795 DTV_ISDBT_LAYERA_FEC(DtvPropertyRequestInt<fe_code_rate>),
796 DTV_ISDBT_LAYERA_MODULATION(DtvPropertyRequestInt<fe_modulation>),
797 DTV_ISDBT_LAYERA_SEGMENT_COUNT(DtvPropertyRequestInt<i32>),
798 DTV_ISDBT_LAYERA_TIME_INTERLEAVING(DtvPropertyRequestInt<i32>),
799
800 DTV_ISDBT_LAYERB_FEC(DtvPropertyRequestInt<fe_code_rate>),
801 DTV_ISDBT_LAYERB_MODULATION(DtvPropertyRequestInt<fe_modulation>),
802 DTV_ISDBT_LAYERB_SEGMENT_COUNT(DtvPropertyRequestInt<i32>),
803 DTV_ISDBT_LAYERB_TIME_INTERLEAVING(DtvPropertyRequestInt<i32>),
804
805 DTV_ISDBT_LAYERC_FEC(DtvPropertyRequestInt<fe_code_rate>),
806 DTV_ISDBT_LAYERC_MODULATION(DtvPropertyRequestInt<fe_modulation>),
807 DTV_ISDBT_LAYERC_SEGMENT_COUNT(DtvPropertyRequestInt<i32>),
808 DTV_ISDBT_LAYERC_TIME_INTERLEAVING(DtvPropertyRequestInt<i32>),
809
810 DTV_API_VERSION(DtvPropertyRequestInt<u32>),
811
812 DTV_CODE_RATE_HP(DtvPropertyRequestInt<fe_code_rate>),
814 DTV_CODE_RATE_LP(DtvPropertyRequestInt<fe_code_rate>),
815 DTV_GUARD_INTERVAL(DtvPropertyRequestInt<fe_guard_interval>),
816 DTV_TRANSMISSION_MODE(DtvPropertyRequestInt<fe_transmit_mode>),
817 DTV_HIERARCHY(DtvPropertyRequestInt<fe_hierarchy>),
818
819 DTV_ISDBT_LAYER_ENABLED(DtvPropertyRequestInt<u32>),
820
821 DTV_STREAM_ID(DtvPropertyRequestInt<u32>),
822 #[deprecated(note = "Obsolete, replaced with DTV_STREAM_ID.")]
823 DTV_DVBT2_PLP_ID_LEGACY(DtvPropertyDeprecated),
824
825 DTV_ENUM_DELSYS(DtvPropertyRequestDeliverySystems),
826
827 DTV_ATSCMH_FIC_VER(DtvPropertyRequestInt<u32>),
829 DTV_ATSCMH_PARADE_ID(DtvPropertyRequestInt<u32>),
830 DTV_ATSCMH_NOG(DtvPropertyRequestInt<u32>),
831 DTV_ATSCMH_TNOG(DtvPropertyRequestInt<u32>),
832 DTV_ATSCMH_SGN(DtvPropertyRequestInt<u32>),
833 DTV_ATSCMH_PRC(DtvPropertyRequestInt<u32>),
834 DTV_ATSCMH_RS_FRAME_MODE(DtvPropertyNotImplemented),
835 DTV_ATSCMH_RS_FRAME_ENSEMBLE(DtvPropertyNotImplemented),
836 DTV_ATSCMH_RS_CODE_MODE_PRI(DtvPropertyNotImplemented),
837 DTV_ATSCMH_RS_CODE_MODE_SEC(DtvPropertyNotImplemented),
838 DTV_ATSCMH_SCCC_BLOCK_MODE(DtvPropertyNotImplemented),
839 DTV_ATSCMH_SCCC_CODE_MODE_A(DtvPropertyNotImplemented),
840 DTV_ATSCMH_SCCC_CODE_MODE_B(DtvPropertyNotImplemented),
841 DTV_ATSCMH_SCCC_CODE_MODE_C(DtvPropertyNotImplemented),
842 DTV_ATSCMH_SCCC_CODE_MODE_D(DtvPropertyNotImplemented),
843
844 DTV_INTERLEAVING(DtvPropertyRequestInt<fe_interleaving>),
845 DTV_LNA(DtvPropertyRequestInt<fe_lna>),
846
847 DTV_STAT_SIGNAL_STRENGTH(DtvPropertyRequestFrontendStats),
849 DTV_STAT_CNR(DtvPropertyRequestFrontendStats),
850 DTV_STAT_PRE_ERROR_BIT_COUNT(DtvPropertyRequestFrontendStats),
851 DTV_STAT_PRE_TOTAL_BIT_COUNT(DtvPropertyRequestFrontendStats),
852 DTV_STAT_POST_ERROR_BIT_COUNT(DtvPropertyRequestFrontendStats),
853 DTV_STAT_POST_TOTAL_BIT_COUNT(DtvPropertyRequestFrontendStats),
854 DTV_STAT_ERROR_BLOCK_COUNT(DtvPropertyRequestFrontendStats),
855 DTV_STAT_TOTAL_BLOCK_COUNT(DtvPropertyRequestFrontendStats),
856
857 DTV_SCRAMBLING_SEQUENCE_INDEX(DtvPropertyRequestInt<u32>),
859}
860
861#[macro_export]
862macro_rules! dtv_property {
863 ( $property:ident ) => {
864 $property($crate::fe::sys::DtvPropertyRequest::new(()))
865 };
866 ( $property:ident($data:expr) ) => {
867 $property($crate::fe::sys::DtvPropertyRequest::new($data))
868 };
869 ( $property:ident, $data:expr ) => {
870 $property($crate::fe::sys::DtvPropertyRequest::new($data))
871 };
872}
873
874#[macro_export]
875macro_rules! dtv_property_parse {
876 ( $property:ident($data:expr)) => {
877 $property($crate::fe::sys::DtvPropertyRequest::new($data.parse().with_context(||format!("Invalid {}: {}", stringify!($property), $data))?))
878 };
879}
880
881impl FromStr for DtvProperty {
882 type Err = anyhow::Error;
883 fn from_str(s: &str) -> Result<Self, Self::Err> {
884 let (k, v) = s.split_once('=').context("Invalid line")?;
885 let v = v.trim();
886 Ok(match k.trim() {
887 "FREQUENCY" => dtv_property_parse!(DTV_FREQUENCY(v)),
888 "MODULATION" => dtv_property_parse!(DTV_MODULATION(v)),
889 "BANDWIDTH_HZ" => dtv_property_parse!(DTV_BANDWIDTH_HZ(v)),
890 "INVERSION" => dtv_property_parse!(DTV_INVERSION(v)),
891 "SYMBOL_RATE" => dtv_property_parse!(DTV_SYMBOL_RATE(v)),
892 "INNER_FEC" => dtv_property_parse!(DTV_INNER_FEC(v)),
893 "VOLTAGE" => dtv_property_parse!(DTV_VOLTAGE(v)),
894 "TONE" => dtv_property_parse!(DTV_TONE(v)),
895 "PILOT" => dtv_property_parse!(DTV_PILOT(v)),
896 "ROLLOFF" => dtv_property_parse!(DTV_ROLLOFF(v)),
897
898 "DELIVERY_SYSTEM" => dtv_property_parse!(DTV_DELIVERY_SYSTEM(v)),
900
901 "ISDBT_PARTIAL_RECEPTION" => dtv_property_parse!(DTV_ISDBT_PARTIAL_RECEPTION(v)),
903 "ISDBT_SOUND_BROADCASTING" => dtv_property_parse!(DTV_ISDBT_SOUND_BROADCASTING(v)),
904
905 "ISDBT_SB_SUBCHANNEL_ID" => dtv_property_parse!(DTV_ISDBT_SB_SUBCHANNEL_ID(v)),
906 "ISDBT_SB_SEGMENT_IDX" => dtv_property_parse!(DTV_ISDBT_SB_SEGMENT_IDX(v)),
907 "ISDBT_SB_SEGMENT_COUNT" => dtv_property_parse!(DTV_ISDBT_SB_SEGMENT_COUNT(v)),
908
909 "ISDBT_LAYERA_FEC" => dtv_property_parse!(DTV_ISDBT_LAYERA_FEC(v)),
910 "ISDBT_LAYERA_MODULATION" => dtv_property_parse!(DTV_ISDBT_LAYERA_MODULATION(v)),
911 "ISDBT_LAYERA_SEGMENT_COUNT" => dtv_property_parse!(DTV_ISDBT_LAYERA_SEGMENT_COUNT(v)),
912 "ISDBT_LAYERA_TIME_INTERLEAVING" => {
913 dtv_property_parse!(DTV_ISDBT_LAYERA_TIME_INTERLEAVING(v))
914 }
915
916 "ISDBT_LAYERB_FEC" => dtv_property_parse!(DTV_ISDBT_LAYERB_FEC(v)),
917 "ISDBT_LAYERB_MODULATION" => dtv_property_parse!(DTV_ISDBT_LAYERB_MODULATION(v)),
918 "ISDBT_LAYERB_SEGMENT_COUNT" => dtv_property_parse!(DTV_ISDBT_LAYERB_SEGMENT_COUNT(v)),
919 "ISDBT_LAYERB_TIME_INTERLEAVING" => {
920 dtv_property_parse!(DTV_ISDBT_LAYERB_TIME_INTERLEAVING(v))
921 }
922
923 "ISDBT_LAYERC_FEC" => dtv_property_parse!(DTV_ISDBT_LAYERC_FEC(v)),
924 "ISDBT_LAYERC_MODULATION" => dtv_property_parse!(DTV_ISDBT_LAYERC_MODULATION(v)),
925 "ISDBT_LAYERC_SEGMENT_COUNT" => dtv_property_parse!(DTV_ISDBT_LAYERC_SEGMENT_COUNT(v)),
926 "ISDBT_LAYERC_TIME_INTERLEAVING" => {
927 dtv_property_parse!(DTV_ISDBT_LAYERC_TIME_INTERLEAVING(v))
928 }
929
930 "CODE_RATE_HP" => dtv_property_parse!(DTV_CODE_RATE_HP(v)),
932 "CODE_RATE_LP" => dtv_property_parse!(DTV_CODE_RATE_LP(v)),
933 "GUARD_INTERVAL" => dtv_property_parse!(DTV_GUARD_INTERVAL(v)),
934 "TRANSMISSION_MODE" => dtv_property_parse!(DTV_TRANSMISSION_MODE(v)),
935 "HIERARCHY" => dtv_property_parse!(DTV_HIERARCHY(v)),
936
937 "ISDBT_LAYER_ENABLED" => dtv_property_parse!(DTV_ISDBT_LAYER_ENABLED(v)),
938
939 "STREAM_ID" => dtv_property_parse!(DTV_STREAM_ID(v)),
940
941 "ATSCMH_FIC_VER" => dtv_property_parse!(DTV_ATSCMH_FIC_VER(v)),
943 "ATSCMH_PARADE_ID" => dtv_property_parse!(DTV_ATSCMH_PARADE_ID(v)),
944 "ATSCMH_NOG" => dtv_property_parse!(DTV_ATSCMH_NOG(v)),
945 "ATSCMH_TNOG" => dtv_property_parse!(DTV_ATSCMH_TNOG(v)),
946 "ATSCMH_SGN" => dtv_property_parse!(DTV_ATSCMH_SGN(v)),
947 "ATSCMH_PRC" => dtv_property_parse!(DTV_ATSCMH_PRC(v)),
948
949 "INTERLEAVING" => dtv_property_parse!(DTV_INTERLEAVING(v)),
950 "LNA" => dtv_property_parse!(DTV_LNA(v)),
951 &_ => bail!("Invalid key {}", k),
952 })
953 }
954}
955
956pub const DTV_IOCTL_MAX_MSGS: usize = 64;
958
959#[repr(C)]
960#[derive(Debug)]
961pub struct FeParameters {
962 pub frequency: u32,
965 pub inversion: u32,
966 __reserved_1: [u8; 28],
968}
969
970pub const FE_MAX_EVENT: usize = 8;
971
972#[repr(C)]
973#[derive(Debug)]
974pub struct FeEvent {
975 pub status: u32,
976 pub parameters: FeParameters,
977}
978
979impl Default for FeEvent {
980 #[inline]
981 fn default() -> Self {
982 unsafe { mem::zeroed::<Self>() }
983 }
984}
985
986impl FeEvent {
987 #[inline]
988 pub fn as_mut_ptr(&mut self) -> *mut FeEvent {
989 self as *mut _
990 }
991}