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);
212 guard = GUARD_INTERVAL_AUTO;
225 return Value >= 0 && Value != 999 ? sprintf(p,
"%c%d", Name, Value) : 0;
230 #define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*'))) 258 int n = strtol(s, &p, 10);
259 if (!errno && p != s) {
265 esyslog(
"ERROR: invalid value for parameter '%c'", *(s - 1));
272 switch (toupper(*s)) {
292 default:
esyslog(
"ERROR: unknown parameter key '%c'", *s);
301 #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,
unsigned 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 int GetSignalStrength(
void)
const;
353 int GetSignalQuality(
void)
const;
360 frontendType = SYS_UNDEFINED;
362 fd_frontend = Fd_Frontend;
368 lastTimeoutReport = 0;
374 lnbPowerTurnedOn =
false;
375 tunerStatus = tsIdle;
377 bondedMaster =
false;
378 SetDescription(
"frontend %d/%d tuner", adapter, frontend);
384 tunerStatus = tsIdle;
401 ResetToneAndVoltage();
402 bondedMaster =
false;
405 dsyslog(
"tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
409 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);
417 dsyslog(
"tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
418 while (t->bondedTuner !=
this)
420 if (t == bondedTuner)
421 t->bondedTuner = NULL;
423 t->bondedTuner = bondedTuner;
424 bondedMaster =
false;
436 return diseqc->Commands();
440 bool VoltOff = dtp.Polarization() ==
'V' || dtp.Polarization() ==
'R';
450 cString BondingParams = GetBondingParams(Channel);
452 if (t->device->Priority() >
IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
453 if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
457 }
while (t != bondedTuner);
479 dsyslog(
"tuner %d/%d is now bonded master", adapter, frontend);
485 if (tunerStatus == tsIdle)
487 if (channel.Source() != Channel->
Source() || channel.Transponder() != Channel->
Transponder())
490 return strcmp(channel.Parameters(), Channel->
Parameters()) == 0;
498 cDvbTuner *BondedMaster = GetBondedMaster();
499 if (BondedMaster ==
this) {
500 if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
506 else if (strcmp(GetBondingParams(Channel), BondedMaster->
GetBondingParams()) != 0)
510 if (!IsTunedTo(Channel))
514 lastTimeoutReport = 0;
519 tunerStatus = tsIdle;
520 ResetToneAndVoltage();
522 if (bondedTuner && device->IsPrimaryDevice())
528 bool isLocked = (tunerStatus >= tsLocked);
529 if (isLocked || !TimeoutMs)
533 if (TimeoutMs && tunerStatus < tsLocked)
534 locked.TimedWait(mutex, TimeoutMs);
535 return tunerStatus >= tsLocked;
542 dvb_frontend_event Event;
543 while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
552 if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
568 if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
573 uint16_t MaxSignal = 0xFFFF;
576 switch (subsystemId) {
579 MaxSignal = 670;
break;
581 int s = int(Signal) * 100 / MaxSignal;
584 #ifdef DEBUG_SIGNALSTRENGTH 585 fprintf(stderr,
"FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
590 #define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set 595 if (GetFrontendStatus(Status)) {
597 if ((Status & FE_HAS_LOCK) == 0) {
598 if ((Status & FE_HAS_SIGNAL) == 0)
600 if ((Status & FE_HAS_CARRIER) == 0)
602 if ((Status & FE_HAS_VITERBI) == 0)
604 if ((Status & FE_HAS_SYNC) == 0)
608 #ifdef DEBUG_SIGNALQUALITY 613 if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
615 if (errno != EINTR) {
617 #ifdef DEBUG_SIGNALQUALITY 623 #ifdef DEBUG_SIGNALQUALITY 628 if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
630 if (errno != EINTR) {
632 #ifdef DEBUG_SIGNALQUALITY 638 #ifdef DEBUG_SIGNALQUALITY 643 if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
645 if (errno != EINTR) {
647 #ifdef DEBUG_SIGNALQUALITY 653 uint16_t MinSnr = 0x0000;
654 uint16_t MaxSnr = 0xFFFF;
657 switch (subsystemId) {
660 if (frontendType == SYS_DVBS2) {
671 int a = int(
constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
672 int b = 100 - (Unc * 10 + (Ber / 256) * 5);
678 #ifdef DEBUG_SIGNALQUALITY 679 fprintf(stderr,
"FE %d/%d: %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ?
int(Ber) : -1, HasUnc ?
int(Unc) : -1, q);
688 while (f && f < 1000000)
697 positioner->SetFrontend(fd_frontend);
704 if (!lnbPowerTurnedOn) {
705 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13));
706 lnbPowerTurnedOn =
true;
711 struct dvb_diseqc_master_cmd cmd;
712 const char *CurrentAction = NULL;
715 for (
int i = 0; !Break; i++) {
716 cmd.msg_len =
sizeof(cmd.msg);
722 bool d = i >= diseqcOffset;
747 default:
esyslog(
"ERROR: unknown diseqc command %d", da);
750 diseqcOffset = i + 1;
752 positioner = Positioner;
754 ResetToneAndVoltage();
761 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
762 CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
767 int ds = SYS_UNDEFINED;
771 ds = SYS_DVBC_ANNEX_AC;
772 else if (Channel->
IsSat())
774 else if (Channel->
IsTerr())
777 esyslog(
"ERROR: can't determine frontend type for channel %d (%s)", Channel->
Number(), Channel->
Name());
783 #define MAXFRONTENDCMDS 16 784 #define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\ 785 Frontend[CmdSeq.num].u.data = (d);\ 786 if (CmdSeq.num++ > MAXFRONTENDCMDS) {\ 787 esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\ 792 memset(&Frontend, 0,
sizeof(Frontend));
793 dtv_properties CmdSeq;
794 memset(&CmdSeq, 0,
sizeof(CmdSeq));
795 CmdSeq.props = Frontend;
797 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
798 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
807 if (frontendType == SYS_UNDEFINED)
810 SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
811 if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
812 unsigned int frequency = channel.Frequency();
814 if (
const cDiseqc *diseqc =
Diseqcs.
Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
815 frequency -= diseqc->Lof();
816 if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
817 if (IsBondedMaster()) {
818 ExecuteDiseqc(diseqc, &frequency);
823 ResetToneAndVoltage();
825 lastSource = channel.Source();
829 esyslog(
"ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
834 int tone = SEC_TONE_OFF;
843 int volt = (dtp.Polarization() ==
'V' || dtp.Polarization() ==
'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
844 if (!IsBondedMaster()) {
846 volt = SEC_VOLTAGE_13;
848 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
849 CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
851 frequency = abs(frequency);
854 SETCMD(DTV_FREQUENCY, frequency * 1000UL);
855 SETCMD(DTV_MODULATION, dtp.Modulation());
856 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
857 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
858 SETCMD(DTV_INVERSION, dtp.Inversion());
859 if (frontendType == SYS_DVBS2) {
861 SETCMD(DTV_PILOT, dtp.Pilot());
862 SETCMD(DTV_ROLLOFF, dtp.RollOff());
868 SETCMD(DTV_ROLLOFF, ROLLOFF_35);
874 else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
877 SETCMD(DTV_INVERSION, dtp.Inversion());
878 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
879 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
880 SETCMD(DTV_MODULATION, dtp.Modulation());
885 else if (frontendType == SYS_DVBT || frontendType ==
SYS_DVBT2) {
888 SETCMD(DTV_INVERSION, dtp.Inversion());
889 SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
890 SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
891 SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
892 SETCMD(DTV_MODULATION, dtp.Modulation());
893 SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
894 SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
895 SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
908 else if (frontendType == SYS_ATSC) {
911 SETCMD(DTV_INVERSION, dtp.Inversion());
912 SETCMD(DTV_MODULATION, dtp.Modulation());
918 esyslog(
"ERROR: attempt to set channel with unknown DVB frontend type");
922 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
923 esyslog(
"ERROR: frontend %d/%d: %m", adapter, frontend);
932 bool LostLock =
false;
933 fe_status_t Status = (fe_status_t)0;
935 fe_status_t NewStatus;
936 if (GetFrontendStatus(NewStatus))
940 switch (tunerStatus) {
944 tunerStatus = SetFrontend() ? tsPositioning : tsIdle;
948 if (positioner->IsMoving())
950 else if (diseqcOffset) {
956 tunerStatus = tsTuned;
966 if (time(NULL) - lastTimeoutReport > 60) {
967 isyslog(
"frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
968 lastTimeoutReport = time(NULL);
975 if (Status & FE_REINIT) {
979 isyslog(
"frontend %d/%d was reinitialized", adapter, frontend);
980 lastTimeoutReport = 0;
983 else if (Status & FE_HAS_LOCK) {
985 isyslog(
"frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
988 tunerStatus = tsLocked;
990 lastTimeoutReport = 0;
992 else if (tunerStatus == tsLocked) {
994 isyslog(
"frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
995 tunerStatus = tsTuned;
996 Timer.
Set(lockTimeout);
997 lastTimeoutReport = 0;
1001 default:
esyslog(
"ERROR: unknown tuner status %d", tunerStatus);
1003 newSet.TimedWait(mutex, WaitTime);
1016 virtual void SetData(
cChannel *Channel);
1017 virtual void GetData(
cChannel *Channel);
1018 virtual cOsdItem *GetOsdItem(
void);
1045 #define ST(s) if (strchr(s, type)) 1063 default:
return NULL;
1098 frontend = Frontend;
1101 numDeliverySystems = 0;
1103 bondedDevice = NULL;
1104 needsDetachBondedReceivers =
false;
1109 int fd_frontend = DvbOpen(
DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
1113 fd_ca = DvbOpen(
DEV_DVB_CA, adapter, frontend, O_RDWR);
1123 if (fd_frontend >= 0) {
1124 if (QueryDeliverySystems(fd_frontend))
1125 dvbTuner =
new cDvbTuner(
this, fd_frontend, adapter, frontend);
1128 esyslog(
"ERROR: can't open DVB device %d/%d", adapter, frontend);
1130 StartSectionHandler();
1135 StopSectionHandler();
1150 cString FileName = DvbName(Name, Adapter, Frontend);
1151 int fd = open(FileName, Mode);
1152 if (fd < 0 && ReportError)
1160 if (access(FileName, F_OK) == 0) {
1161 int f = open(FileName, O_RDONLY);
1166 else if (errno != ENODEV && errno != EINVAL)
1169 else if (errno != ENOENT)
1177 dsyslog(
"probing %s", *FileName);
1179 if (dp->Probe(Adapter, Frontend))
1182 dsyslog(
"creating cDvbDevice");
1190 if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1192 if (numDeliverySystems)
1200 return frontendInfo.name;
1213 while ((a = DvbDir.
Next()) != NULL) {
1217 if (AdapterDir.
Ok()) {
1219 while ((f = AdapterDir.
Next()) != NULL) {
1231 if (Nodes.
Size() > 0) {
1233 for (
int i = 0; i < Nodes.
Size(); i++) {
1236 if (2 == sscanf(Nodes[i],
"%d %d", &Adapter, &Frontend)) {
1237 if (Exists(Adapter, Frontend)) {
1240 if (UseDevice(NextCardIndex())) {
1241 if (Probe(Adapter, Frontend))
1252 isyslog(
"found %d DVB device%s", Found, Found > 1 ?
"s" :
"");
1254 isyslog(
"using only %d DVB device%s", Used, Used > 1 ?
"s" :
"");
1257 isyslog(
"no DVB device found");
1263 numDeliverySystems = 0;
1264 if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
1268 dtv_property Frontend[1];
1269 dtv_properties CmdSeq;
1272 memset(&Frontend, 0,
sizeof(Frontend));
1273 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1274 CmdSeq.props = Frontend;
1275 SETCMD(DTV_API_VERSION, 0);
1276 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1284 bool LegacyMode =
true;
1286 memset(&Frontend, 0,
sizeof(Frontend));
1287 memset(&CmdSeq, 0,
sizeof(CmdSeq));
1288 CmdSeq.props = Frontend;
1290 int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
1292 for (uint i = 0; i < Frontend[0].u.buffer.len; i++) {
1294 esyslog(
"ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
1297 deliverySystems[numDeliverySystems++] = Frontend[0].u.buffer.data[i];
1302 esyslog(
"ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
1307 switch (frontendInfo.type) {
1308 case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1310 deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1312 case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1314 deliverySystems[numDeliverySystems++] =
SYS_DVBT2;
1316 case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC;
break;
1317 case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC;
break;
1318 default:
esyslog(
"ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
1321 if (numDeliverySystems > 0) {
1323 for (
int i = 0; i < numDeliverySystems; i++)
1326 if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QPSK, ModulationValues)); }
1327 if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_16, ModulationValues)); }
1328 if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_32, ModulationValues)); }
1329 if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_64, ModulationValues)); }
1330 if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_128, ModulationValues)); }
1331 if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(QAM_256, ModulationValues)); }
1332 if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(VSB_8, ModulationValues)); }
1333 if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms =
cString::sprintf(
"%s%s%s", *ms, **ms ?
"," :
"",
MapToUserString(VSB_16, ModulationValues)); }
1336 ms =
"unknown modulations";
1337 isyslog(
"frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
1341 esyslog(
"ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
1353 int ErrorDevice = 0;
1356 if (
cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1357 if (
cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1358 if (!DvbDevice1->Bond(DvbDevice2))
1362 ErrorDevice = d + 1;
1365 ErrorDevice = i + 1;
1367 esyslog(
"ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
1372 ErrorDevice = d + 1;
1375 ErrorDevice = i + 1;
1377 esyslog(
"ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
1397 if (!bondedDevice) {
1398 if (Device !=
this) {
1403 dsyslog(
"device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1408 esyslog(
"ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->
CardIndex() + 1);
1411 esyslog(
"ERROR: can't bond device %d with itself", CardIndex() + 1);
1414 esyslog(
"ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->
CardIndex() + 1);
1424 dsyslog(
"device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1425 while (d->bondedDevice !=
this)
1426 d = d->bondedDevice;
1427 if (d == bondedDevice)
1428 d->bondedDevice = NULL;
1430 d->bondedDevice = bondedDevice;
1431 bondedDevice = NULL;
1438 if (bondedDevice || Positioner())
1439 return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1451 dmx_pes_filter_params pesFilterParams;
1452 memset(&pesFilterParams, 0,
sizeof(pesFilterParams));
1454 if (Handle->
handle < 0) {
1456 if (Handle->
handle < 0) {
1461 pesFilterParams.pid = Handle->
pid;
1462 pesFilterParams.input = DMX_IN_FRONTEND;
1463 pesFilterParams.output = DMX_OUT_TS_TAP;
1464 pesFilterParams.pes_type= DMX_PES_OTHER;
1465 pesFilterParams.flags = DMX_IMMEDIATE_START;
1466 if (ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
1471 else if (!Handle->
used) {
1473 if (Type <= ptTeletext) {
1474 pesFilterParams.pid = 0x1FFF;
1475 pesFilterParams.input = DMX_IN_FRONTEND;
1476 pesFilterParams.output = DMX_OUT_DECODER;
1477 pesFilterParams.pes_type= DMX_PES_OTHER;
1478 pesFilterParams.flags = DMX_IMMEDIATE_START;
1479 CHECK(ioctl(Handle->
handle, DMX_SET_PES_FILTER, &pesFilterParams));
1491 int f = open(FileName, O_RDWR | O_NONBLOCK);
1493 dmx_sct_filter_params sctFilterParams;
1494 memset(&sctFilterParams, 0,
sizeof(sctFilterParams));
1495 sctFilterParams.pid = Pid;
1496 sctFilterParams.timeout = 0;
1497 sctFilterParams.flags = DMX_IMMEDIATE_START;
1498 sctFilterParams.filter.filter[0] = Tid;
1499 sctFilterParams.filter.mask[0] = Mask;
1500 if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
1503 esyslog(
"ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
1508 esyslog(
"ERROR: can't open filter handle on '%s'", *FileName);
1519 for (
int i = 0; i < numDeliverySystems; i++) {
1520 if (deliverySystems[i] == DeliverySystem)
1531 || type ==
cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
1532 || type ==
cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
1538 if (!ProvidesSource(Channel->
Source()))
1543 dtp.
Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
1544 dtp.
Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
1545 dtp.
Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
1546 dtp.
Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
1547 dtp.
Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
1548 dtp.
Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
1549 dtp.
Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
1550 dtp.
Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
1551 dtp.
Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
1556 return DeviceHooksProvidesTransponder(Channel);
1562 bool result =
false;
1563 bool hasPriority = Priority ==
IDLEPRIORITY || Priority > this->Priority();
1564 bool needsDetachReceivers =
false;
1565 needsDetachBondedReceivers =
false;
1567 if (dvbTuner && ProvidesTransponder(Channel)) {
1568 result = hasPriority;
1571 if (dvbTuner->IsTunedTo(Channel)) {
1572 if (Channel->
Vpid() && !HasPid(Channel->
Vpid()) || Channel->
Apid(0) && !HasPid(Channel->
Apid(0)) || Channel->
Dpid(0) && !HasPid(Channel->
Dpid(0))) {
1574 if (CamSlot()->CanDecrypt(Channel))
1577 needsDetachReceivers =
true;
1586 needsDetachReceivers = Receiving();
1590 if (!BondingOk(Channel)) {
1593 if (d->Priority() >= Priority) {
1597 needsDetachReceivers |= d->Receiving();
1599 needsDetachBondedReceivers =
true;
1600 needsDetachReceivers |= Receiving();
1605 if (NeedsDetachReceivers)
1606 *NeedsDetachReceivers = needsDetachReceivers;
1612 return dvbTuner != NULL;
1617 return numDeliverySystems + numModulations;
1622 return dvbTuner ? dvbTuner->Positioner() : NULL;
1627 return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
1632 return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
1637 return dvbTuner ? dvbTuner->GetTransponder() : NULL;
1642 return dvbTuner ? dvbTuner->IsTunedTo(Channel) :
false;
1653 dvbTuner->SetChannel(Channel);
1659 return dvbTuner ? dvbTuner->Locked(TimeoutMs) :
false;
1664 setTransferModeForDolbyDigital = Mode;
1670 fd_dvr = DvbOpen(
DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK,
true);
1690 if (cs->WantsTsData()) {
1692 Data = tsBuffer->Get(&Available);
1694 Data = cs->Decrypt(Data, Available);
1695 tsBuffer->Skip(Available);
1700 Data = tsBuffer->Get();
1711 d->cDevice::DetachAllReceivers();
1713 }
while (d && d !=
this && needsDetachBondedReceivers);
1714 needsDetachBondedReceivers =
false;
1723 DvbDeviceProbes.
Add(
this);
1728 DvbDeviceProbes.
Del(
this,
false);
1733 uint32_t SubsystemId = 0;
1736 if (stat(FileName, &st) == 0) {
1740 while ((e = d.
Next()) != NULL) {
1741 if (strstr(e->d_name,
"frontend")) {
1743 if (FILE *f = fopen(FileName,
"r")) {
1745 char *s = ReadLine.
Read(f);
1749 if (s && 2 == sscanf(s,
"%u:%u", &Major, &Minor)) {
1750 if (((Major << 8) | Minor) == st.st_rdev) {
1751 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
1752 if ((f = fopen(FileName,
"r")) != NULL) {
1753 if (
char *s = ReadLine.
Read(f))
1754 SubsystemId = strtoul(s, NULL, 0) << 16;
1758 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idVendor", e->d_name);
1759 if ((f = fopen(FileName,
"r")) != NULL) {
1760 if (
char *s = ReadLine.
Read(f))
1761 SubsystemId = strtoul(s, NULL, 16) << 16;
1765 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/subsystem_device", e->d_name);
1766 if ((f = fopen(FileName,
"r")) != NULL) {
1767 if (
char *s = ReadLine.
Read(f))
1768 SubsystemId |= strtoul(s, NULL, 0);
1772 FileName =
cString::sprintf(
"/sys/class/dvb/%s/device/idProduct", e->d_name);
1773 if ((f = fopen(FileName,
"r")) != NULL) {
1774 if (
char *s = ReadLine.
Read(f))
1775 SubsystemId |= strtoul(s, NULL, 16);
static unsigned int FrequencyToHz(unsigned int f)
struct dirent * Next(void)
virtual ~cDvbDeviceProbe()
const char * DeliverySystemNames[]
cDvbTransponderParameters(const char *Parameters=NULL)
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.
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
void ResetToneAndVoltage(void)
#define SCR_RANDOM_TIMEOUT
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 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...
#define DVBS_LOCK_TIMEOUT
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
static cString sprintf(const char *fmt,...) __attribute__((format(printf
#define DVBC_LOCK_TIMEOUT
const tDvbParameterMap SystemValuesSat[]
virtual void Append(T Data)
#define DVBT_LOCK_TIMEOUT
static uint32_t GetSubsystemId(int Adapter, int Frontend)
const tDvbParameterMap InversionValues[]
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).
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
Parses the DiSEqC commands and returns the appropriate action code with every call.
static int NumDevices(void)
Returns the total number of devices.
bool IsTunedTo(const cChannel *Channel) const
#define TUNER_POLL_TIMEOUT
void DelLivePids(void)
Deletes the live viewing PIDs.
int GetSignalStrength(void) const
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)
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...
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.
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 void SetData(cChannel *Channel)
Sets all source specific parameters to those of the given Channel.
cDvbDevice * bondedDevice
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)
cList< cDvbDeviceProbe > DvbDeviceProbes
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
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[]
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)
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
const cChannel * GetTransponder(void) const
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_DVBT2_PLP_ID_LEGACY
const tDvbParameterMap SystemValuesTerr[]
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)
The cDevice class is the base from which actual devices can be derived.
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...