14 #include <linux/dvb/dmx.h>
15 #include <linux/dvb/frontend.h>
16 #include <sys/ioctl.h>
26 #define DVBS_TUNE_TIMEOUT 9000
27 #define DVBS_LOCK_TIMEOUT 2000
28 #define DVBC_TUNE_TIMEOUT 9000
29 #define DVBC_LOCK_TIMEOUT 2000
30 #define DVBT_TUNE_TIMEOUT 9000
31 #define DVBT_LOCK_TIMEOUT 2000
32 #define ATSC_TUNE_TIMEOUT 9000
33 #define ATSC_LOCK_TIMEOUT 2000
35 #define SCR_RANDOM_TIMEOUT 500
37 #define TSBUFFERSIZE MEGABYTE(16)
42 { 0, PILOT_OFF,
trNOOP(
"off") },
43 { 1, PILOT_ON,
trNOOP(
"on") },
44 { 999, PILOT_AUTO,
trNOOP(
"auto") },
49 { 0, INVERSION_OFF,
trNOOP(
"off") },
50 { 1, INVERSION_ON,
trNOOP(
"on") },
51 { 999, INVERSION_AUTO,
trNOOP(
"auto") },
56 { 5, 5000000,
"5 MHz" },
57 { 6, 6000000,
"6 MHz" },
58 { 7, 7000000,
"7 MHz" },
59 { 8, 8000000,
"8 MHz" },
60 { 10, 10000000,
"10 MHz" },
61 { 1712, 1712000,
"1.712 MHz" },
66 { 0, FEC_NONE,
trNOOP(
"none") },
67 { 12, FEC_1_2,
"1/2" },
68 { 23, FEC_2_3,
"2/3" },
69 { 34, FEC_3_4,
"3/4" },
70 { 35, FEC_3_5,
"3/5" },
71 { 45, FEC_4_5,
"4/5" },
72 { 56, FEC_5_6,
"5/6" },
73 { 67, FEC_6_7,
"6/7" },
74 { 78, FEC_7_8,
"7/8" },
75 { 89, FEC_8_9,
"8/9" },
76 { 910, FEC_9_10,
"9/10" },
77 { 999, FEC_AUTO,
trNOOP(
"auto") },
82 { 16, QAM_16,
"QAM16" },
83 { 32, QAM_32,
"QAM32" },
84 { 64, QAM_64,
"QAM64" },
85 { 128, QAM_128,
"QAM128" },
86 { 256, QAM_256,
"QAM256" },
89 { 6, APSK_16,
"16APSK" },
90 { 7, APSK_32,
"32APSK" },
91 { 10, VSB_8,
"VSB8" },
92 { 11, VSB_16,
"VSB16" },
93 { 12, DQPSK,
"DQPSK" },
94 { 999, QAM_AUTO,
trNOOP(
"auto") },
98 #define DVB_SYSTEM_1 0
99 #define DVB_SYSTEM_2 1
115 { 2, TRANSMISSION_MODE_2K,
"2K" },
117 { 8, TRANSMISSION_MODE_8K,
"8K" },
120 { 999, TRANSMISSION_MODE_AUTO,
trNOOP(
"auto") },
125 { 4, GUARD_INTERVAL_1_4,
"1/4" },
126 { 8, GUARD_INTERVAL_1_8,
"1/8" },
127 { 16, GUARD_INTERVAL_1_16,
"1/16" },
128 { 32, GUARD_INTERVAL_1_32,
"1/32" },
132 { 999, GUARD_INTERVAL_AUTO,
trNOOP(
"auto") },
137 { 0, HIERARCHY_NONE,
trNOOP(
"none") },
138 { 1, HIERARCHY_1,
"1" },
139 { 2, HIERARCHY_2,
"2" },
140 { 4, HIERARCHY_4,
"4" },
141 { 999, HIERARCHY_AUTO,
trNOOP(
"auto") },
146 { 0, ROLLOFF_AUTO,
trNOOP(
"auto") },
147 { 20, ROLLOFF_20,
"0.20" },
148 { 25, ROLLOFF_25,
"0.25" },
149 { 35, ROLLOFF_35,
"0.35" },
180 *String =
tr(Map[n].userString);
211 return Value >= 0 && Value != 999 ? sprintf(p,
"%c%d", Name, Value) : 0;
216 #define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*')))
244 int n = strtol(s, &p, 10);
245 if (!errno && p != s) {
251 esyslog(
"ERROR: invalid value for parameter '%c'", *(s - 1));
265 guard = GUARD_INTERVAL_AUTO;
274 switch (toupper(*s)) {
294 default:
esyslog(
"ERROR: unknown parameter key '%c'", *s);
336 #define MAXFRONTENDCMDS 16
337 #define SETCMD(c, d) { Props[CmdSeq.num].cmd = (c);\
338 Props[CmdSeq.num].u.data = (d);\
339 if (CmdSeq.num++ > MAXFRONTENDCMDS) {\
340 esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\
415 if (Modulation == QPSK && !(
frontendInfo.caps & FE_CAN_QPSK) ||
416 Modulation == QAM_16 && !(
frontendInfo.caps & FE_CAN_QAM_16) ||
417 Modulation == QAM_32 && !(
frontendInfo.caps & FE_CAN_QAM_32) ||
418 Modulation == QAM_64 && !(
frontendInfo.caps & FE_CAN_QAM_64) ||
419 Modulation == QAM_128 && !(
frontendInfo.caps & FE_CAN_QAM_128) ||
420 Modulation == QAM_256 && !(
frontendInfo.caps & FE_CAN_QAM_256) ||
421 Modulation == QAM_AUTO && !(
frontendInfo.caps & FE_CAN_QAM_AUTO) ||
422 Modulation == VSB_8 && !(
frontendInfo.caps & FE_CAN_8VSB) ||
423 Modulation == VSB_16 && !(
frontendInfo.caps & FE_CAN_16VSB) ||
437 dtv_property Props[1];
438 dtv_properties CmdSeq;
441 memset(&Props, 0,
sizeof(Props));
442 memset(&CmdSeq, 0,
sizeof(CmdSeq));
443 CmdSeq.props = Props;
444 SETCMD(DTV_API_VERSION, 0);
445 if (ioctl(
fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
453 bool LegacyMode =
true;
455 memset(&Props, 0,
sizeof(Props));
456 memset(&CmdSeq, 0,
sizeof(CmdSeq));
457 CmdSeq.props = Props;
459 int Result = ioctl(
fd_frontend, FE_GET_PROPERTY, &CmdSeq);
461 for (uint i = 0; i < Props[0].u.buffer.len; i++) {
469 esyslog(
"ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode",
adapter,
frontend);
503 ms =
"unknown modulations";
514 #define TUNER_POLL_TIMEOUT 10
518 int ds = SYS_UNDEFINED;
522 ds = SYS_DVBC_ANNEX_AC;
523 else if (Channel->
IsSat())
525 else if (Channel->
IsTerr())
528 esyslog(
"ERROR: can't determine frontend type for channel %d (%s)", Channel->
Number(), Channel->
Name());
574 virtual void Action(
void);
592 bool Locked(
int TimeoutMs = 0);
594 bool GetSignalStats(
int &Valid,
double *Strength = NULL,
double *Cnr = NULL,
double *BerPre = NULL,
double *BerPost = NULL,
double *Per = NULL,
int *Status = NULL)
const;
631 for (
int i = 1; ; i++) {
731 while (t->bondedTuner !=
this)
734 t->bondedTuner = NULL;
749 return diseqc->Commands();
765 if (t->device->Priority() >
IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
766 if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
812 if (BondedMaster ==
this) {
842 if (isLocked || !TimeoutMs)
855 dvb_frontend_event Event;
856 while (ioctl(
fd_frontend, FE_GET_EVENT, &Event) == 0)
864 Status = (fe_status_t)0;
866 if (ioctl(
fd_frontend, FE_READ_STATUS, &Status) != -1)
878 bool cDvbTuner::GetSignalStats(
int &Valid,
double *Strength,
double *Cnr,
double *BerPre,
double *BerPost,
double *Per,
int *Status)
const
881 fe_status_t FeStatus = (fe_status_t)0;
883 dtv_properties CmdSeq;
884 memset(&Props, 0,
sizeof(Props));
885 memset(&CmdSeq, 0,
sizeof(CmdSeq));
886 CmdSeq.props = Props;
888 if (ioctl(
fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
901 if (Strength)
SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
902 if (Cnr)
SETCMD(DTV_STAT_CNR, 0);
903 if (BerPre) {
SETCMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0);
904 SETCMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0); }
905 if (BerPost) {
SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
906 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0); }
907 if (Per) {
SETCMD(DTV_STAT_ERROR_BLOCK_COUNT, 0);
908 SETCMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0); }
909 if (CmdSeq.num && ioctl(
fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
915 if (Props[i].u.st.len > 0) {
916 switch (Props[i].u.st.stat[0].scale) {
917 case FE_SCALE_DECIBEL: *Strength = double(Props[i].u.st.stat[0].svalue) / 1000;
926 if (Props[i].u.st.len > 0) {
927 switch (Props[i].u.st.stat[0].scale) {
928 case FE_SCALE_DECIBEL: *Cnr = double(Props[i].u.st.stat[0].svalue) / 1000;
937 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
938 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
939 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
940 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
942 *BerPre = double(ebc) / tbc;
950 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
951 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
952 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
953 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
955 *BerPost = double(ebc) / tbc;
963 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
964 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
965 uint64_t ebc = Props[i].u.st.stat[0].uvalue;
966 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue;
968 *Per = double(ebc) / tbc;
975 #ifdef DEBUG_SIGNALSTATS
983 fprintf(stderr,
"\n");
999 double v = 10.0 * (dB1000 - High) / (Low - High);
1003 #define REF_S1(q1) (mod == QPSK) ? q1 : 0
1004 #define REF_S2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == PSK_8) ? q2 : (mod == APSK_16) ? q3 : (mod == APSK_32) ? q4 : 0
1005 #define REF_T1(q1, q2, q3) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : 0
1006 #define REF_T2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_256) ? q4 : 0
1007 #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
1014 int mod = (FeModulation >= 0) ? FeModulation : dtp.
Modulation();
1015 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.
CoderateH();
1016 int fec = (FeFec >= 0) ? FeFec : dtp.
CoderateH();
1023 if (mod == QAM_AUTO) mod = QPSK;
1025 case FEC_1_2: pref =
REF_T1(-93, -87, -82);
break;
1027 case FEC_2_3: pref =
REF_T1(-91, -85, -80);
break;
1028 case FEC_3_4: pref =
REF_T1(-90, -84, -78);
break;
1029 case FEC_5_6: pref =
REF_T1(-89, -83, -77);
break;
1030 case FEC_7_8: pref =
REF_T1(-88, -82, -76);
break;
1034 if (mod == QAM_AUTO) mod = QAM_64;
1036 case FEC_1_2: pref =
REF_T2(-96, -91, -86, -82);
break;
1038 case FEC_3_5: pref =
REF_T2(-95, -89, -85, -80);
break;
1039 case FEC_2_3: pref =
REF_T2(-94, -88, -83, -78);
break;
1040 case FEC_3_4: pref =
REF_T2(-93, -87, -82, -76);
break;
1041 case FEC_4_5: pref =
REF_T2(-92, -86, -81, -75);
break;
1042 case FEC_5_6: pref =
REF_T2(-92, -86, -80, -74);
break;
1046 int prel = (Strength / 1000) - pref;
1047 ssi = (prel < -15) ? 0 :
1048 (prel < 0) ? (prel + 15) * 2 / 3 :
1049 (prel < 20) ? prel * 4 + 10 :
1050 (prel < 35) ? (prel - 20) * 2 / 3 + 90 :
1052 #ifdef DEBUG_SIGNALSTRENGTH
1053 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);
1057 else if (Channel->
IsCable()) {
1062 if (mod == QAM_AUTO) mod = QAM_256;
1064 int pref =
REF_C1(-79, -76, -73, -70, -67);
1066 int prel = (Strength / 1000) - pref;
1067 ssi = (prel < -15) ? 0 :
1068 (prel < 0) ? (prel + 15) * 2 / 3 :
1069 (prel < 20) ? prel * 4 + 10 :
1070 (prel < 35) ? (prel - 20) * 2 / 3 + 90 :
1072 #ifdef DEBUG_SIGNALSTRENGTH
1073 fprintf(stderr,
"SSI-C: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(mod:%d)\n", Strength, pref, prel, ssi, mod);
1077 else if (Channel->
IsSat())
1083 #define IGNORE_BER 1
1084 #define BER_ERROR_FREE (1000*1000*1000)
1094 int mod = (FeModulation >= 0) ? FeModulation : dtp.
Modulation();
1095 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.
CoderateH();
1096 int fec = (FeFec >= 0) ? FeFec : dtp.
CoderateH();
1103 if (mod == QAM_AUTO) mod = QPSK;
1105 case FEC_1_2: cnref =
REF_T1(51, 108, 165);
break;
1107 case FEC_2_3: cnref =
REF_T1(69, 131, 187);
break;
1108 case FEC_3_4: cnref =
REF_T1(79, 146, 202);
break;
1109 case FEC_5_6: cnref =
REF_T1(89, 156, 216);
break;
1110 case FEC_7_8: cnref =
REF_T1(97, 160, 225);
break;
1114 if (mod == QAM_AUTO) mod = QAM_64;
1116 case FEC_1_2: cnref =
REF_T2(35, 87, 130, 170);
break;
1118 case FEC_3_5: cnref =
REF_T2(47, 101, 148, 194);
break;
1119 case FEC_2_3: cnref =
REF_T2(56, 114, 162, 208);
break;
1120 case FEC_3_4: cnref =
REF_T2(66, 125, 177, 229);
break;
1121 case FEC_4_5: cnref =
REF_T2(72, 133, 187, 243);
break;
1122 case FEC_5_6: cnref =
REF_T2(77, 138, 194, 251);
break;
1126 int cnrel = (Signal/100) - cnref;
1130 ber_sqi = (Ber < 1000) ? 0 :
1131 (Ber >= 10000000) ? 100 :
1132 (int)(20 * log10(Ber)) - 40;
1134 cnr_sqi = (cnrel < -70) ? 0 :
1135 (cnrel < +30) ? (100 + (cnrel - 30)) :
1137 sqi = (cnr_sqi * ber_sqi) / 100;
1142 ber_sqi = (Ber < 10000) ? 0 :
1143 (Ber >= 10000000) ? 100 * 100 / 6 :
1146 sqi = (cnrel < -30) ? 0 :
1147 (cnrel <= +30) ? (cnrel + 30) * ber_sqi / 1000 :
1152 #ifdef DEBUG_SIGNALQUALITY
1153 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);
1157 else if (Channel->
IsCable()) {
1158 if (mod == QAM_AUTO) mod = QAM_256;
1160 int cnref =
REF_C1(200, 230, 260, 290, 320);
1162 int cnrel = (Signal / 100) - cnref;
1163 int ber_sqi = (Ber < 1000) ? 0 :
1164 (Ber >= 10000000) ? 100 :
1165 (int)(20 * log10(Ber)) - 40;
1167 int cnr_sqi = (cnrel < -70) ? 0 :
1168 (cnrel < +30) ? (100 + (cnrel - 30)) :
1170 sqi = (cnr_sqi * ber_sqi) / 100;
1173 #ifdef DEBUG_SIGNALQUALITY
1174 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);
1178 else if (Channel->
IsSat()) {
1181 if (mod == QAM_AUTO) mod = QPSK;
1183 case FEC_1_2: cnref =
REF_S1(38);
break;
1185 case FEC_2_3: cnref =
REF_S1(56);
break;
1186 case FEC_3_4: cnref =
REF_S1(67);
break;
1187 case FEC_5_6: cnref =
REF_S1(77);
break;
1188 case FEC_7_8: cnref =
REF_S1(84);
break;
1194 #ifdef DEBUG_SIGNALQUALITY
1195 dsyslog(
"SQI-S1: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
1200 if (mod == QAM_AUTO) mod = QAM_64;
1204 case FEC_2_5: cnref =
REF_S2( 7, 65, 90, 126);
break;
1205 case FEC_1_2: cnref =
REF_S2( 20, 65, 90, 126);
break;
1206 case FEC_3_5: cnref =
REF_S2( 32, 65, 90, 126);
break;
1208 case FEC_2_3: cnref =
REF_S2( 41, 76, 90, 126);
break;
1209 case FEC_3_4: cnref =
REF_S2( 50, 66, 102, 126);
break;
1210 case FEC_4_5: cnref =
REF_S2( 57, 89, 110, 136);
break;
1211 case FEC_5_6: cnref =
REF_S2( 62, 104, 116, 143);
break;
1212 case FEC_8_9: cnref =
REF_S2( 72, 117, 129, 157);
break;
1213 case FEC_9_10: cnref =
REF_S2( 74, 120, 131, 161);
break;
1219 #ifdef DEBUG_SIGNALQUALITY
1220 dsyslog(
"SQI-S2: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
1232 for (
int i = 0; i < 1; i++) {
1234 dtv_properties CmdSeq;
1235 memset(&Props, 0,
sizeof(Props));
1236 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1237 CmdSeq.props = Props;
1238 SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
1239 SETCMD(DTV_MODULATION, 0);
1240 SETCMD(DTV_CODE_RATE_HP, 0);
1241 SETCMD(DTV_INNER_FEC, 0);
1242 if (ioctl(
fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1246 int FeMod = (Props[1].u.st.len > 0) ? (
int)Props[1].u.data : -1;
1247 int FeCod = (Props[2].u.st.len > 0) ? (
int)Props[2].u.data : -1;
1248 int FeFec = (Props[3].u.st.len > 0) ? (
int)Props[3].u.data : -1;
1250 if (Props[0].u.st.len > 0) {
1251 switch (Props[0].u.st.stat[0].scale) {
1252 case FE_SCALE_DECIBEL: Signal =
StrengthToSSI(&
channel, Props[0].u.st.stat[0].svalue, FeMod, FeCod, FeFec);
1254 case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1258 #ifdef DEBUG_SIGNALSTRENGTH
1259 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);
1269 if (ioctl(
fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
1274 uint16_t MaxSignal = 0xFFFF;
1280 MaxSignal = 670;
break;
1282 int s = int(Signal) * 100 / MaxSignal;
1285 #ifdef DEBUG_SIGNALSTRENGTH
1291 #define LOCK_THRESHOLD 5
1296 for (
int i = 0; i < 1; i++) {
1298 dtv_properties CmdSeq;
1299 memset(&Props, 0,
sizeof(Props));
1300 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1301 CmdSeq.props = Props;
1303 SETCMD(DTV_MODULATION, 0);
1304 SETCMD(DTV_CODE_RATE_HP, 0);
1305 SETCMD(DTV_INNER_FEC, 0);
1306 SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
1307 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
1308 if (ioctl(
fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1312 int FeMod = (Props[1].u.st.len > 0) ? (
int)Props[1].u.data : -1;
1313 int FeCod = (Props[2].u.st.len > 0) ? (
int)Props[2].u.data : -1;
1314 int FeFec = (Props[3].u.st.len > 0) ? (
int)Props[3].u.data : -1;
1316 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) {
1317 uint64_t ebc = Props[4].u.st.stat[0].uvalue;
1318 uint64_t tbc = Props[5].u.st.stat[0].uvalue;
1320 uint64_t BerRev = tbc / ebc;
1326 if (Props[0].u.st.len > 0) {
1327 switch (Props[0].u.st.stat[0].scale) {
1328 case FE_SCALE_DECIBEL: Cnr =
SignalToSQI(&
channel, Props[0].u.st.stat[0].svalue, Ber, FeMod, FeCod, FeFec);
1330 case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1334 #ifdef DEBUG_SIGNALQUALITY
1335 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);
1346 if ((Status & FE_HAS_LOCK) == 0) {
1347 if ((Status & FE_HAS_SIGNAL) == 0)
1349 if ((Status & FE_HAS_CARRIER) == 0)
1351 if ((Status & FE_HAS_VITERBI) == 0)
1353 if ((Status & FE_HAS_SYNC) == 0)
1357 #ifdef DEBUG_SIGNALQUALITY
1364 if (errno != EINTR) {
1366 #ifdef DEBUG_SIGNALQUALITY
1372 #ifdef DEBUG_SIGNALQUALITY
1379 if (errno != EINTR) {
1381 #ifdef DEBUG_SIGNALQUALITY
1387 #ifdef DEBUG_SIGNALQUALITY
1392 if (ioctl(
fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1) {
1394 #ifdef DEBUG_SIGNALQUALITY
1415 Unc >>=
min(t,
int(
sizeof(Unc) * 8 - 1));
1418 #ifdef DEBUG_SIGNALQUALITY
1424 if (errno != EINTR) {
1426 #ifdef DEBUG_SIGNALQUALITY
1432 uint16_t MinSnr = 0x0000;
1433 uint16_t MaxSnr = 0xFFFF;
1448 MaxSnr = 255;
break;
1450 int a = int(
constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
1451 int b = 100 - (Unc * 10 + (Ber / 256) * 5);
1457 #ifdef DEBUG_SIGNALQUALITY
1458 fprintf(stderr,
"FE %d/%d: API3 %08X Q = %04X %04X %d %5d %5d %3d%%\n",
adapter,
frontend,
dvbFrontend->
SubsystemId(), MaxSnr, Snr, HasSnr, HasBer ?
int(Ber) : -1, HasUnc ?
int(Unc) : -1, q);
1467 while (f && f < 1000000)
1488 if (Diseqc->
IsScr())
1490 struct dvb_diseqc_master_cmd cmd;
1491 const char *CurrentAction = NULL;
1494 for (
int i = 0; !Break; i++) {
1495 cmd.msg_len =
sizeof(cmd.msg);
1526 default:
esyslog(
"ERROR: unknown diseqc command %d", da);
1534 if (Diseqc->
IsScr())
1547 memset(&Props, 0,
sizeof(Props));
1548 dtv_properties CmdSeq;
1549 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1550 CmdSeq.props = Props;
1552 if (ioctl(
fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1570 frequency -= diseqc->Lof();
1589 int tone = SEC_TONE_OFF;
1592 tone = SEC_TONE_OFF;
1600 tone = SEC_TONE_OFF;
1601 volt = SEC_VOLTAGE_13;
1606 frequency = abs(frequency);
1609 SETCMD(DTV_FREQUENCY, frequency * 1000UL);
1623 SETCMD(DTV_ROLLOFF, ROLLOFF_35);
1673 esyslog(
"ERROR: attempt to set channel with unknown DVB frontend type");
1677 if (ioctl(
fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1687 bool LostLock =
false;
1688 fe_status_t Status = (fe_status_t)0;
1690 int WaitTime = 1000;
1691 fe_status_t NewStatus;
1732 if (Status & FE_REINIT) {
1740 else if (Status & FE_HAS_LOCK) {
1810 #define ST(s) if (strchr(s, type))
1828 default:
return NULL;
1882 int DvbOpen(
const char *Name,
int Adapter,
int Frontend,
int Mode,
bool ReportError)
1885 int fd = open(FileName, Mode);
1886 if (fd < 0 && ReportError)
1899 if (access(FileName, F_OK) == 0) {
1900 int f = open(FileName, O_RDONLY);
1905 else if (errno != ENODEV && errno != EINVAL)
1908 else if (errno != ENOENT)
1916 dsyslog(
"probing %s", *FileName);
1921 dsyslog(
"creating cDvbDevice");
1950 while ((a = DvbDir.
Next()) != NULL) {
1954 if (AdapterDir.
Ok()) {
1956 while ((f = AdapterDir.
Next()) != NULL) {
1971 if (Nodes.
Size() > 0) {
1973 for (
int i = 0; i < Nodes.
Size(); i++) {
1994 isyslog(
"found %d DVB device%s", Found, Found > 1 ?
"s" :
"");
1996 isyslog(
"using only %d DVB device%s", Used, Used != 1 ?
"s" :
"");
1999 isyslog(
"no DVB device found");
2011 int ErrorDevice = 0;
2016 if (!DvbDevice1->Bond(DvbDevice2))
2020 ErrorDevice = d + 1;
2023 ErrorDevice = i + 1;
2025 esyslog(
"ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
2030 ErrorDevice = d + 1;
2033 ErrorDevice = i + 1;
2035 esyslog(
"ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
2056 if (Device !=
this) {
2083 while (d->bondedDevice !=
this)
2084 d = d->bondedDevice;
2086 d->bondedDevice = NULL;
2109 dmx_pes_filter_params pesFilterParams;
2110 memset(&pesFilterParams, 0,
sizeof(pesFilterParams));
2112 if (Handle->
handle < 0) {
2114 if (Handle->
handle < 0) {
2119 pesFilterParams.pid = Handle->
pid;
2120 pesFilterParams.input = DMX_IN_FRONTEND;
2121 pesFilterParams.output = DMX_OUT_TS_TAP;
2122 pesFilterParams.pes_type= DMX_PES_OTHER;
2123 pesFilterParams.flags = DMX_IMMEDIATE_START;
2124 if (ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
2129 else if (!Handle->
used) {
2132 pesFilterParams.pid = 0x1FFF;
2133 pesFilterParams.input = DMX_IN_FRONTEND;
2134 pesFilterParams.output = DMX_OUT_DECODER;
2135 pesFilterParams.pes_type= DMX_PES_OTHER;
2136 pesFilterParams.flags = DMX_IMMEDIATE_START;
2137 CHECK(ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams));
2146 #define RB_NUM_SECTIONS 8
2151 int f = open(FileName, O_RDWR | O_NONBLOCK);
2155 dsyslog(
"OpenFilter (pid=%d, tid=%02X): ioctl DMX_SET_BUFFER_SIZE failed", Pid, Tid);
2157 dmx_sct_filter_params sctFilterParams;
2158 memset(&sctFilterParams, 0,
sizeof(sctFilterParams));
2159 sctFilterParams.pid = Pid;
2160 sctFilterParams.timeout = 0;
2161 sctFilterParams.flags = DMX_IMMEDIATE_START;
2162 sctFilterParams.filter.filter[0] = Tid;
2163 sctFilterParams.filter.mask[0] = Mask;
2164 if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
2167 esyslog(
"ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
2172 esyslog(
"ERROR: can't open filter handle on '%s'", *FileName);
2211 bool result =
false;
2213 bool needsDetachReceivers =
false;
2217 result = hasPriority;
2223 if (
CamSlot()->CanDecrypt(Channel))
2226 needsDetachReceivers =
true;
2246 needsDetachReceivers |= d->Receiving();
2254 if (NeedsDetachReceivers)
2255 *NeedsDetachReceivers = needsDetachReceivers;
2274 bool cDvbDevice::SignalStats(
int &Valid,
double *Strength,
double *Cnr,
double *BerPre,
double *BerPost,
double *Per,
int *Status)
const
2346 if (cs->WantsTsData()) {
2351 Data = cs->Decrypt(Data, Available);
2368 d->cDevice::DetachAllReceivers();
2390 uint32_t SubsystemId = 0;
2393 if (stat(FileName, &st) == 0) {
2397 while ((e = d.
Next()) != NULL) {
2398 if (strstr(e->d_name,
"frontend")) {
2400 if (FILE *f = fopen(FileName,
"r")) {
2402 char *s = ReadLine.
Read(f);
2406 if (s && 2 == sscanf(s,
"%u:%u", &Major, &Minor)) {
2407 if (((Major << 8) | Minor) == st.st_rdev) {
2408 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
2409 if ((f = fopen(FileName,
"r")) != NULL) {
2410 if (
char *s = ReadLine.
Read(f))
2411 SubsystemId = strtoul(s, NULL, 0) << 16;
2415 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idVendor", e->d_name);
2416 if ((f = fopen(FileName,
"r")) != NULL) {
2417 if (
char *s = ReadLine.
Read(f))
2418 SubsystemId = strtoul(s, NULL, 16) << 16;
2422 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_device", e->d_name);
2423 if ((f = fopen(FileName,
"r")) != NULL) {
2424 if (
char *s = ReadLine.
Read(f))
2425 SubsystemId |= strtoul(s, NULL, 0);
2429 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idProduct", e->d_name);
2430 if ((f = fopen(FileName,
"r")) != NULL) {
2431 if (
char *s = ReadLine.
Read(f))
2432 SubsystemId |= strtoul(s, NULL, 16);
const char * Name(void) const
int Ca(int Index=0) const
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
const char * Parameters(void) const
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
bool TimedWait(cMutex &Mutex, int TimeoutMs)
static int NextCardIndex(int n=0)
Calculates the next card index.
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
static bool UseDevice(int n)
Tells whether the device with the given card index shall be used in this instance of VDR.
bool IsPrimaryDevice(void) const
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
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...
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
bool DeviceHooksProvidesEIT(void) const
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
cSectionHandler * SectionHandler(void) const
static int NumDevices(void)
Returns the total number of devices.
int Priority(void) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
static cDevice * PrimaryDevice(void)
Returns the primary device.
const cSdtFilter * SdtFilter(void) const
void DelLivePids(void)
Deletes the live viewing PIDs.
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
cCamSlot * CamSlot(void) const
Returns the CAM slot that is currently used with this device, or NULL if no CAM slot is in use.
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.
int Position(void) const
Indicates which positioning mode to use in order to move the dish to a given satellite position.
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
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.
static cDvbCiAdapter * CreateCiAdapter(cDevice *Device, int Fd)
static uint32_t GetSubsystemId(int Adapter, int Frontend)
virtual ~cDvbDeviceProbe()
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
static void UnBondDevices(void)
Unbonds all devices.
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
static void SetTransferModeForDolbyDigital(int Mode)
cDvbDevice(int Adapter, int Frontend)
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
static bool Exists(int Adapter, int Frontend)
Checks whether the given adapter/frontend exists.
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
static bool useDvbDevices
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
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...
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...
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...
virtual bool OpenDvr(void)
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver.
virtual void CloseDvr(void)
Shuts down the DVR.
static bool Initialize(void)
Initializes the DVB devices.
void UnBond(void)
Removes this device from any bonding it might have with other devices.
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
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 ...
cTSBuffer * tsBuffer
< Controls how the DVB device handles Transfer Mode when replaying Dolby Digital audio.
bool needsDetachBondedReceivers
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).
static int setTransferModeForDolbyDigital
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
virtual bool GetTSPacket(uchar *&Data)
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data.
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
bool Bond(cDvbDevice *Device)
Bonds this device with the given Device, making both of them use the same satellite cable and LNB.
virtual bool ProvidesDeliverySystem(int DeliverySystem) const
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const
Returns true if this device can provide the given channel.
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
cDvbDevice * bondedDevice
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
static bool Probe(int Adapter, int Frontend)
Probes for existing DVB devices.
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...
const char * FrontendName(void)
bool ProvidesModulation(int System, int StreamId, int Modulation) const
uint32_t SubsystemId(void) const
int NumDeliverySystems(void) const
cDvbFrontend(int Adapter, int Frontend)
int NumModulations(void) const
bool ProvidesDeliverySystem(int DeliverySystem) const
cVector< int > deliverySystems
bool QueryDeliverySystems(void)
dvb_frontend_info frontendInfo
cDvbSourceParam(char Source, const char *Description)
cDvbTransponderParameters dtp
virtual void SetData(cChannel *Channel)
Sets all source specific parameters to those of the given Channel.
virtual cOsdItem * GetOsdItem(void)
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
virtual void GetData(cChannel *Channel)
Copies all source specific parameters to the given Channel.
cString ToString(char Type) const
const char * ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map=NULL)
char Polarization(void) const
bool Parse(const char *s)
int PrintParameter(char *p, char Name, int Value) const
int CoderateL(void) const
int Transmission(void) const
int Bandwidth(void) const
int Inversion(void) const
cDvbTransponderParameters(const char *Parameters=NULL)
int Modulation(void) const
int Hierarchy(void) const
int CoderateH(void) const
void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
bool Bond(cDvbTuner *Tuner)
void ClearEventQueue(void) const
int NumProvidedSystems(void) const
void SetChannel(const cChannel *Channel)
cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend)
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
const cPositioner * Positioner(void) const
void ResetToneAndVoltage(void)
cPositioner * GetPositioner(void)
cString GetBondingParams(const cChannel *Channel=NULL) const
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
bool Locked(int TimeoutMs=0)
int GetSignalQuality(void) const
bool ProvidesModulation(int System, int StreamId, int Modulation) const
cVector< cDvbFrontend * > dvbFrontends
const cChannel * GetTransponder(void) const
bool IsBondedMaster(void) const
cDvbTuner * GetBondedMaster(void)
uint32_t SubsystemId(void) const
bool GetSignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
const char * FrontendName(void)
bool SetFrontendType(const cChannel *Channel)
bool ProvidesFrontend(const cChannel *Channel, bool Activate=false) const
int FrontendType(void) const
bool IsTunedTo(const cChannel *Channel) const
cDvbFrontend * dvbFrontend
const cDiseqc * lastDiseqc
const cDvbDevice * device
int GetSignalStrength(void) const
bool ProvidesDeliverySystem(int DeliverySystem) const
bool GetFrontendStatus(fe_status_t &Status) const
bool Poll(int TimeoutMs=0)
A steerable satellite dish generally points to the south on the northern hemisphere,...
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
void SetFrontend(int Frontend)
This function is called whenever the positioner is connected to a DVB frontend.
virtual bool IsMoving(void) const
Returns true if the dish is currently moving as a result of a call to GotoPosition() or GotoAngle().
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
virtual void GotoAngle(int Longitude)
Move the dish to the given angular position.
struct dirent * Next(void)
int FirstDeviceIndex(int DeviceIndex) const
Returns the first device index (starting at 0) that uses the same sat cable number as the device with...
bool TransponderWrong(void) const
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise).
static bool IsSat(int Code)
void Sort(bool IgnoreCase=false)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Derived cDevice classes that can receive channels will have to provide Transport Stream (TS) packets ...
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
void Skip(int Count)
If after a call to Get() more or less than TS_SIZE of the available data has been processed,...
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
void SetDescription(const char *Description,...) __attribute__((format(printf
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
void Set(int Ms=0)
Sets the timer.
bool TimedOut(void) const
virtual void Append(T Data)
#define DTV_STAT_HAS_NONE
#define DTV_STAT_HAS_VITERBI
#define DTV_STAT_VALID_STRENGTH
#define DTV_STAT_VALID_BERPRE
#define DTV_STAT_VALID_NONE
The cDevice class is the base from which actual devices can be derived.
#define DTV_STAT_VALID_PER
#define DTV_STAT_HAS_CARRIER
#define DTV_STAT_VALID_CNR
#define DTV_STAT_HAS_LOCK
#define DTV_STAT_VALID_BERPOST
#define DTV_STAT_HAS_SYNC
#define DTV_STAT_HAS_SIGNAL
#define DTV_STAT_VALID_STATUS
int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
static const int DeliverySystemNamesMax
const tDvbParameterMap CoderateValues[]
int dB1000toPercent(int dB1000, int Low, int High)
const tDvbParameterMap PilotValues[]
int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
#define REF_T2(q1, q2, q3, q4)
const tDvbParameterMap GuardValues[]
#define DVBC_LOCK_TIMEOUT
const char * MapToUserString(int Value, const tDvbParameterMap *Map)
const tDvbParameterMap SystemValuesSat[]
const tDvbParameterMap HierarchyValues[]
#define DVBC_TUNE_TIMEOUT
int DriverIndex(int Value, const tDvbParameterMap *Map)
#define REF_C1(q1, q2, q3, q4, q5)
cString DvbName(const char *Name, int Adapter, int Frontend)
#define SCR_RANDOM_TIMEOUT
#define REF_S2(q1, q2, q3, q4)
const tDvbParameterMap BandwidthValues[]
#define TUNER_POLL_TIMEOUT
cList< cDvbDeviceProbe > DvbDeviceProbes
const tDvbParameterMap TransmissionValues[]
const tDvbParameterMap InversionValues[]
static unsigned int FrequencyToHz(unsigned int f)
#define ATSC_TUNE_TIMEOUT
const tDvbParameterMap RollOffValues[]
const tDvbParameterMap ModulationValues[]
const tDvbParameterMap SystemValuesTerr[]
static const char * GetDeliverySystemName(int Index)
#define DVBT_TUNE_TIMEOUT
int UserIndex(int Value, const tDvbParameterMap *Map)
#define REF_T1(q1, q2, q3)
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
#define ATSC_LOCK_TIMEOUT
#define DVBS_LOCK_TIMEOUT
const char * DeliverySystemNames[]
int MapToDriver(int Value, const tDvbParameterMap *Map)
#define DVBS_TUNE_TIMEOUT
#define DVBT_LOCK_TIMEOUT
#define DTV_DVBT2_PLP_ID_LEGACY