14 #include <linux/dvb/dmx.h> 15 #include <linux/dvb/frontend.h> 16 #include <sys/ioctl.h> 26 #define DVBS_TUNE_TIMEOUT 9000 //ms 27 #define DVBS_LOCK_TIMEOUT 2000 //ms 28 #define DVBC_TUNE_TIMEOUT 9000 //ms 29 #define DVBC_LOCK_TIMEOUT 2000 //ms 30 #define DVBT_TUNE_TIMEOUT 9000 //ms 31 #define DVBT_LOCK_TIMEOUT 2000 //ms 32 #define ATSC_TUNE_TIMEOUT 9000 //ms 33 #define ATSC_LOCK_TIMEOUT 2000 //ms 35 #define SCR_RANDOM_TIMEOUT 500 // ms (add random value up to this when tuning SCR device to avoid lockups) 40 { 0, PILOT_OFF,
trNOOP(
"off") },
41 { 1, PILOT_ON,
trNOOP(
"on") },
42 { 999, PILOT_AUTO,
trNOOP(
"auto") },
47 { 0, INVERSION_OFF,
trNOOP(
"off") },
48 { 1, INVERSION_ON,
trNOOP(
"on") },
49 { 999, INVERSION_AUTO,
trNOOP(
"auto") },
54 { 5, 5000000,
"5 MHz" },
55 { 6, 6000000,
"6 MHz" },
56 { 7, 7000000,
"7 MHz" },
57 { 8, 8000000,
"8 MHz" },
58 { 10, 10000000,
"10 MHz" },
59 { 1712, 1712000,
"1.712 MHz" },
64 { 0, FEC_NONE,
trNOOP(
"none") },
65 { 12, FEC_1_2,
"1/2" },
66 { 23, FEC_2_3,
"2/3" },
67 { 34, FEC_3_4,
"3/4" },
68 { 35, FEC_3_5,
"3/5" },
69 { 45, FEC_4_5,
"4/5" },
70 { 56, FEC_5_6,
"5/6" },
71 { 67, FEC_6_7,
"6/7" },
72 { 78, FEC_7_8,
"7/8" },
73 { 89, FEC_8_9,
"8/9" },
74 { 910, FEC_9_10,
"9/10" },
75 { 999, FEC_AUTO,
trNOOP(
"auto") },
80 { 16, QAM_16,
"QAM16" },
81 { 32, QAM_32,
"QAM32" },
82 { 64, QAM_64,
"QAM64" },
83 { 128, QAM_128,
"QAM128" },
84 { 256, QAM_256,
"QAM256" },
87 { 6, APSK_16,
"16APSK" },
88 { 7, APSK_32,
"32APSK" },
89 { 10, VSB_8,
"VSB8" },
90 { 11, VSB_16,
"VSB16" },
91 { 12, DQPSK,
"DQPSK" },
92 { 999, QAM_AUTO,
trNOOP(
"auto") },
96 #define DVB_SYSTEM_1 0 // see also nit.c 97 #define DVB_SYSTEM_2 1 113 { 2, TRANSMISSION_MODE_2K,
"2K" },
115 { 8, TRANSMISSION_MODE_8K,
"8K" },
118 { 999, TRANSMISSION_MODE_AUTO,
trNOOP(
"auto") },
123 { 4, GUARD_INTERVAL_1_4,
"1/4" },
124 { 8, GUARD_INTERVAL_1_8,
"1/8" },
125 { 16, GUARD_INTERVAL_1_16,
"1/16" },
126 { 32, GUARD_INTERVAL_1_32,
"1/32" },
130 { 999, GUARD_INTERVAL_AUTO,
trNOOP(
"auto") },
135 { 0, HIERARCHY_NONE,
trNOOP(
"none") },
136 { 1, HIERARCHY_1,
"1" },
137 { 2, HIERARCHY_2,
"2" },
138 { 4, HIERARCHY_4,
"4" },
139 { 999, HIERARCHY_AUTO,
trNOOP(
"auto") },
144 { 0, ROLLOFF_AUTO,
trNOOP(
"auto") },
145 { 20, ROLLOFF_20,
"0.20" },
146 { 25, ROLLOFF_25,
"0.25" },
147 { 35, ROLLOFF_35,
"0.35" },
178 *String =
tr(Map[n].userString);
209 return Value >= 0 && Value != 999 ? sprintf(p,
"%c%d", Name, Value) : 0;
214 #define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*'))) 241 int n = strtol(s, &p, 10);
242 if (!errno && p != s) {
248 esyslog(
"ERROR: invalid value for parameter '%c'", *(s - 1));
262 guard = GUARD_INTERVAL_AUTO;
270 switch (toupper(*s)) {
289 default:
esyslog(
"ERROR: unknown parameter key '%c'", *s);
298 #define TUNER_POLL_TIMEOUT 10 // ms 328 bool SetFrontendType(
const cChannel *Channel);
332 void ClearEventQueue(
void)
const;
333 bool GetFrontendStatus(fe_status_t &Status)
const;
335 void ExecuteDiseqc(
const cDiseqc *Diseqc,
int *Frequency);
336 void ResetToneAndVoltage(
void);
337 bool SetFrontend(
void);
338 virtual void Action(
void);
345 bool BondingOk(
const cChannel *Channel,
bool ConsiderOccupied =
false)
const;
348 bool IsTunedTo(
const cChannel *Channel)
const;
349 void SetChannel(
const cChannel *Channel);
350 bool Locked(
int TimeoutMs = 0);
352 bool GetSignalStats(
int &Valid,
double *Strength = NULL,
double *Cnr = NULL,
double *BerPre = NULL,
double *BerPost = NULL,
double *Per = NULL,
int *Status = NULL)
const;
353 int GetSignalStrength(
void)
const;
354 int GetSignalQuality(
void)
const;
361 frontendType = SYS_UNDEFINED;
363 fd_frontend = Fd_Frontend;
369 lastTimeoutReport = 0;
378 lnbPowerTurnedOn =
false;
379 tunerStatus = tsIdle;
381 bondedMaster =
false;
382 SetDescription(
"frontend %d/%d tuner", adapter, frontend);
388 tunerStatus = tsIdle;
405 ResetToneAndVoltage();
406 bondedMaster =
false;
409 dsyslog(
"tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
413 esyslog(
"ERROR: tuner %d/%d already bonded with tuner %d/%d, can't bond with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend, Tuner->
adapter, Tuner->
frontend);
421 dsyslog(
"tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
422 while (t->bondedTuner !=
this)
424 if (t == bondedTuner)
425 t->bondedTuner = NULL;
427 t->bondedTuner = bondedTuner;
428 bondedMaster =
false;
440 return diseqc->Commands();
444 bool VoltOff = dtp.Polarization() ==
'V' || dtp.Polarization() ==
'R';
454 cString BondingParams = GetBondingParams(Channel);
456 if (t->device->Priority() >
IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
457 if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
461 }
while (t != bondedTuner);
483 dsyslog(
"tuner %d/%d is now bonded master", adapter, frontend);
489 if (tunerStatus == tsIdle)
491 if (channel.Source() != Channel->
Source() || channel.Transponder() != Channel->
Transponder())
494 return strcmp(channel.Parameters(), Channel->
Parameters()) == 0;
502 cDvbTuner *BondedMaster = GetBondedMaster();
503 if (BondedMaster ==
this) {
504 if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
510 else if (strcmp(GetBondingParams(Channel), BondedMaster->
GetBondingParams()) != 0)
514 if (!IsTunedTo(Channel))
518 lastTimeoutReport = 0;
523 tunerStatus = tsIdle;
524 ResetToneAndVoltage();
526 if (bondedTuner && device->IsPrimaryDevice())
532 bool isLocked = (tunerStatus >= tsLocked);
533 if (isLocked || !TimeoutMs)
537 if (TimeoutMs && tunerStatus < tsLocked)
538 locked.TimedWait(mutex, TimeoutMs);
539 return tunerStatus >= tsLocked;
546 dvb_frontend_event Event;
547 while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
556 if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
568 #define MAXFRONTENDCMDS 16 569 #define SETCMD(c, d) { Props[CmdSeq.num].cmd = (c);\ 570 Props[CmdSeq.num].u.data = (d);\ 571 if (CmdSeq.num++ > MAXFRONTENDCMDS) {\ 572 esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\ 577 bool cDvbTuner::GetSignalStats(
int &Valid,
double *Strength,
double *Cnr,
double *BerPre,
double *BerPost,
double *Per,
int *Status)
const 580 fe_status_t FeStatus;
582 dtv_properties CmdSeq;
583 memset(&Props, 0,
sizeof(Props));
584 memset(&CmdSeq, 0,
sizeof(CmdSeq));
585 CmdSeq.props = Props;
587 if (ioctl(fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
588 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
600 if (Strength)
SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
601 if (Cnr)
SETCMD(DTV_STAT_CNR, 0);
602 if (BerPre) {
SETCMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0);
603 SETCMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0); }
604 if (BerPost) {
SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
605 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0); }
606 if (Per) {
SETCMD(DTV_STAT_ERROR_BLOCK_COUNT, 0);
607 SETCMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0); }
608 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
609 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
614 if (Props[i].u.st.len > 0) {
615 switch (Props[i].u.st.stat[0].scale) {
616 case FE_SCALE_DECIBEL: *Strength = double(Props[i].u.st.stat[0].svalue) / 1000;
625 if (Props[i].u.st.len > 0) {
626 switch (Props[i].u.st.stat[0].scale) {
627 case FE_SCALE_DECIBEL: *Cnr = double(Props[i].u.st.stat[0].svalue) / 1000;
636 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
637 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
638 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
639 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
641 *BerPre = double(ebc) / tbc;
649 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
650 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
651 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
652 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
654 *BerPost = double(ebc) / tbc;
662 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
663 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
664 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
665 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
667 *Per = double(ebc) / tbc;
674 #ifdef DEBUG_SIGNALSTATS 675 fprintf(stderr,
"FE %d/%d: API5 %04X", adapter, frontend, Valid);
682 fprintf(stderr,
"\n");
698 double v = 10.0 * (dB1000 - High) / (Low - High);
702 #define REF_S1(q1) (mod == QPSK) ? q1 : 0 703 #define REF_S2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == PSK_8) ? q2 : (mod == APSK_16) ? q3 : (mod == APSK_32) ? q4 : 0 704 #define REF_T1(q1, q2, q3) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : 0 705 #define REF_T2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_256) ? q4 : 0 706 #define REF_C1(q1, q2, q3, q4, q5) (mod == QAM_16) ? q1 : (mod == QAM_32) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_128) ? q4 : (mod == QAM_256) ? q5: 0 713 int mod = (FeModulation >= 0) ? FeModulation : dtp.
Modulation();
714 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH();
715 int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
722 if (mod == QAM_AUTO) mod = QPSK;
724 case FEC_1_2: pref =
REF_T1(-93, -87, -82);
break;
726 case FEC_2_3: pref =
REF_T1(-91, -85, -80);
break;
727 case FEC_3_4: pref =
REF_T1(-90, -84, -78);
break;
728 case FEC_5_6: pref =
REF_T1(-89, -83, -77);
break;
729 case FEC_7_8: pref =
REF_T1(-88, -82, -76);
break;
733 if (mod == QAM_AUTO) mod = QAM_64;
735 case FEC_1_2: pref =
REF_T2(-96, -91, -86, -82);
break;
737 case FEC_3_5: pref =
REF_T2(-95, -89, -85, -80);
break;
738 case FEC_2_3: pref =
REF_T2(-94, -88, -83, -78);
break;
739 case FEC_3_4: pref =
REF_T2(-93, -87, -82, -76);
break;
740 case FEC_4_5: pref =
REF_T2(-92, -86, -81, -75);
break;
741 case FEC_5_6: pref =
REF_T2(-92, -86, -80, -74);
break;
745 int prel = (Strength / 1000) - pref;
746 ssi = (prel < -15) ? 0 :
747 (prel < 0) ? (prel + 15) * 2 / 3 :
748 (prel < 20) ? prel * 4 + 10 :
749 (prel < 35) ? (prel - 20) * 2 / 3 + 90 :
751 #ifdef DEBUG_SIGNALSTRENGTH 752 fprintf(stderr,
"SSI-T: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(sys:%d, mod:%d, fec:%d)\n", Strength, pref, prel, ssi, dtp.System(), mod, fec);
761 if (mod == QAM_AUTO) mod = QAM_256;
763 int pref =
REF_C1(-79, -76, -73, -70, -67);
765 int prel = (Strength / 1000) - pref;
766 ssi = (prel < -15) ? 0 :
767 (prel < 0) ? (prel + 15) * 2 / 3 :
768 (prel < 20) ? prel * 4 + 10 :
769 (prel < 35) ? (prel - 20) * 2 / 3 + 90 :
771 #ifdef DEBUG_SIGNALSTRENGTH 772 fprintf(stderr,
"SSI-C: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(mod:%d)\n", Strength, pref, prel, ssi, mod);
776 else if (Channel->
IsSat())
783 #define BER_ERROR_FREE (1000*1000*1000) // 1/10^-9 785 int SignalToSQI(
const cChannel *Channel,
int Signal,
int Ber,
int FeModulation,
int FeCoderateH,
int FeFec)
793 int mod = (FeModulation >= 0) ? FeModulation : dtp.
Modulation();
794 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH();
795 int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
802 if (mod == QAM_AUTO) mod = QPSK;
804 case FEC_1_2: cnref =
REF_T1(51, 108, 165);
break;
806 case FEC_2_3: cnref =
REF_T1(69, 131, 187);
break;
807 case FEC_3_4: cnref =
REF_T1(79, 146, 202);
break;
808 case FEC_5_6: cnref =
REF_T1(89, 156, 216);
break;
809 case FEC_7_8: cnref =
REF_T1(97, 160, 225);
break;
813 if (mod == QAM_AUTO) mod = QAM_64;
815 case FEC_1_2: cnref =
REF_T2(35, 87, 130, 170);
break;
817 case FEC_3_5: cnref =
REF_T2(47, 101, 148, 194);
break;
818 case FEC_2_3: cnref =
REF_T2(56, 114, 162, 208);
break;
819 case FEC_3_4: cnref =
REF_T2(66, 125, 177, 229);
break;
820 case FEC_4_5: cnref =
REF_T2(72, 133, 187, 243);
break;
821 case FEC_5_6: cnref =
REF_T2(77, 138, 194, 251);
break;
825 int cnrel = (Signal/100) - cnref;
829 ber_sqi = (Ber < 1000) ? 0 :
830 (Ber >= 10000000) ? 100 :
831 (int)(20 * log10(Ber)) - 40;
833 cnr_sqi = (cnrel < -70) ? 0 :
834 (cnrel < +30) ? (100 + (cnrel - 30)) :
836 sqi = (cnr_sqi * ber_sqi) / 100;
841 ber_sqi = (Ber < 10000) ? 0 :
842 (Ber >= 10000000) ? 100 * 100 / 6 :
845 sqi = (cnrel < -30) ? 0 :
846 (cnrel <= +30) ? (cnrel + 30) * ber_sqi / 1000 :
851 #ifdef DEBUG_SIGNALQUALITY 852 fprintf(stderr,
"SQI-T: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
857 if (mod == QAM_AUTO) mod = QAM_256;
859 int cnref =
REF_C1(200, 230, 260, 290, 320);
861 int cnrel = (Signal / 100) - cnref;
862 int ber_sqi = (Ber < 1000) ? 0 :
863 (Ber >= 10000000) ? 100 :
864 (int)(20 * log10(Ber)) - 40;
866 int cnr_sqi = (cnrel < -70) ? 0 :
867 (cnrel < +30) ? (100 + (cnrel - 30)) :
869 sqi = (cnr_sqi * ber_sqi) / 100;
872 #ifdef DEBUG_SIGNALQUALITY 873 dsyslog(
"SQI-C: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
877 else if (Channel->
IsSat()) {
880 if (mod == QAM_AUTO) mod = QPSK;
882 case FEC_1_2: cnref =
REF_S1(38);
break;
884 case FEC_2_3: cnref =
REF_S1(56);
break;
885 case FEC_3_4: cnref =
REF_S1(67);
break;
886 case FEC_5_6: cnref =
REF_S1(77);
break;
887 case FEC_7_8: cnref =
REF_S1(84);
break;
893 #ifdef DEBUG_SIGNALQUALITY 894 dsyslog(
"SQI-S1: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
899 if (mod == QAM_AUTO) mod = QAM_64;
903 case FEC_2_5: cnref =
REF_S2( 7, 65, 90, 126);
break;
904 case FEC_1_2: cnref =
REF_S2( 20, 65, 90, 126);
break;
905 case FEC_3_5: cnref =
REF_S2( 32, 65, 90, 126);
break;
907 case FEC_2_3: cnref =
REF_S2( 41, 76, 90, 126);
break;
908 case FEC_3_4: cnref =
REF_S2( 50, 66, 102, 126);
break;
909 case FEC_4_5: cnref =
REF_S2( 57, 89, 110, 136);
break;
910 case FEC_5_6: cnref =
REF_S2( 62, 104, 116, 143);
break;
911 case FEC_8_9: cnref =
REF_S2( 72, 117, 129, 157);
break;
912 case FEC_9_10: cnref =
REF_S2( 74, 120, 131, 161);
break;
918 #ifdef DEBUG_SIGNALQUALITY 919 dsyslog(
"SQI-S2: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
931 for (
int i = 0; i < 1; i++) {
933 dtv_properties CmdSeq;
934 memset(&Props, 0,
sizeof(Props));
935 memset(&CmdSeq, 0,
sizeof(CmdSeq));
936 CmdSeq.props = Props;
937 SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
938 SETCMD(DTV_MODULATION, 0);
939 SETCMD(DTV_CODE_RATE_HP, 0);
941 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
942 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
945 int FeMod = (Props[1].u.st.len > 0) ? (
int)Props[1].u.data : -1;
946 int FeCod = (Props[2].u.st.len > 0) ? (
int)Props[2].u.data : -1;
947 int FeFec = (Props[3].u.st.len > 0) ? (
int)Props[3].u.data : -1;
949 if (Props[0].u.st.len > 0) {
950 switch (Props[0].u.st.stat[0].scale) {
951 case FE_SCALE_DECIBEL: Signal =
StrengthToSSI(&channel, Props[0].u.st.stat[0].svalue, FeMod, FeCod, FeFec);
953 case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
957 #ifdef DEBUG_SIGNALSTRENGTH 958 fprintf(stderr,
"FE %d/%d: API5 %d %08X %.1f S = %d\n", adapter, frontend, Props[0].u.st.stat[0].scale,
int(Props[0].u.st.stat[0].svalue),
int(Props[0].u.st.stat[0].svalue) / 1000.0, Signal);
968 if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
973 uint16_t MaxSignal = 0xFFFF;
976 switch (subsystemId) {
979 MaxSignal = 670;
break;
981 int s = int(Signal) * 100 / MaxSignal;
984 #ifdef DEBUG_SIGNALSTRENGTH 985 fprintf(stderr,
"FE %d/%d: API3 %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
990 #define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set 995 for (
int i = 0; i < 1; i++) {
997 dtv_properties CmdSeq;
998 memset(&Props, 0,
sizeof(Props));
999 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1000 CmdSeq.props = Props;
1002 SETCMD(DTV_MODULATION, 0);
1003 SETCMD(DTV_CODE_RATE_HP, 0);
1004 SETCMD(DTV_INNER_FEC, 0);
1005 SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
1006 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
1007 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1008 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
1011 int FeMod = (Props[1].u.st.len > 0) ? (
int)Props[1].u.data : -1;
1012 int FeCod = (Props[2].u.st.len > 0) ? (
int)Props[2].u.data : -1;
1013 int FeFec = (Props[3].u.st.len > 0) ? (
int)Props[3].u.data : -1;
1015 if (Props[4].u.st.len > 0 && Props[4].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[5].u.st.len > 0 && Props[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
1016 uint64_t ebc = Props[4].u.st.stat[0].uvalue;
1017 uint64_t tbc = Props[5].u.st.stat[0].uvalue;
1019 uint64_t BerRev = tbc / ebc;
1025 if (Props[0].u.st.len > 0) {
1026 switch (Props[0].u.st.stat[0].scale) {
1027 case FE_SCALE_DECIBEL: Cnr =
SignalToSQI(&channel, Props[0].u.st.stat[0].svalue, Ber, FeMod, FeCod, FeFec);
1029 case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1033 #ifdef DEBUG_SIGNALQUALITY 1034 fprintf(stderr,
"FE %d/%d: API5 %d %08X %.1f Q = %d\n", adapter, frontend, Props[0].u.st.stat[0].scale,
int(Props[0].u.st.stat[0].svalue),
int(Props[0].u.st.stat[0].svalue) / 1000.0, Cnr);
1043 if (GetFrontendStatus(Status)) {
1045 if ((Status & FE_HAS_LOCK) == 0) {
1046 if ((Status & FE_HAS_SIGNAL) == 0)
1048 if ((Status & FE_HAS_CARRIER) == 0)
1050 if ((Status & FE_HAS_VITERBI) == 0)
1052 if ((Status & FE_HAS_SYNC) == 0)
1056 #ifdef DEBUG_SIGNALQUALITY 1061 if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
1063 if (errno != EINTR) {
1065 #ifdef DEBUG_SIGNALQUALITY 1071 #ifdef DEBUG_SIGNALQUALITY 1076 if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
1078 if (errno != EINTR) {
1080 #ifdef DEBUG_SIGNALQUALITY 1086 #ifdef DEBUG_SIGNALQUALITY 1091 if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1) {
1092 if (Unc != lastUncValue) {
1093 #ifdef DEBUG_SIGNALQUALITY 1094 fprintf(stderr,
"FE %d/%d: API3 UNC = %u %u %u\n", adapter, frontend, Unc, lastUncValue, lastUncDelta);
1096 lastUncDelta = (Unc >= lastUncValue) ? Unc - lastUncValue : lastUncValue - Unc;
1098 lastUncChange = time(NULL);
1112 int t = time(NULL) - lastUncChange - 2;
1114 Unc >>=
min(t,
int(
sizeof(Unc) * 8 - 1));
1117 #ifdef DEBUG_SIGNALQUALITY 1118 fprintf(stderr,
"FE %d/%d: API3 UNC = %u\n", adapter, frontend, Unc);
1123 if (errno != EINTR) {
1125 #ifdef DEBUG_SIGNALQUALITY 1131 uint16_t MinSnr = 0x0000;
1132 uint16_t MaxSnr = 0xFFFF;
1135 switch (subsystemId) {
1138 if (frontendType == SYS_DVBS2) {
1147 MaxSnr = 255;
break;
1149 int a = int(
constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
1150 int b = 100 - (Unc * 10 + (Ber / 256) * 5);
1156 #ifdef DEBUG_SIGNALQUALITY 1157 fprintf(stderr,
"FE %d/%d: API3 %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ?
int(Ber) : -1, HasUnc ?
int(Unc) : -1, q);
1166 while (f && f < 1000000)
1175 positioner->SetFrontend(fd_frontend);
1182 if (!lnbPowerTurnedOn) {
1183 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13));
1184 lnbPowerTurnedOn =
true;
1187 if (Diseqc->
IsScr())
1189 struct dvb_diseqc_master_cmd cmd;
1190 const char *CurrentAction = NULL;
1193 for (
int i = 0; !Break; i++) {
1194 cmd.msg_len =
sizeof(cmd.msg);
1200 bool d = i >= diseqcOffset;
1225 default:
esyslog(
"ERROR: unknown diseqc command %d", da);
1228 diseqcOffset = i + 1;
1230 positioner = Positioner;
1232 ResetToneAndVoltage();
1233 if (Diseqc->
IsScr())
1239 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
1240 CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
1245 int ds = SYS_UNDEFINED;
1249 ds = SYS_DVBC_ANNEX_AC;
1250 else if (Channel->
IsSat())
1252 else if (Channel->
IsTerr())
1255 esyslog(
"ERROR: can't determine frontend type for channel %d (%s)", Channel->
Number(), Channel->
Name());
1262 memset(&Props, 0,
sizeof(Props));
1263 dtv_properties CmdSeq;
1264 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1265 CmdSeq.props = Props;
1267 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1268 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
1277 if (frontendType == SYS_UNDEFINED)
1280 SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
1281 if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
1282 int frequency = channel.Frequency();
1284 if (
const cDiseqc *diseqc =
Diseqcs.
Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
1285 frequency -= diseqc->Lof();
1286 if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
1287 if (IsBondedMaster()) {
1288 ExecuteDiseqc(diseqc, &frequency);
1293 ResetToneAndVoltage();
1294 lastDiseqc = diseqc;
1295 lastSource = channel.Source();
1299 esyslog(
"ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
1304 int tone = SEC_TONE_OFF;
1307 tone = SEC_TONE_OFF;
1313 int volt = (dtp.Polarization() ==
'V' || dtp.Polarization() ==
'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
1314 if (!IsBondedMaster()) {
1315 tone = SEC_TONE_OFF;
1316 volt = SEC_VOLTAGE_13;
1318 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
1319 CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
1321 frequency = abs(frequency);
1324 SETCMD(DTV_FREQUENCY, frequency * 1000UL);
1325 SETCMD(DTV_MODULATION, dtp.Modulation());
1326 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1327 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1328 SETCMD(DTV_INVERSION, dtp.Inversion());
1329 if (frontendType == SYS_DVBS2) {
1331 SETCMD(DTV_PILOT, dtp.Pilot());
1332 SETCMD(DTV_ROLLOFF, dtp.RollOff());
1338 SETCMD(DTV_ROLLOFF, ROLLOFF_35);
1344 else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
1347 SETCMD(DTV_INVERSION, dtp.Inversion());
1348 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1349 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1350 SETCMD(DTV_MODULATION, dtp.Modulation());
1355 else if (frontendType == SYS_DVBT || frontendType ==
SYS_DVBT2) {
1358 SETCMD(DTV_INVERSION, dtp.Inversion());
1359 SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
1360 SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
1361 SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
1362 SETCMD(DTV_MODULATION, dtp.Modulation());
1363 SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
1364 SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
1365 SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
1368 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1378 else if (frontendType == SYS_ATSC) {
1381 SETCMD(DTV_INVERSION, dtp.Inversion());
1382 SETCMD(DTV_MODULATION, dtp.Modulation());
1388 esyslog(
"ERROR: attempt to set channel with unknown DVB frontend type");
1392 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1393 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
1402 bool LostLock =
false;
1403 fe_status_t Status = (fe_status_t)0;
1405 fe_status_t NewStatus;
1406 if (GetFrontendStatus(NewStatus))
1409 int WaitTime = 1000;
1410 switch (tunerStatus) {
1414 tunerStatus = SetFrontend() ? tsPositioning : tsIdle;
1418 if (positioner->IsMoving())
1420 else if (diseqcOffset) {
1422 tunerStatus = tsSet;
1426 tunerStatus = tsTuned;
1433 tunerStatus = tsSet;
1436 if (time(NULL) - lastTimeoutReport > 60) {
1437 isyslog(
"frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1438 lastTimeoutReport = time(NULL);
1445 if (Status & FE_REINIT) {
1446 tunerStatus = tsSet;
1449 isyslog(
"frontend %d/%d was reinitialized", adapter, frontend);
1450 lastTimeoutReport = 0;
1453 else if (Status & FE_HAS_LOCK) {
1455 isyslog(
"frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1458 tunerStatus = tsLocked;
1460 lastTimeoutReport = 0;
1462 else if (tunerStatus == tsLocked) {
1464 isyslog(
"frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1465 tunerStatus = tsTuned;
1466 Timer.
Set(lockTimeout);
1467 lastTimeoutReport = 0;
1471 default:
esyslog(
"ERROR: unknown tuner status %d", tunerStatus);
1473 newSet.TimedWait(mutex, WaitTime);
1486 virtual void SetData(
cChannel *Channel);
1487 virtual void GetData(
cChannel *Channel);
1488 virtual cOsdItem *GetOsdItem(
void);
1515 #define ST(s) if (strchr(s, type)) 1533 default:
return NULL;
1580 frontend = Frontend;
1583 numDeliverySystems = 0;
1585 bondedDevice = NULL;
1586 needsDetachBondedReceivers =
false;
1591 int fd_frontend = DvbOpen(
DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
1595 fd_ca = DvbOpen(
DEV_DVB_CA, adapter, frontend, O_RDWR);
1598 checkTsBuffer =
false;
1606 if (fd_frontend >= 0) {
1607 if (QueryDeliverySystems(fd_frontend))
1608 dvbTuner =
new cDvbTuner(
this, fd_frontend, adapter, frontend);
1611 esyslog(
"ERROR: can't open DVB device %d/%d", adapter, frontend);
1613 StartSectionHandler();
1618 StopSectionHandler();
1633 cString FileName = DvbName(Name, Adapter, Frontend);
1634 int fd = open(FileName, Mode);
1635 if (fd < 0 && ReportError)
1643 if (access(FileName, F_OK) == 0) {
1644 int f = open(FileName, O_RDONLY);
1649 else if (errno != ENODEV && errno != EINVAL)
1652 else if (errno != ENOENT)
1660 dsyslog(
"probing %s", *FileName);
1662 if (dp->Probe(Adapter, Frontend))
1665 dsyslog(
"creating cDvbDevice");
1673 if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1675 if (numDeliverySystems)
1683 return frontendInfo.name;
1696 while ((a = DvbDir.
Next()) != NULL) {
1700 if (AdapterDir.
Ok()) {
1702 while ((f = AdapterDir.
Next()) != NULL) {
1714 if (Nodes.
Size() > 0) {
1716 for (
int i = 0; i < Nodes.
Size(); i++) {
1719 if (2 == sscanf(Nodes[i],
"%d %d", &Adapter, &Frontend)) {
1720 if (Exists(Adapter, Frontend)) {
1723 if (useDvbDevices && UseDevice(NextCardIndex())) {
1724 if (Probe(Adapter, Frontend))
1735 isyslog(
"found %d DVB device%s", Found, Found > 1 ?
"s" :
"");
1737 isyslog(
"using only %d DVB device%s", Used, Used != 1 ?
"s" :
"");
1740 isyslog(
"no DVB device found");
1746 numDeliverySystems = 0;
1747 if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
1751 dtv_property Props[1];
1752 dtv_properties CmdSeq;
1755 memset(&Props, 0,
sizeof(Props));
1756 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1757 CmdSeq.props = Props;
1758 SETCMD(DTV_API_VERSION, 0);
1759 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1767 bool LegacyMode =
true;
1769 memset(&Props, 0,
sizeof(Props));
1770 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1771 CmdSeq.props = Props;
1773 int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
1775 for (uint i = 0; i < Props[0].u.buffer.len; i++) {
1777 esyslog(
"ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
1780 deliverySystems[numDeliverySystems++] = Props[0].u.buffer.data[i];
1785 esyslog(
"ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
1790 switch (frontendInfo.type) {
1791 case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1793 deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1795 case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1797 deliverySystems[numDeliverySystems++] =
SYS_DVBT2;
1799 case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC;
break;
1800 case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC;
break;
1801 default:
esyslog(
"ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
1804 if (numDeliverySystems > 0) {
1806 for (
int i = 0; i < numDeliverySystems; i++)
1809 if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QPSK, ModulationValues)); }
1810 if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_16, ModulationValues)); }
1811 if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_32, ModulationValues)); }
1812 if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_64, ModulationValues)); }
1813 if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_128, ModulationValues)); }
1814 if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_256, ModulationValues)); }
1815 if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(VSB_8, ModulationValues)); }
1816 if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(VSB_16, ModulationValues)); }
1819 ms =
"unknown modulations";
1820 isyslog(
"frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
1824 esyslog(
"ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
1836 int ErrorDevice = 0;
1839 if (
cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1840 if (
cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1841 if (!DvbDevice1->Bond(DvbDevice2))
1845 ErrorDevice = d + 1;
1848 ErrorDevice = i + 1;
1850 esyslog(
"ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
1855 ErrorDevice = d + 1;
1858 ErrorDevice = i + 1;
1860 esyslog(
"ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
1880 if (!bondedDevice) {
1881 if (Device !=
this) {
1886 dsyslog(
"device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1891 esyslog(
"ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->
CardIndex() + 1);
1894 esyslog(
"ERROR: can't bond device %d with itself", CardIndex() + 1);
1897 esyslog(
"ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->
CardIndex() + 1);
1907 dsyslog(
"device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1908 while (d->bondedDevice !=
this)
1909 d = d->bondedDevice;
1910 if (d == bondedDevice)
1911 d->bondedDevice = NULL;
1913 d->bondedDevice = bondedDevice;
1914 bondedDevice = NULL;
1921 if (bondedDevice || Positioner())
1922 return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1934 dmx_pes_filter_params pesFilterParams;
1935 memset(&pesFilterParams, 0,
sizeof(pesFilterParams));
1937 if (Handle->
handle < 0) {
1939 if (Handle->
handle < 0) {
1944 pesFilterParams.pid = Handle->
pid;
1945 pesFilterParams.input = DMX_IN_FRONTEND;
1946 pesFilterParams.output = DMX_OUT_TS_TAP;
1947 pesFilterParams.pes_type= DMX_PES_OTHER;
1948 pesFilterParams.flags = DMX_IMMEDIATE_START;
1949 if (ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
1954 else if (!Handle->
used) {
1956 if (Type <= ptTeletext) {
1957 pesFilterParams.pid = 0x1FFF;
1958 pesFilterParams.input = DMX_IN_FRONTEND;
1959 pesFilterParams.output = DMX_OUT_DECODER;
1960 pesFilterParams.pes_type= DMX_PES_OTHER;
1961 pesFilterParams.flags = DMX_IMMEDIATE_START;
1962 CHECK(ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams));
1974 int f = open(FileName, O_RDWR | O_NONBLOCK);
1976 dmx_sct_filter_params sctFilterParams;
1977 memset(&sctFilterParams, 0,
sizeof(sctFilterParams));
1978 sctFilterParams.pid = Pid;
1979 sctFilterParams.timeout = 0;
1980 sctFilterParams.flags = DMX_IMMEDIATE_START;
1981 sctFilterParams.filter.filter[0] = Tid;
1982 sctFilterParams.filter.mask[0] = Mask;
1983 if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
1986 esyslog(
"ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
1991 esyslog(
"ERROR: can't open filter handle on '%s'", *FileName);
2002 for (
int i = 0; i < numDeliverySystems; i++) {
2003 if (deliverySystems[i] == DeliverySystem)
2014 || type ==
cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
2015 || type ==
cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
2021 if (!ProvidesSource(Channel->
Source()))
2026 dtp.
Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
2027 dtp.
Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
2028 dtp.
Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
2029 dtp.
Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
2030 dtp.
Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
2031 dtp.
Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
2032 dtp.
Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
2033 dtp.
Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
2034 dtp.
Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
2039 return DeviceHooksProvidesTransponder(Channel);
2045 bool result =
false;
2046 bool hasPriority = Priority ==
IDLEPRIORITY || Priority > this->Priority();
2047 bool needsDetachReceivers =
false;
2048 needsDetachBondedReceivers =
false;
2050 if (dvbTuner && ProvidesTransponder(Channel)) {
2051 result = hasPriority;
2054 if (dvbTuner->IsTunedTo(Channel)) {
2055 if (Channel->
Vpid() && !HasPid(Channel->
Vpid()) || Channel->
Apid(0) && !HasPid(Channel->
Apid(0)) || Channel->
Dpid(0) && !HasPid(Channel->
Dpid(0))) {
2057 if (CamSlot()->CanDecrypt(Channel))
2060 needsDetachReceivers =
true;
2069 needsDetachReceivers = Receiving();
2073 if (!BondingOk(Channel)) {
2076 if (d->Priority() >= Priority) {
2080 needsDetachReceivers |= d->Receiving();
2082 needsDetachBondedReceivers =
true;
2083 needsDetachReceivers |= Receiving();
2088 if (NeedsDetachReceivers)
2089 *NeedsDetachReceivers = needsDetachReceivers;
2095 return dvbTuner != NULL;
2100 return numDeliverySystems + numModulations;
2105 return dvbTuner ? dvbTuner->Positioner() : NULL;
2108 bool cDvbDevice::SignalStats(
int &Valid,
double *Strength,
double *Cnr,
double *BerPre,
double *BerPost,
double *Per,
int *Status)
const 2110 return dvbTuner ? dvbTuner->GetSignalStats(Valid, Strength, Cnr, BerPre, BerPost, Per, Status) :
false;
2115 return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
2120 return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
2125 return dvbTuner ? dvbTuner->GetTransponder() : NULL;
2130 return dvbTuner ? dvbTuner->IsTunedTo(Channel) :
false;
2141 dvbTuner->SetChannel(Channel);
2147 return dvbTuner ? dvbTuner->Locked(TimeoutMs) :
false;
2152 setTransferModeForDolbyDigital = Mode;
2158 fd_dvr = DvbOpen(
DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK,
true);
2178 if (cs->WantsTsData()) {
2180 Data = tsBuffer->Get(&Available, checkTsBuffer);
2183 Data = cs->Decrypt(Data, Available);
2184 tsBuffer->Skip(Available);
2185 checkTsBuffer = Data != NULL;
2189 Data = tsBuffer->Get();
2200 d->cDevice::DetachAllReceivers();
2202 }
while (d && d !=
this && needsDetachBondedReceivers);
2203 needsDetachBondedReceivers =
false;
2212 DvbDeviceProbes.
Add(
this);
2217 DvbDeviceProbes.
Del(
this,
false);
2222 uint32_t SubsystemId = 0;
2225 if (stat(FileName, &st) == 0) {
2229 while ((e = d.
Next()) != NULL) {
2230 if (strstr(e->d_name,
"frontend")) {
2232 if (FILE *f = fopen(FileName,
"r")) {
2234 char *s = ReadLine.
Read(f);
2238 if (s && 2 == sscanf(s,
"%u:%u", &Major, &Minor)) {
2239 if (((Major << 8) | Minor) == st.st_rdev) {
2240 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
2241 if ((f = fopen(FileName,
"r")) != NULL) {
2242 if (
char *s = ReadLine.
Read(f))
2243 SubsystemId = strtoul(s, NULL, 0) << 16;
2247 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idVendor", e->d_name);
2248 if ((f = fopen(FileName,
"r")) != NULL) {
2249 if (
char *s = ReadLine.
Read(f))
2250 SubsystemId = strtoul(s, NULL, 16) << 16;
2254 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_device", e->d_name);
2255 if ((f = fopen(FileName,
"r")) != NULL) {
2256 if (
char *s = ReadLine.
Read(f))
2257 SubsystemId |= strtoul(s, NULL, 0);
2261 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idProduct", e->d_name);
2262 if ((f = fopen(FileName,
"r")) != NULL) {
2263 if (
char *s = ReadLine.
Read(f))
2264 SubsystemId |= strtoul(s, NULL, 16);
static unsigned int FrequencyToHz(unsigned int f)
struct dirent * Next(void)
#define DTV_STAT_VALID_PER
virtual ~cDvbDeviceProbe()
const char * DeliverySystemNames[]
cDvbTransponderParameters(const char *Parameters=NULL)
bool GetSignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
int PrintParameter(char *p, char Name, int Value) const
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
bool IsBondedMaster(void) const
static bool Exists(int Adapter, int Frontend)
Checks whether the given adapter/frontend exists.
#define DTV_STAT_VALID_NONE
The cDevice class is the base from which actual devices can be derived.
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
void ResetToneAndVoltage(void)
#define SCR_RANDOM_TIMEOUT
#define DTV_STAT_HAS_VITERBI
int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
friend class cDvbSourceParam
const char * ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map=NULL)
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
int Position(void) const
Indicates which positioning mode to use in order to move the dish to a given satellite position...
static bool Initialize(void)
Initializes the DVB devices.
virtual bool GetTSPacket(uchar *&Data)
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data...
#define DVBT_TUNE_TIMEOUT
int UserIndex(int Value, const tDvbParameterMap *Map)
void Add(cListObject *Object, cListObject *After=NULL)
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
void UnBond(void)
Removes this device from any bonding it might have with other devices.
#define DTV_STAT_HAS_SYNC
#define DVBC_TUNE_TIMEOUT
int Ca(int Index=0) const
void ClearEventQueue(void) const
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
virtual cOsdItem * GetOsdItem(void)
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
static const int DeliverySystemNamesMax
#define DVBS_LOCK_TIMEOUT
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
static const char * GetDeliverySystemName(int Index)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
#define DVBC_LOCK_TIMEOUT
const tDvbParameterMap SystemValuesSat[]
virtual void Append(T Data)
#define REF_T2(q1, q2, q3, q4)
#define DVBT_LOCK_TIMEOUT
static uint32_t GetSubsystemId(int Adapter, int Frontend)
const tDvbParameterMap InversionValues[]
#define REF_C1(q1, q2, q3, q4, q5)
bool Parse(const char *s)
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
#define REF_T1(q1, q2, q3)
static int NumDevices(void)
Returns the total number of devices.
#define DTV_STAT_HAS_CARRIER
bool IsTunedTo(const cChannel *Channel) const
#define TUNER_POLL_TIMEOUT
void DelLivePids(void)
Deletes the live viewing PIDs.
int GetSignalStrength(void) const
#define DTV_STAT_VALID_BERPOST
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
cDvbTuner * GetBondedMaster(void)
cString ToString(char Type) const
bool Poll(int TimeoutMs=0)
#define REF_S2(q1, q2, q3, q4)
int MapToDriver(int Value, const tDvbParameterMap *Map)
bool QueryDeliverySystems(int fd_frontend)
cPositioner * GetPositioner(void)
const char * Parameters(void) const
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
A steerable satellite dish generally points to the south on the northern hemisphere, and to the north on the southern hemisphere (unless you're located directly on the equator, in which case the general direction is "up").
virtual void GotoAngle(int Longitude)
Move the dish to the given angular position.
int Modulation(void) const
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
const tDvbParameterMap HierarchyValues[]
const char * Name(void) const
char Polarization(void) const
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
#define DTV_STAT_VALID_STATUS
static bool Probe(int Adapter, int Frontend)
Probes for existing DVB devices.
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
uint32_t SubsystemId(void) const
#define MAXDELIVERYSYSTEMS
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Returns statistics about the currently received signal (if available).
virtual void SetData(cChannel *Channel)
Sets all source specific parameters to those of the given Channel.
cDvbDevice * bondedDevice
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, int *Frequency) const
Parses the DiSEqC commands and returns the appropriate action code with every call.
cDvbSourceParam(char Source, const char *Description)
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
bool TimedOut(void) const
virtual bool IsMoving(void) const
Returns true if the dish is currently moving as a result of a call to GotoPosition() or GotoAngle()...
static cDvbCiAdapter * CreateCiAdapter(cDevice *Device, int Fd)
#define DTV_STAT_HAS_LOCK
cList< cDvbDeviceProbe > DvbDeviceProbes
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
int dB1000toPercent(int dB1000, int Low, int High)
virtual void CloseDvr(void)
Shuts down the DVR.
#define DVBS_TUNE_TIMEOUT
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
static bool IsSat(int Code)
int DriverIndex(int Value, const tDvbParameterMap *Map)
#define ATSC_LOCK_TIMEOUT
const tDvbParameterMap ModulationValues[]
#define DTV_STAT_VALID_STRENGTH
bool Locked(int TimeoutMs=0)
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
virtual bool OpenDvr(void)
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver...
int GetSignalQuality(void) const
bool Bond(cDvbTuner *Tuner)
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
static void UnBondDevices(void)
Unbonds all devices.
const char * MapToUserString(int Value, const tDvbParameterMap *Map)
static bool useDvbDevices
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
const tDvbParameterMap PilotValues[]
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
int FrontendType(void) const
const cDiseqc * lastDiseqc
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
void Del(cListObject *Object, bool DeleteObject=true)
cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
int FirstDeviceIndex(int DeviceIndex) const
Returns the first device index (starting at 0) that uses the same sat cable number as the device with...
virtual bool ProvidesDeliverySystem(int DeliverySystem) const
const tDvbParameterMap RollOffValues[]
static cDevice * PrimaryDevice(void)
Returns the primary device.
static int setTransferModeForDolbyDigital
const tDvbParameterMap CoderateValues[]
bool Bond(cDvbDevice *Device)
Bonds this device with the given Device, making both of them use the same satellite cable and LNB...
const cPositioner * Positioner(void) const
#define DTV_STAT_HAS_SIGNAL
const cChannel * GetTransponder(void) const
#define DTV_STAT_VALID_BERPRE
virtual bool ProvidesTransponder(const cChannel *Channel) const
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
const cDiseqc * Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
Selects a DiSEqC entry suitable for the given Device and tuning parameters.
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const
Returns true if this device can provide the given channel.
void Sort(bool IgnoreCase=false)
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API...
void SetChannel(const cChannel *Channel)
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise)...
bool GetFrontendStatus(fe_status_t &Status) const
#define DTV_STAT_HAS_NONE
#define DTV_DVBT2_PLP_ID_LEGACY
const tDvbParameterMap SystemValuesTerr[]
#define DTV_STAT_VALID_CNR
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
const tDvbParameterMap BandwidthValues[]
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
Returns true if this device is either not bonded to any other device, or the given Channel is on the ...
Derived cDevice classes that can receive channels will have to provide Transport Stream (TS) packets ...
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
cDvbDevice(int Adapter, int Frontend)
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
cString GetBondingParams(const cChannel *Channel=NULL) const
#define ATSC_TUNE_TIMEOUT
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
cDvbTransponderParameters dtp
static cString DvbName(const char *Name, int Adapter, int Frontend)
static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError=false)
const cDvbDevice * device
const tDvbParameterMap GuardValues[]
virtual void GetData(cChannel *Channel)
Copies all source specific parameters to the given Channel.
const tDvbParameterMap TransmissionValues[]
static void SetTransferModeForDolbyDigital(int Mode)
virtual bool ProvidesEIT(void) const
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...