vdr 2.8.3
dvbdevice.c
Go to the documentation of this file.
1/*
2 * dvbdevice.c: The DVB device tuner interface
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: dvbdevice.c 5.10 2026/08/29 11:46:58 kls Exp $
8 */
9
10#include "dvbdevice.h"
11#include <ctype.h>
12#include <errno.h>
13#include <limits.h>
14#include <linux/dvb/dmx.h>
15#include <linux/dvb/frontend.h>
16#include <sys/ioctl.h>
17#include <sys/mman.h>
18#include "channels.h"
19#include "diseqc.h"
20#include "dvbci.h"
21#include "menuitems.h"
22#include "sourceparams.h"
23
24static int DvbApiVersion = 0x0000; // the version of the DVB driver actually in use (will be determined by the first device created)
25
26#define BANDWIDTH_HZ_AUTO 0 // missing in DVB API 5
27
28#define DVBS_TUNE_TIMEOUT 9000 //ms
29#define DVBS_LOCK_TIMEOUT 2000 //ms
30#define DVBC_TUNE_TIMEOUT 9000 //ms
31#define DVBC_LOCK_TIMEOUT 2000 //ms
32#define DVBT_TUNE_TIMEOUT 9000 //ms
33#define DVBT_LOCK_TIMEOUT 2000 //ms
34#define ATSC_TUNE_TIMEOUT 9000 //ms
35#define ATSC_LOCK_TIMEOUT 2000 //ms
36
37#define SCR_RANDOM_TIMEOUT 500 // ms (add random value up to this when tuning SCR device to avoid lockups)
38
39#define TSBUFFERSIZE MEGABYTE(16)
40
41// --- DVB Parameter Maps ----------------------------------------------------
42
44 { 0, PILOT_OFF, trNOOP("off") },
45 { 1, PILOT_ON, trNOOP("on") },
46 { 999, PILOT_AUTO, trNOOP("auto") },
47 { -1, 0, NULL }
48 };
49
51 { 0, INVERSION_OFF, trNOOP("off") },
52 { 1, INVERSION_ON, trNOOP("on") },
53 { 999, INVERSION_AUTO, trNOOP("auto") },
54 { -1, 0, NULL }
55 };
56
58 { 5, 5000000, "5 MHz" },
59 { 6, 6000000, "6 MHz" },
60 { 7, 7000000, "7 MHz" },
61 { 8, 8000000, "8 MHz" },
62 { 10, 10000000, "10 MHz" },
63 { 1712, 1712000, "1.712 MHz" },
64 { 999, BANDWIDTH_HZ_AUTO, trNOOP("auto") },
65 { -1, 0, NULL }
66 };
67
69 { 0, FEC_NONE, trNOOP("none") },
70 { 12, FEC_1_2, "1/2" },
71 { 23, FEC_2_3, "2/3" },
72 { 34, FEC_3_4, "3/4" },
73 { 35, FEC_3_5, "3/5" },
74 { 45, FEC_4_5, "4/5" },
75 { 56, FEC_5_6, "5/6" },
76 { 67, FEC_6_7, "6/7" },
77 { 78, FEC_7_8, "7/8" },
78 { 89, FEC_8_9, "8/9" },
79 { 910, FEC_9_10, "9/10" },
80 { 999, FEC_AUTO, trNOOP("auto") },
81 { -1, 0, NULL }
82 };
83
85 { 16, QAM_16, "QAM16" },
86 { 32, QAM_32, "QAM32" },
87 { 64, QAM_64, "QAM64" },
88 { 128, QAM_128, "QAM128" },
89 { 256, QAM_256, "QAM256" },
90 { 2, QPSK, "QPSK" },
91 { 5, PSK_8, "8PSK" },
92 { 6, APSK_16, "16APSK" },
93 { 7, APSK_32, "32APSK" },
94 { 10, VSB_8, "VSB8" },
95 { 11, VSB_16, "VSB16" },
96 { 12, DQPSK, "DQPSK" },
97 { 999, QAM_AUTO, trNOOP("auto") },
98 { -1, 0, NULL }
99 };
100
101#define DVB_SYSTEM_1 0 // see also nit.c
102#define DVB_SYSTEM_2 1
103
105 { 0, DVB_SYSTEM_1, "DVB-S" },
106 { 1, DVB_SYSTEM_2, "DVB-S2" },
107 { -1, 0, NULL }
108 };
109
111 { 0, DVB_SYSTEM_1, "DVB-T" },
112 { 1, DVB_SYSTEM_2, "DVB-T2" },
113 { -1, 0, NULL }
114 };
115
117 { 1, TRANSMISSION_MODE_1K, "1K" },
118 { 2, TRANSMISSION_MODE_2K, "2K" },
119 { 4, TRANSMISSION_MODE_4K, "4K" },
120 { 8, TRANSMISSION_MODE_8K, "8K" },
121 { 16, TRANSMISSION_MODE_16K, "16K" },
122 { 32, TRANSMISSION_MODE_32K, "32K" },
123 { 999, TRANSMISSION_MODE_AUTO, trNOOP("auto") },
124 { -1, 0, NULL }
125 };
126
128 { 4, GUARD_INTERVAL_1_4, "1/4" },
129 { 8, GUARD_INTERVAL_1_8, "1/8" },
130 { 16, GUARD_INTERVAL_1_16, "1/16" },
131 { 32, GUARD_INTERVAL_1_32, "1/32" },
132 { 128, GUARD_INTERVAL_1_128, "1/128" },
133 { 19128, GUARD_INTERVAL_19_128, "19/128" },
134 { 19256, GUARD_INTERVAL_19_256, "19/256" },
135 { 999, GUARD_INTERVAL_AUTO, trNOOP("auto") },
136 { -1, 0, NULL }
137 };
138
140 { 0, HIERARCHY_NONE, trNOOP("none") },
141 { 1, HIERARCHY_1, "1" },
142 { 2, HIERARCHY_2, "2" },
143 { 4, HIERARCHY_4, "4" },
144 { 999, HIERARCHY_AUTO, trNOOP("auto") },
145 { -1, 0, NULL }
146 };
147
149 { 0, ROLLOFF_AUTO, trNOOP("auto") },
150 { 20, ROLLOFF_20, "0.20" },
151 { 25, ROLLOFF_25, "0.25" },
152 { 35, ROLLOFF_35, "0.35" },
153 { -1, 0, NULL }
154 };
155
156int UserIndex(int Value, const tDvbParameterMap *Map)
157{
158 const tDvbParameterMap *map = Map;
159 while (map && map->userValue != -1) {
160 if (map->userValue == Value)
161 return map - Map;
162 map++;
163 }
164 return -1;
165}
166
167int DriverIndex(int Value, const tDvbParameterMap *Map)
168{
169 const tDvbParameterMap *map = Map;
170 while (map && map->userValue != -1) {
171 if (map->driverValue == Value)
172 return map - Map;
173 map++;
174 }
175 return -1;
176}
177
178int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
179{
180 int n = DriverIndex(Value, Map);
181 if (n >= 0) {
182 if (String)
183 *String = tr(Map[n].userString);
184 return Map[n].userValue;
185 }
186 return -1;
187}
188
189const char *MapToUserString(int Value, const tDvbParameterMap *Map)
190{
191 int n = DriverIndex(Value, Map);
192 if (n >= 0)
193 return Map[n].userString;
194 return "???";
195}
196
197int MapToDriver(int Value, const tDvbParameterMap *Map)
198{
199 int n = UserIndex(Value, Map);
200 if (n >= 0)
201 return Map[n].driverValue;
202 return -1;
203}
204
205// --- cDvbTransponderParameters ---------------------------------------------
206
208{
209 Parse(Parameters);
210}
211
212int cDvbTransponderParameters::PrintParameter(char *p, char Name, int Value) const
213{
214 return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0;
215}
216
218{
219#define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*')))
220 char buffer[64];
221 char *q = buffer;
222 *q = 0;
223 ST(" S *") q += sprintf(q, "%c", polarization);
224 ST(" T*") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues));
225 ST(" CST*") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues));
226 ST(" T*") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues));
227 ST(" T*") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues));
228 ST("ACST*") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues));
229 ST("ACST*") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues));
230 ST(" S 2") q += PrintParameter(q, 'N', MapToUser(pilot, PilotValues));
231 ST(" S 2") q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues));
232 ST(" ST2") q += PrintParameter(q, 'P', streamId);
233 ST(" T2") q += PrintParameter(q, 'Q', t2systemId);
234 ST(" ST*") q += PrintParameter(q, 'S', MapToUser(system, SystemValuesSat)); // we only need the numerical value, so Sat or Terr doesn't matter
236 ST(" T2") q += PrintParameter(q, 'X', sisoMiso);
237 ST(" T*") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues));
238 return buffer;
239}
240
241const char *cDvbTransponderParameters::ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map)
242{
243 if (*++s) {
244 char *p = NULL;
245 errno = 0;
246 int n = strtol(s, &p, 10);
247 if (!errno && p != s) {
248 Value = Map ? MapToDriver(n, Map) : n;
249 if (Value >= 0)
250 return p;
251 }
252 }
253 esyslog("ERROR: invalid value for parameter '%c'", *(s - 1));
254 return NULL;
255}
256
258{
259 polarization = 0;
260 inversion = INVERSION_AUTO;
262 coderateH = FEC_AUTO;
263 coderateL = FEC_AUTO;
264 modulation = QAM_AUTO;
266 transmission = TRANSMISSION_MODE_AUTO;
267 guard = GUARD_INTERVAL_AUTO;
268 hierarchy = HIERARCHY_AUTO;
269 rollOff = ROLLOFF_AUTO;
270 streamId = 0;
271 t2systemId = 0;
272 sisoMiso = 0;
273 pilot = PILOT_AUTO;
274 while (s && *s) {
275 switch (toupper(*s)) {
276 case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break;
277 case 'C': s = ParseParameter(s, coderateH, CoderateValues); break;
278 case 'D': s = ParseParameter(s, coderateL, CoderateValues); break;
279 case 'G': s = ParseParameter(s, guard, GuardValues); break;
280 case 'H': polarization = 'H'; s++; break;
281 case 'I': s = ParseParameter(s, inversion, InversionValues); break;
282 case 'L': polarization = 'L'; s++; break;
283 case 'M': s = ParseParameter(s, modulation, ModulationValues); break;
284 case 'N': s = ParseParameter(s, pilot, PilotValues); break;
285 case 'O': s = ParseParameter(s, rollOff, RollOffValues); break;
286 case 'P': s = ParseParameter(s, streamId); break;
287 case 'Q': s = ParseParameter(s, t2systemId); break;
288 case 'R': polarization = 'R'; s++; break;
289 case 'S': s = ParseParameter(s, system, SystemValuesSat); break; // we only need the numerical value, so Sat or Terr doesn't matter
290 case 'T': s = ParseParameter(s, transmission, TransmissionValues); break;
291 case 'V': polarization = 'V'; s++; break;
292 case 'X': s = ParseParameter(s, sisoMiso); break;
293 case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break;
294 default: esyslog("ERROR: unknown parameter key '%c'", *s);
295 return false;
296 }
297 }
298 return true;
299}
300
301// --- cDvbFrontend ----------------------------------------------------------
302
303const char *DeliverySystemNames[] = {
304 "???",
305 "DVB-C",
306 "DVB-C",
307 "DVB-T",
308 "DSS",
309 "DVB-S",
310 "DVB-S2",
311 "DVB-H",
312 "ISDBT",
313 "ISDBS",
314 "ISDBC",
315 "ATSC",
316 "ATSCMH",
317 "DTMB",
318 "CMMB",
319 "DAB",
320 "DVB-T2",
321 "TURBO",
322 "DVB-C",
323 "DVB-C2",
324 NULL
325 };
326
327static const int DeliverySystemNamesMax = sizeof(DeliverySystemNames) / sizeof(DeliverySystemNames[0]) - 2; // -1 to get the maximum allowed index & -1 for the NULL => -2
328
329static const char *GetDeliverySystemName(int Index)
330{
331 if (Index > DeliverySystemNamesMax)
332 Index = 0;
333 return DeliverySystemNames[Index];
334};
335
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);\
341 return false;\
342 }\
343 }
344
346private:
349 uint32_t subsystemId;
350 dvb_frontend_info frontendInfo;
353 bool QueryDeliverySystems(void);
354public:
355 cDvbFrontend(int Adapter, int Frontend);
357 int Open(void);
358 void Close(void);
359 const char *FrontendName(void) { return frontendInfo.name; }
360 bool ProvidesDeliverySystem(int DeliverySystem) const;
361 bool ProvidesModulation(int System, int StreamId, int Modulation) const;
362 int NumDeliverySystems(void) const { return deliverySystems.Size(); }
363 int NumModulations(void) const { return numModulations; }
364 uint32_t SubsystemId(void) const { return subsystemId; }
365 };
366
367cDvbFrontend::cDvbFrontend(int Adapter, int Frontend)
368{
369 adapter = Adapter;
370 frontend = Frontend;
371 fd_frontend = -1;
373 memset(&frontendInfo, 0, sizeof(frontendInfo));
374 strn0cpy(frontendInfo.name, "???", sizeof(frontendInfo.name));
375 numModulations = 0;
376 Open();
378 Close();
379}
380
385
387{
388 Close();
389 fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK, true);
390 return fd_frontend;
391}
392
394{
395 if (fd_frontend >= 0) {
396 if (close(fd_frontend) != 0)
397 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
398 fd_frontend = -1;
399 }
400}
401
402bool cDvbFrontend::ProvidesDeliverySystem(int DeliverySystem) const
403{
404 for (int i = 0; i < deliverySystems.Size(); i++) {
405 if (deliverySystems[i] == DeliverySystem)
406 return true;
407 }
408 return false;
409}
410
411bool cDvbFrontend::ProvidesModulation(int System, int StreamId, int Modulation) const
412{
413 if (StreamId != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM))
414 return false;
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) ||
424 Modulation == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && System == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to de
425 return false;
426 return true;
427}
428
430{
432 numModulations = 0;
433 if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
434 LOG_ERROR;
435 return false;
436 }
437 dtv_property Props[1];
438 dtv_properties CmdSeq;
439 // Determine the version of the running DVB API:
440 if (!DvbApiVersion) {
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) {
446 LOG_ERROR;
447 return false;
448 }
449 DvbApiVersion = Props[0].u.data;
450 isyslog("DVB API version is 0x%04X (VDR was built with 0x%04X)", DvbApiVersion, DVBAPIVERSION);
451 }
452 // Determine the types of delivery systems this device provides:
453 bool LegacyMode = true;
454 if (DvbApiVersion >= 0x0505) {
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);
460 if (Result == 0) {
461 for (uint i = 0; i < Props[0].u.buffer.len; i++) {
462 // activate this line to simulate a multi-frontend device if you only have a single-frontend device with DVB-S and DVB-S2:
463 //if (frontend == 0 && Props[0].u.buffer.data[i] != SYS_DVBS || frontend == 1 && Props[0].u.buffer.data[i] != SYS_DVBS2)
464 deliverySystems.Append(Props[0].u.buffer.data[i]);
465 }
466 LegacyMode = false;
467 }
468 else {
469 esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
470 }
471 }
472 if (LegacyMode) {
473 // Legacy mode (DVB-API < 5.5):
474 switch (frontendInfo.type) {
475 case FE_QPSK: deliverySystems.Append(SYS_DVBS);
477 deliverySystems.Append(SYS_DVBS2);
478 break;
479 case FE_OFDM: deliverySystems.Append(SYS_DVBT);
482 break;
483 case FE_QAM: deliverySystems.Append(SYS_DVBC_ANNEX_AC); break;
484 case FE_ATSC: deliverySystems.Append(SYS_ATSC); break;
485 default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
486 }
487 }
488 if (deliverySystems.Size() > 0) {
489 cString ds("");
490 for (int i = 0; i < deliverySystems.Size(); i++)
491 ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", GetDeliverySystemName(deliverySystems[i]));
492 cString ms("");
493 if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
494 if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
495 if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); }
496 if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); }
497 if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); }
498 if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); }
499 if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); }
500 if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); }
501 if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); }
502 if (!**ms)
503 ms = "unknown modulations";
504 isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
505 return true;
506 }
507 else
508 esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
509 return false;
510}
511
512// --- cDvbTuner -------------------------------------------------------------
513
514#define TUNER_POLL_TIMEOUT 10 // ms
515
517{
518 int ds = SYS_UNDEFINED;
519 if (Channel->IsAtsc())
520 ds = SYS_ATSC;
521 else if (Channel->IsCable())
522 ds = SYS_DVBC_ANNEX_AC;
523 else if (Channel->IsSat())
524 ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBS : SYS_DVBS2;
525 else if (Channel->IsTerr())
526 ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBT : SYS_DVBT2;
527 else
528 esyslog("ERROR: can't determine frontend type for channel %d (%s)", Channel->Number(), Channel->Name());
529 return ds;
530}
531
532class cDvbTuner : public cThread {
533private:
536 std::atomic<int> frontendType; // FrontendType() reads it without the mutex
538 mutable int fd_frontend;
540 mutable int frontend;
548 mutable uint32_t lastUncValue;
549 mutable uint32_t lastUncDelta;
550 mutable time_t lastUncChange;
552 mutable const cDiseqc *lastDiseqc;
554 mutable int lastSource;
555 std::atomic<cPositioner *> positioner; // Positioner() reads it without the mutex
556 const cScr *scr;
557 mutable bool lnbPowerTurnedOn;
558 std::atomic<eTunerStatus> tunerStatus; // Locked() and the destructor use it without the mutex
559 mutable cMutex mutex;
564 cString GetBondingParams(const cChannel *Channel = NULL) const;
566 bool IsBondedMaster(void) const { return !bondedTuner || bondedMaster; }
567 void ClearEventQueue(void) const;
568 bool GetFrontendStatus(fe_status_t &Status) const;
570 void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency);
571 void ResetToneAndVoltage(void);
572 bool SetFrontend(void);
573 virtual void Action(void) override;
574public:
575 cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend);
576 virtual ~cDvbTuner() override;
577 bool ProvidesDeliverySystem(int DeliverySystem) const;
578 bool ProvidesModulation(int System, int StreamId, int Modulation) const;
579 bool ProvidesFrontend(const cChannel *Channel, bool Activate = false) const;
580 int Frontend(void) const { return frontend; }
581 int FrontendType(void) const { return frontendType; }
582 const char *FrontendName(void) { return dvbFrontend->FrontendName(); }
584 bool Bond(cDvbTuner *Tuner);
585 void UnBond(void);
586 bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
587 const cChannel *GetTransponder(void) const { return &channel; }
588 uint32_t SubsystemId(void) const { return dvbFrontend->SubsystemId(); }
589 bool IsTunedTo(const cChannel *Channel) const;
590 void SetChannel(const cChannel *Channel);
591 bool Locked(int TimeoutMs = 0);
592 const cPositioner *Positioner(void) const { return positioner; }
593 bool GetSignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
594 int GetSignalStrength(void) const;
595 int GetSignalQuality(void) const;
596 void SetPowerSaveMode(bool On);
597 };
598
600
601cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend)
602{
603 frontendType = SYS_UNDEFINED;
604 device = Device;
605 fd_frontend = -1;
606 adapter = Adapter;
608 dvbFrontend = NULL;
609 tuneTimeout = 0;
610 lockTimeout = 0;
612 lastUncValue = 0;
613 lastUncDelta = 0;
614 lastUncChange = 0;
615 lastDiseqc = NULL;
616 diseqcOffset = 0;
617 lastSource = 0;
618 positioner = NULL;
619 scr = NULL;
620 lnbPowerTurnedOn = false;
622 bondedTuner = NULL;
623 bondedMaster = false;
628 cString FrontendNumbers = cString::sprintf("%d", frontend);
629 // Check for multiple frontends:
630 if (frontend == 0) {
631 for (int i = 1; ; i++) {
632 if (access(DvbName(DEV_DVB_FRONTEND, adapter, i), F_OK) == 0) {
633 if (access(DvbName(DEV_DVB_DEMUX, adapter, i), F_OK) != 0) {
634 fe = new cDvbFrontend(adapter, i);
637 //numModulations += fe->NumModulations(); // looks like in multi frontend devices all frontends report the same modulations
638 FrontendNumbers = cString::sprintf("%s+%d", *FrontendNumbers, i);
639 }
640 }
641 else
642 break;
643 }
644 }
645 // Open default frontend:
648 SetDescription("frontend %d/%s tuner", adapter, *FrontendNumbers);
649 Start();
650}
651
653{
657 Cancel(3);
658 UnBond();
659 /* looks like this irritates the SCR switch, so let's leave it out for now
660 if (lastDiseqc && lastDiseqc->IsScr()) {
661 unsigned int Frequency = 0;
662 ExecuteDiseqc(lastDiseqc, &Frequency);
663 }
664 */
665 for (int i = 0; i < dvbFrontends.Size(); i++)
666 delete dvbFrontends[i];
667}
668
669bool cDvbTuner::ProvidesDeliverySystem(int DeliverySystem) const
670{
671 for (int i = 0; i < dvbFrontends.Size(); i++) {
672 if (dvbFrontends[i]->ProvidesDeliverySystem(DeliverySystem))
673 return true;
674 }
675 return false;
676}
677
678bool cDvbTuner::ProvidesModulation(int System, int StreamId, int Modulation) const
679{
680 for (int i = 0; i < dvbFrontends.Size(); i++) {
681 if (dvbFrontends[i]->ProvidesModulation(System, StreamId, Modulation))
682 return true;
683 }
684 return false;
685}
686
687bool cDvbTuner::ProvidesFrontend(const cChannel *Channel, bool Activate) const
688{
690 int DeliverySystem = GetRequiredDeliverySystem(Channel, &dtp);
691 for (int i = 0; i < dvbFrontends.Size(); i++) {
692 if (dvbFrontends[i]->ProvidesDeliverySystem(DeliverySystem) && dvbFrontends[i]->ProvidesModulation(dtp.System(), dtp.StreamId(), dtp.Modulation())) {
693 if (Activate && dvbFrontend != dvbFrontends[i]) {
694 cMutexLock MutexLock(&mutex);
698 frontend = i;
699 dsyslog("using frontend %d/%d", adapter, frontend);
700 lastDiseqc = NULL;
701 lastSource = 0;
702 lastUncValue = 0;
703 lastUncDelta = 0;
704 lastUncChange = 0;
705 lnbPowerTurnedOn = false;
706 }
707 return true;
708 }
709 }
710 return false;
711}
712
714{
715 cMutexLock MutexLock(&bondMutex);
716 if (!bondedTuner) {
718 bondedMaster = false; // makes sure we don't disturb an existing master
719 bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
720 Tuner->bondedTuner = this;
721 dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
722 return true;
723 }
724 else
725 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);
726 return false;
727}
728
730{
731 cMutexLock MutexLock(&bondMutex);
732 if (cDvbTuner *t = bondedTuner) {
733 dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
734 while (t->bondedTuner != this)
735 t = t->bondedTuner;
736 if (t == bondedTuner)
737 t->bondedTuner = NULL;
738 else
739 t->bondedTuner = bondedTuner;
740 bondedMaster = false; // another one will automatically become master whenever necessary
741 bondedTuner = NULL;
742 }
743}
744
746{
747 if (!Channel)
748 Channel = &channel;
750 if (Setup.DiSEqC) {
751 if (const cDiseqc *diseqc = Diseqcs.Get(device->DeviceNumber() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL))
752 return diseqc->Commands();
753 }
754 else {
755 bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
756 bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
757 return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
758 }
759 return "";
760}
761
762bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
763{
764 cMutexLock MutexLock(&bondMutex);
765 if (cDvbTuner *t = bondedTuner) {
766 cString BondingParams = GetBondingParams(Channel);
767 do {
768 if (t->device->Priority() > IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
769 if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
770 return false;
771 }
772 t = t->bondedTuner;
773 } while (t != bondedTuner);
774 }
775 return true;
776}
777
779{
780 if (!bondedTuner)
781 return this; // an unbonded tuner is always "master"
782 cMutexLock MutexLock(&bondMutex);
783 if (bondedMaster)
784 return this;
785 // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
786 if (cDvbTuner *t = bondedTuner) {
787 while (t != this) {
788 if (t->bondedMaster)
789 return t;
790 t = t->bondedTuner;
791 }
792 }
793 // None of the other bonded tuners is master, so make this one the master:
794 bondedMaster = true;
795 dsyslog("tuner %d/%d is now bonded master", adapter, frontend);
796 return this;
797}
798
799bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
800{
801 cMutexLock MutexLock(&mutex); // SetChannel() reassigns 'channel', freeing its strings
802 if (tunerStatus == tsIdle)
803 return false; // not tuned to
804 if (channel.Source() != Channel->Source() || channel.Transponder() != Channel->Transponder() || channel.Srate() != Channel->Srate())
805 return false; // sufficient mismatch
806 // Polarization is already checked as part of the Transponder.
807 return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
808}
809
810void cDvbTuner::SetChannel(const cChannel *Channel)
811{
812 if (Channel) {
813 if (bondedTuner) {
814 cMutexLock MutexLock(&bondMutex);
815 cDvbTuner *BondedMaster = GetBondedMaster();
816 if (BondedMaster == this) {
817 if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
818 // switching to a completely different band, so set all others to idle:
819 for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
820 t->SetChannel(NULL);
821 }
822 }
823 else if (strcmp(GetBondingParams(Channel), BondedMaster->GetBondingParams()) != 0)
824 BondedMaster->SetChannel(Channel);
825 }
826 cMutexLock MutexLock(&mutex);
827 if (!IsTunedTo(Channel))
829 diseqcOffset = 0;
830 channel = *Channel;
833 }
834 else {
835 cMutexLock MutexLock(&mutex);
838 }
840 cDevice::PrimaryDevice()->DelLivePids(); // 'device' is const, so we must do it this way
841}
842
843bool cDvbTuner::Locked(int TimeoutMs)
844{
845 bool isLocked = (tunerStatus >= tsLocked);
846 if (isLocked || !TimeoutMs)
847 return isLocked;
848
849 cMutexLock MutexLock(&mutex);
850 if (TimeoutMs && tunerStatus < tsLocked)
851 locked.TimedWait(mutex, TimeoutMs);
852 return tunerStatus >= tsLocked;
853}
854
856{
857 cPoller Poller(fd_frontend);
858 if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
859 dvb_frontend_event Event;
860 while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
861 ; // just to clear the event queue - we'll read the actual status below
862 }
863}
864
865bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
866{
867 if (fd_frontend == -1)
868 return false;
870 Status = (fe_status_t)0; // initialize here to fix buggy drivers
871 while (1) {
872 if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
873 return true;
874 if (errno != EINTR)
875 break;
876 }
877 return false;
878}
879
880//#define DEBUG_SIGNALSTATS
881//#define DEBUG_SIGNALSTRENGTH
882//#define DEBUG_SIGNALQUALITY
883
884bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
885{
886 if (fd_frontend == -1)
887 return false;
889 fe_status_t FeStatus = (fe_status_t)0; // initialize here to fix buggy drivers
890 dtv_property Props[MAXFRONTENDCMDS];
891 dtv_properties CmdSeq;
892 memset(&Props, 0, sizeof(Props));
893 memset(&CmdSeq, 0, sizeof(CmdSeq));
894 CmdSeq.props = Props;
895 Valid = DTV_STAT_VALID_NONE;
896 if (ioctl(fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
897 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
898 return false;
899 }
900 if (Status) {
901 *Status = DTV_STAT_HAS_NONE;
902 if (FeStatus & FE_HAS_SIGNAL) *Status |= DTV_STAT_HAS_SIGNAL;
903 if (FeStatus & FE_HAS_CARRIER) *Status |= DTV_STAT_HAS_CARRIER;
904 if (FeStatus & FE_HAS_VITERBI) *Status |= DTV_STAT_HAS_VITERBI;
905 if (FeStatus & FE_HAS_SYNC) *Status |= DTV_STAT_HAS_SYNC;
906 if (FeStatus & FE_HAS_LOCK) *Status |= DTV_STAT_HAS_LOCK;
907 Valid |= DTV_STAT_VALID_STATUS;
908 }
909 if (Strength) SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
910 if (Cnr) SETCMD(DTV_STAT_CNR, 0);
911 if (BerPre) { SETCMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0);
912 SETCMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0); }
913 if (BerPost) { SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
914 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0); }
915 if (Per) { SETCMD(DTV_STAT_ERROR_BLOCK_COUNT, 0);
916 SETCMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0); }
917 if (CmdSeq.num && ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
918 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
919 return false;
920 }
921 int i = 0;
922 if (Strength) {
923 if (Props[i].u.st.len > 0) {
924 switch (Props[i].u.st.stat[0].scale) {
925 case FE_SCALE_DECIBEL: *Strength = double(Props[i].u.st.stat[0].svalue) / 1000;
927 break;
928 default: ;
929 }
930 }
931 i++;
932 }
933 if (Cnr) {
934 if (Props[i].u.st.len > 0) {
935 switch (Props[i].u.st.stat[0].scale) {
936 case FE_SCALE_DECIBEL: *Cnr = double(Props[i].u.st.stat[0].svalue) / 1000;
937 Valid |= DTV_STAT_VALID_CNR;
938 break;
939 default: ;
940 }
941 }
942 i++;
943 }
944 if (BerPre) {
945 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
946 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
947 uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error bit count
948 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total bit count
949 if (tbc > 0) {
950 *BerPre = double(ebc) / tbc;
951 Valid |= DTV_STAT_VALID_BERPRE;
952 }
953 }
954 }
955 i += 2;
956 }
957 if (BerPost) {
958 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
959 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
960 uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error bit count
961 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total bit count
962 if (tbc > 0) {
963 *BerPost = double(ebc) / tbc;
964 Valid |= DTV_STAT_VALID_BERPOST;
965 }
966 }
967 }
968 i += 2;
969 }
970 if (Per) {
971 if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
972 if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
973 uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error block count
974 uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total block count
975 if (tbc > 0) {
976 *Per = double(ebc) / tbc;
977 Valid |= DTV_STAT_VALID_PER;
978 }
979 }
980 }
981 i += 2;
982 }
983#ifdef DEBUG_SIGNALSTATS
984 fprintf(stderr, "FE %d/%d: API5 %04X", adapter, frontend, Valid);
985 if ((Valid & DTV_STAT_VALID_STATUS) != 0) fprintf(stderr, " STAT=%04X", *Status);
986 if ((Valid & DTV_STAT_VALID_STRENGTH) != 0) fprintf(stderr, " STR=%1.1fdBm", *Strength);
987 if ((Valid & DTV_STAT_VALID_CNR) != 0) fprintf(stderr, " CNR=%1.1fdB", *Cnr);
988 if ((Valid & DTV_STAT_VALID_BERPRE) != 0) fprintf(stderr, " BERPRE=%1.1e", *BerPre);
989 if ((Valid & DTV_STAT_VALID_BERPOST) != 0) fprintf(stderr, " BERPOST=%1.1e", *BerPost);
990 if ((Valid & DTV_STAT_VALID_PER) != 0) fprintf(stderr, " PER=%1.1e", *Per);
991 fprintf(stderr, "\n");
992#endif
993 return Valid != DTV_STAT_VALID_NONE;
994}
995
996int dB1000toPercent(int dB1000, int Low, int High)
997{
998 // Convert the given value, which is in 1/1000 dBm, to a percentage in the
999 // range 0..100. Anything below Low is considered 0%, and anything above
1000 // High counts as 100%.
1001 if (dB1000 < Low)
1002 return 0;
1003 if (dB1000 > High)
1004 return 100;
1005 // return 100 - 100 * (High - dB1000) / (High - Low); // linear conversion
1006 // return 100 - 100 * sqr(dB1000 - High) / sqr(Low - High); // quadratic conversion, see https://www.adriangranados.com/blog/dbm-to-percent-conversion
1007 double v = 10.0 * (dB1000 - High) / (Low - High); // avoids the sqr() function
1008 return 100 - v * v;
1009}
1010
1011#define REF_S1(q1) (mod == QPSK) ? q1 : 0
1012#define REF_S2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == PSK_8) ? q2 : (mod == APSK_16) ? q3 : (mod == APSK_32) ? q4 : 0
1013#define REF_T1(q1, q2, q3) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : 0
1014#define REF_T2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_256) ? q4 : 0
1015#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
1016
1017int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
1018{
1019 // Strength in 0.001dBm (dBm x 1000)
1020 cDvbTransponderParameters dtp(Channel->Parameters());
1021 int ssi = 0; // 0-100
1022 int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
1023 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
1024 int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
1025 if (Channel->IsTerr()) {
1026 int pref = 0;
1027 // NorDig Unified Ver. 2.6 - 3.4.4.6 Page 43 ff.
1028 // reference values : pref-15dBm = 0%, pref+35dBm = 100%
1029 if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
1030 fec = cod; // adjustment for DVB-T
1031 if (mod == QAM_AUTO) mod = QPSK;
1032 switch (fec) { // dBm: Q4 Q16 Q64
1033 case FEC_1_2: pref = REF_T1(-93, -87, -82); break;
1034 default:
1035 case FEC_2_3: pref = REF_T1(-91, -85, -80); break;
1036 case FEC_3_4: pref = REF_T1(-90, -84, -78); break;
1037 case FEC_5_6: pref = REF_T1(-89, -83, -77); break;
1038 case FEC_7_8: pref = REF_T1(-88, -82, -76); break;
1039 }
1040 }
1041 else { // DVB-T2
1042 if (mod == QAM_AUTO) mod = QAM_64;
1043 switch (fec) { // dBm: Q4 Q16 Q64 Q256
1044 case FEC_1_2: pref = REF_T2(-96, -91, -86, -82); break;
1045 default:
1046 case FEC_3_5: pref = REF_T2(-95, -89, -85, -80); break;
1047 case FEC_2_3: pref = REF_T2(-94, -88, -83, -78); break;
1048 case FEC_3_4: pref = REF_T2(-93, -87, -82, -76); break;
1049 case FEC_4_5: pref = REF_T2(-92, -86, -81, -75); break;
1050 case FEC_5_6: pref = REF_T2(-92, -86, -80, -74); break;
1051 }
1052 }
1053 if (pref) {
1054 int prel = (Strength / 1000) - pref;
1055 ssi = (prel < -15) ? 0 :
1056 (prel < 0) ? (prel + 15) * 2 / 3 : // 0% - 10%
1057 (prel < 20) ? prel * 4 + 10 : // 10% - 90%
1058 (prel < 35) ? (prel - 20) * 2 / 3 + 90 : // 90% - 100%
1059 100;
1060#ifdef DEBUG_SIGNALSTRENGTH
1061 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);
1062#endif
1063 }
1064 }
1065 else if (Channel->IsCable()) { // ! COMPLETELY UNTESTED !
1066 // Formula: pref(dB) = -174.0 + NoiseFigure + SymRef + CnRef
1067 // NoiseFigure = 6.5 dB; -> Tuner specific - range: 3.5 .. 9.0 dB
1068 // SymRef = 10*log(6900000) = 68.5 dB; -> for Symbolrate of 6900 kSym/sec (TV: 6900, 6750 or 6111 kSym/sec)
1069 // ==> pref(dB) = -174.0 + 6.5 + 68.5 + CnRef[modulation]{20,23,26,29,32}; (+/- 3 dB tuner specific)
1070 if (mod == QAM_AUTO) mod = QAM_256;
1071 // Q16 Q32 Q64 Q128 Q256
1072 int pref = REF_C1(-79, -76, -73, -70, -67);
1073 if (pref) {
1074 int prel = (Strength / 1000) - pref;
1075 ssi = (prel < -15) ? 0 :
1076 (prel < 0) ? (prel + 15) * 2 / 3 : // 0% - 10%
1077 (prel < 20) ? prel * 4 + 10 : // 10% - 90%
1078 (prel < 35) ? (prel - 20) * 2 / 3 + 90 : // 90% - 100%
1079 100;
1080#ifdef DEBUG_SIGNALSTRENGTH
1081 fprintf(stderr, "SSI-C: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(mod:%d)\n", Strength, pref, prel, ssi, mod);
1082#endif
1083 }
1084 }
1085 else if (Channel->IsSat())
1086 ssi = dB1000toPercent(Strength, -95000, -20000); // defaults
1087 return ssi;
1088}
1089
1090// Due to missing values or the different meanings of the reported error rate, ber_sqi is currently not taken into account
1091#define IGNORE_BER 1
1092#define BER_ERROR_FREE (1000*1000*1000) // 1/10^-9
1093
1094int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
1095{
1096#if IGNORE_BER
1097 Ber = BER_ERROR_FREE; // assume/pretend to be biterror free
1098#endif
1099 // Signal in 0.001dB (dB x 1000)
1100 cDvbTransponderParameters dtp(Channel->Parameters());
1101 int sqi = 0; // 0-100
1102 int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
1103 int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
1104 int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
1105 if (Channel->IsTerr()) { // QEF: BER 10^-6
1106 int cnref = 0;
1107 // NorDig Unified Ver. 2.6 - 3.4.4.7 Page 45 ff.
1108 // reference values for QEF (BER 10^-11 at MPEG2 demux input)
1109 if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
1110 fec = cod; // adjustment for DVB-T
1111 if (mod == QAM_AUTO) mod = QPSK;
1112 switch (fec) { // 0.1 dB Q4 Q16 Q64 (Hierarchy=None)
1113 case FEC_1_2: cnref = REF_T1(51, 108, 165); break;
1114 default:
1115 case FEC_2_3: cnref = REF_T1(69, 131, 187); break;
1116 case FEC_3_4: cnref = REF_T1(79, 146, 202); break;
1117 case FEC_5_6: cnref = REF_T1(89, 156, 216); break;
1118 case FEC_7_8: cnref = REF_T1(97, 160, 225); break;
1119 }
1120 }
1121 else { // DVB-T2
1122 if (mod == QAM_AUTO) mod = QAM_64;
1123 switch (fec) { // 0.1 dB Q4 Q16 Q64 Q256
1124 case FEC_1_2: cnref = REF_T2(35, 87, 130, 170); break;
1125 default:
1126 case FEC_3_5: cnref = REF_T2(47, 101, 148, 194); break;
1127 case FEC_2_3: cnref = REF_T2(56, 114, 162, 208); break;
1128 case FEC_3_4: cnref = REF_T2(66, 125, 177, 229); break;
1129 case FEC_4_5: cnref = REF_T2(72, 133, 187, 243); break;
1130 case FEC_5_6: cnref = REF_T2(77, 138, 194, 251); break;
1131 }
1132 }
1133 if (cnref) {
1134 int cnrel = (Signal/100) - cnref; // 0.1 dB
1135 int ber_sqi = 100; // 100%
1136 int cnr_sqi = 0; // 0%
1137 if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
1138 ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
1139 (Ber >= 10000000) ? 100 : // <= 10^-7
1140 (int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
1141 // scale: -7dB/+3dB to reference-value
1142 cnr_sqi = (cnrel < -70) ? 0 :
1143 (cnrel < +30) ? (100 + (cnrel - 30)) :
1144 100;
1145 sqi = (cnr_sqi * ber_sqi) / 100;
1146 // alternative: stretched scale: cnref-7dB = 0%, 30dB = 100%
1147 // sqi = dB1000toPercent(Signal, (100*cnref)-7000, 30000);
1148 }
1149 else { // DVB-T2
1150 ber_sqi = (Ber < 10000) ? 0 : // > 10^-4
1151 (Ber >= 10000000) ? 100 * 100 / 6 : // <= 10^-7 : 16.67% -> SQI 0% .. 100%
1152 (100 * 100 / 15); // 6.67% -> SQI 0% .. 40% || 100%
1153 // scale: -3dB/+3dB to reference-value
1154 sqi = (cnrel < -30) ? 0 :
1155 (cnrel <= +30) ? (cnrel + 30) * ber_sqi / 1000 : // (0 .. 6) * 16,67 || 6.67
1156 100;
1157 // alternative: stretched scale: cnref-3dB = 0%, 32dB = 100%
1158 // sqi = dB1000toPercent(Signal, (100*cnref)-3000, 32000);
1159 }
1160#ifdef DEBUG_SIGNALQUALITY
1161 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);
1162#endif
1163 }
1164 }
1165 else if (Channel->IsCable()) { // ! COMPLETELY UNTESTED !
1166 if (mod == QAM_AUTO) mod = QAM_256;
1167 // 0.1 dB Q16 Q32 Q64 Q128 Q256
1168 int cnref = REF_C1(200, 230, 260, 290, 320); // minimum for BER<10^-4
1169 if (cnref) {
1170 int cnrel = (Signal / 100) - cnref; // 0.1 dB
1171 int ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
1172 (Ber >= 10000000) ? 100 : // <= 10^-7
1173 (int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
1174 // scale: -7dB/+3dB to reference-value
1175 int cnr_sqi = (cnrel < -70) ? 0 :
1176 (cnrel < +30) ? (100 + (cnrel - 30)) :
1177 100;
1178 sqi = (cnr_sqi * ber_sqi) / 100;
1179 // alternative: stretched scale: cnref-7dB = 0%, 40dB = 100%
1180 // sqi = dB1000toPercent(Signal, (100*cnref)-7000, 40000);
1181#ifdef DEBUG_SIGNALQUALITY
1182 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);
1183#endif
1184 }
1185 }
1186 else if (Channel->IsSat()) {
1187 int cnref = 0;
1188 if (dtp.System() == DVB_SYSTEM_1) { // DVB-S
1189 if (mod == QAM_AUTO) mod = QPSK;
1190 switch (fec) { // 0.1 dB: Q4 : 10^-7
1191 case FEC_1_2: cnref = REF_S1(38); break;
1192 default:
1193 case FEC_2_3: cnref = REF_S1(56); break;
1194 case FEC_3_4: cnref = REF_S1(67); break;
1195 case FEC_5_6: cnref = REF_S1(77); break;
1196 case FEC_7_8: cnref = REF_S1(84); break;
1197 }
1198 if (cnref) {
1199 //cnrel = (Signal/100) - cnref; // 0.1 dB
1200 // scale: cnref-4dB = 0%, 15dB = 100%
1201 sqi = dB1000toPercent(Signal, (100*cnref)-4000, 15000);
1202#ifdef DEBUG_SIGNALQUALITY
1203 dsyslog("SQI-S1: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
1204#endif
1205 }
1206 }
1207 else { // DVB-S2
1208 if (mod == QAM_AUTO) mod = QAM_64;
1209 switch (fec) { // 0.1 dB Q4 Q8 16A* 32A*
1210 //case FEC_1_4: cnref = REF_S2(-14, 65, 90, 126); break;
1211 //case FEC_1_3: cnref = REF_S2( -2, 65, 90, 126); break;
1212 case FEC_2_5: cnref = REF_S2( 7, 65, 90, 126); break;
1213 case FEC_1_2: cnref = REF_S2( 20, 65, 90, 126); break;
1214 case FEC_3_5: cnref = REF_S2( 32, 65, 90, 126); break;
1215 default:
1216 case FEC_2_3: cnref = REF_S2( 41, 76, 90, 126); break;
1217 case FEC_3_4: cnref = REF_S2( 50, 66, 102, 126); break;
1218 case FEC_4_5: cnref = REF_S2( 57, 89, 110, 136); break;
1219 case FEC_5_6: cnref = REF_S2( 62, 104, 116, 143); break;
1220 case FEC_8_9: cnref = REF_S2( 72, 117, 129, 157); break;
1221 case FEC_9_10: cnref = REF_S2( 74, 120, 131, 161); break;
1222 }
1223 if (cnref) {
1224 // cnrel = (Signal/100) - cnref; // 0.1 dB
1225 // scale: cnref-4dB = 0%, 20dB = 100%
1226 sqi = dB1000toPercent(Signal, (100*cnref)-4000, 20000);
1227#ifdef DEBUG_SIGNALQUALITY
1228 dsyslog("SQI-S2: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
1229#endif
1230 }
1231 }
1232 }
1233 return sqi;
1234}
1235
1237{
1238 if (fd_frontend == -1)
1239 return 0;
1241 // Try DVB API 5:
1242 for (int i = 0; i < 1; i++) { // just a trick to break out with 'continue' ;-)
1243 dtv_property Props[MAXFRONTENDCMDS];
1244 dtv_properties CmdSeq;
1245 memset(&Props, 0, sizeof(Props));
1246 memset(&CmdSeq, 0, sizeof(CmdSeq));
1247 CmdSeq.props = Props;
1248 SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
1249 SETCMD(DTV_MODULATION, 0);
1250 SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
1251 SETCMD(DTV_INNER_FEC, 0);
1252 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1253 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
1254 return -1;
1255 }
1256 int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
1257 int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
1258 int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
1259 int Signal = 0;
1260 if (Props[0].u.st.len > 0) {
1261 cMutexLock MutexLock(&mutex); // for 'channel' (see IsTunedTo()), but not across the slow ioctls above, which would stall the tuner thread
1262 switch (Props[0].u.st.stat[0].scale) {
1263 case FE_SCALE_DECIBEL: Signal = StrengthToSSI(&channel, Props[0].u.st.stat[0].svalue, FeMod, FeCod, FeFec);
1264 break;
1265 case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1266 break;
1267 default: ;
1268 }
1269#ifdef DEBUG_SIGNALSTRENGTH
1270 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);
1271#endif
1272 }
1273 else
1274 continue;
1275 return Signal;
1276 }
1277 // Fall back to DVB API 3:
1278 uint16_t Signal;
1279 while (1) {
1280 if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
1281 break;
1282 if (errno != EINTR)
1283 return -1;
1284 }
1285 uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
1286 // Use the subsystemId to identify individual devices in case they need
1287 // special treatment to map their Signal value into the range 0...0xFFFF.
1288 switch (dvbFrontend->SubsystemId()) {
1289 case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
1290 case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
1291 MaxSignal = 670; break;
1292 }
1293 int s = int(Signal) * 100 / MaxSignal;
1294 if (s > 100)
1295 s = 100;
1296#ifdef DEBUG_SIGNALSTRENGTH
1297 fprintf(stderr, "FE %d/%d: API3 %08X S = %04X %04X %3d%%\n", adapter, frontend, dvbFrontend->SubsystemId(), MaxSignal, Signal, s);
1298#endif
1299 return s;
1300}
1301
1302#define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
1303
1305{
1306 if (fd_frontend == -1)
1307 return 0;
1308 // Try DVB API 5:
1309 for (int i = 0; i < 1; i++) { // just a trick to break out with 'continue' ;-)
1310 dtv_property Props[MAXFRONTENDCMDS];
1311 dtv_properties CmdSeq;
1312 memset(&Props, 0, sizeof(Props));
1313 memset(&CmdSeq, 0, sizeof(CmdSeq));
1314 CmdSeq.props = Props;
1315 SETCMD(DTV_STAT_CNR, 0);
1316 SETCMD(DTV_MODULATION, 0);
1317 SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
1318 SETCMD(DTV_INNER_FEC, 0);
1319 SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
1320 SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
1321 if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1322 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
1323 return -1;
1324 }
1325 int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
1326 int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
1327 int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
1328 int Ber = BER_ERROR_FREE; // 1/10^-9
1329 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) {
1330 uint64_t ebc = Props[4].u.st.stat[0].uvalue; // error bit count
1331 uint64_t tbc = Props[5].u.st.stat[0].uvalue; // total bit count
1332 if (ebc > 0) {
1333 uint64_t BerRev = tbc / ebc; // reversed, for integer arithmetic
1334 if (BerRev < BER_ERROR_FREE)
1335 Ber = (int)BerRev;
1336 }
1337 }
1338 int Cnr = 0;
1339 if (Props[0].u.st.len > 0) {
1340 cMutexLock MutexLock(&mutex); // for 'channel', see GetSignalStrength()
1341 switch (Props[0].u.st.stat[0].scale) {
1342 case FE_SCALE_DECIBEL: Cnr = SignalToSQI(&channel, Props[0].u.st.stat[0].svalue, Ber, FeMod, FeCod, FeFec);
1343 break;
1344 case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1345 break;
1346 default: ;
1347 }
1348#ifdef DEBUG_SIGNALQUALITY
1349 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);
1350#endif
1351 }
1352 else
1353 continue;
1354 return Cnr;
1355 }
1356 // Fall back to DVB API 3:
1357 fe_status_t Status;
1358 if (GetFrontendStatus(Status)) {
1359 // Actually one would expect these checks to be done from FE_HAS_SIGNAL to FE_HAS_LOCK, but some drivers (like the stb0899) are broken, so FE_HAS_LOCK is the only one that (hopefully) is generally reliable...
1360 if ((Status & FE_HAS_LOCK) == 0) {
1361 if ((Status & FE_HAS_SIGNAL) == 0)
1362 return 0;
1363 if ((Status & FE_HAS_CARRIER) == 0)
1364 return 1;
1365 if ((Status & FE_HAS_VITERBI) == 0)
1366 return 2;
1367 if ((Status & FE_HAS_SYNC) == 0)
1368 return 3;
1369 return 4;
1370 }
1371#ifdef DEBUG_SIGNALQUALITY
1372 bool HasSnr = true;
1373#endif
1374 uint16_t Snr;
1375 while (1) {
1376 if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
1377 break;
1378 if (errno != EINTR) {
1379 Snr = 0xFFFF;
1380#ifdef DEBUG_SIGNALQUALITY
1381 HasSnr = false;
1382#endif
1383 break;
1384 }
1385 }
1386#ifdef DEBUG_SIGNALQUALITY
1387 bool HasBer = true;
1388#endif
1389 uint32_t Ber;
1390 while (1) {
1391 if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
1392 break;
1393 if (errno != EINTR) {
1394 Ber = 0;
1395#ifdef DEBUG_SIGNALQUALITY
1396 HasBer = false;
1397#endif
1398 break;
1399 }
1400 }
1401#ifdef DEBUG_SIGNALQUALITY
1402 bool HasUnc = true;
1403#endif
1404 uint32_t Unc;
1405 while (1) {
1406 if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1) {
1407 if (Unc != lastUncValue) {
1408#ifdef DEBUG_SIGNALQUALITY
1409 fprintf(stderr, "FE %d/%d: API3 UNC = %u %u %u\n", adapter, frontend, Unc, lastUncValue, lastUncDelta);
1410#endif
1411 lastUncDelta = (Unc >= lastUncValue) ? Unc - lastUncValue : lastUncValue - Unc;
1412 lastUncValue = Unc;
1413 lastUncChange = time(NULL);
1414 }
1415 // The number of uncorrected blocks is a counter, which is normally
1416 // at a constant value and only increases if there are new uncorrected
1417 // blocks. So a change in the Unc value indicates reduced signal quality.
1418 // Whenever the Unc counter changes, we take the delta between the old
1419 // and new value into account for calculating the overall signal quality.
1420 // The impact of Unc is considered for 2 seconds, and after that it is
1421 // bisected with every passing second in order to phase it out. Otherwise
1422 // once one or more uncorrected blocks occur, the signal quality would
1423 // be considered low even if there haven't been any more uncorrected bocks
1424 // for quite a while.
1425 Unc = lastUncDelta;
1426 if (Unc > 0) {
1427 int t = time(NULL) - lastUncChange - 2;
1428 if (t > 0)
1429 Unc >>= min(t, int(sizeof(Unc) * 8 - 1));
1430 if (Unc == 0)
1431 lastUncDelta = 0;
1432#ifdef DEBUG_SIGNALQUALITY
1433 fprintf(stderr, "FE %d/%d: API3 UNC = %u\n", adapter, frontend, Unc);
1434#endif
1435 }
1436 break;
1437 }
1438 if (errno != EINTR) {
1439 Unc = 0;
1440#ifdef DEBUG_SIGNALQUALITY
1441 HasUnc = false;
1442#endif
1443 break;
1444 }
1445 }
1446 uint16_t MinSnr = 0x0000;
1447 uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
1448 // Use the subsystemId to identify individual devices in case they need
1449 // special treatment to map their Snr value into the range 0...0xFFFF.
1450 switch (dvbFrontend->SubsystemId()) {
1451 case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
1452 case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
1453 if (frontendType == SYS_DVBS2) {
1454 MinSnr = 10;
1455 MaxSnr = 70;
1456 }
1457 else
1458 MaxSnr = 200;
1459 break;
1460 case 0x20130245: // PCTV Systems PCTV 73ESE
1461 case 0x2013024F: // PCTV Systems nanoStick T2 290e
1462 MaxSnr = 255; break;
1463 }
1464 int a = int(constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
1465 int b = 100 - (Unc * 10 + (Ber / 256) * 5);
1466 if (b < 0)
1467 b = 0;
1468 int q = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
1469 if (q > 100)
1470 q = 100;
1471#ifdef DEBUG_SIGNALQUALITY
1472 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);
1473#endif
1474 return q;
1475 }
1476 return -1;
1477}
1478
1479static unsigned int FrequencyToHz(unsigned int f)
1480{
1481 while (f && f < 1000000)
1482 f *= 1000;
1483 return f;
1484}
1485
1487{
1489 if (!p) {
1492 positioner = p;
1493 }
1494 return p;
1495}
1496
1497void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
1498{
1499 if (!lnbPowerTurnedOn) {
1500 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
1501 lnbPowerTurnedOn = true;
1502 }
1503 static cMutex Mutex;
1504 if (Diseqc->IsScr())
1505 Mutex.Lock();
1506 struct dvb_diseqc_master_cmd cmd;
1507 const char *CurrentAction = NULL;
1508 cPositioner *Positioner = NULL;
1509 bool Break = false;
1510 for (int i = 0; !Break; i++) {
1511 cmd.msg_len = sizeof(cmd.msg);
1512 cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
1513 if (da == cDiseqc::daNone) {
1514 diseqcOffset = 0;
1515 break;
1516 }
1517 bool d = i >= diseqcOffset;
1518 switch (da) {
1519 case cDiseqc::daToneOff: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
1520 case cDiseqc::daToneOn: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
1521 case cDiseqc::daVoltage13: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
1522 case cDiseqc::daVoltage18: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
1523 case cDiseqc::daMiniA: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
1524 case cDiseqc::daMiniB: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
1525 case cDiseqc::daCodes: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break;
1526 case cDiseqc::daPositionN: if ((Positioner = GetPositioner()) != NULL) {
1527 if (d) {
1529 Break = Positioner->IsMoving();
1530 }
1531 }
1532 break;
1533 case cDiseqc::daPositionA: if ((Positioner = GetPositioner()) != NULL) {
1534 if (d) {
1536 Break = Positioner->IsMoving();
1537 }
1538 }
1539 break;
1540 case cDiseqc::daScr:
1541 case cDiseqc::daWait: break;
1542 default: esyslog("ERROR: unknown diseqc command %d", da);
1543 }
1544 if (Break)
1545 diseqcOffset = i + 1;
1546 }
1548 if (scr && !Break)
1549 ResetToneAndVoltage(); // makes sure we don't block the bus!
1550 if (Diseqc->IsScr())
1551 Mutex.Unlock();
1552}
1553
1555{
1556 if (fd_frontend == -1)
1557 return;
1558 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
1559 CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
1560}
1561
1563{
1564 dtv_property Props[MAXFRONTENDCMDS];
1565 memset(&Props, 0, sizeof(Props));
1566 dtv_properties CmdSeq;
1567 memset(&CmdSeq, 0, sizeof(CmdSeq));
1568 CmdSeq.props = Props;
1569 SETCMD(DTV_CLEAR, 0);
1570 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1571 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
1572 return false;
1573 }
1574 CmdSeq.num = 0;
1575
1577
1578 // Determine the required frontend type:
1580 if (frontendType == SYS_UNDEFINED)
1581 return false;
1582
1583 SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
1584 if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
1585 int frequency = channel.Frequency();
1586 if (Setup.DiSEqC) {
1587 if (const cDiseqc *diseqc = Diseqcs.Get(device->DeviceNumber() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
1588 frequency -= diseqc->Lof();
1589 if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
1590 if (IsBondedMaster()) {
1591 ExecuteDiseqc(diseqc, &frequency);
1592 if (frequency == 0)
1593 return false;
1594 }
1595 else
1597 lastDiseqc = diseqc;
1599 }
1600 }
1601 else {
1602 esyslog("ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
1603 return false;
1604 }
1605 }
1606 else {
1607 int tone = SEC_TONE_OFF;
1608 if (frequency < Setup.LnbSLOF) {
1609 frequency -= Setup.LnbFrequLo;
1610 tone = SEC_TONE_OFF;
1611 }
1612 else {
1613 frequency -= Setup.LnbFrequHi;
1614 tone = SEC_TONE_ON;
1615 }
1616 int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
1617 if (!IsBondedMaster()) {
1618 tone = SEC_TONE_OFF;
1619 volt = SEC_VOLTAGE_13;
1620 }
1621 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
1622 CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
1623 }
1624 frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
1625
1626 // DVB-S/DVB-S2 (common parts)
1627 SETCMD(DTV_FREQUENCY, frequency * 1000UL);
1628 SETCMD(DTV_MODULATION, dtp.Modulation());
1629 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1630 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1631 SETCMD(DTV_INVERSION, dtp.Inversion());
1632 if (frontendType == SYS_DVBS2) {
1633 // DVB-S2
1634 SETCMD(DTV_PILOT, dtp.Pilot());
1635 SETCMD(DTV_ROLLOFF, dtp.RollOff());
1636 if (DvbApiVersion >= 0x0508)
1638 }
1639 else {
1640 // DVB-S
1641 SETCMD(DTV_ROLLOFF, ROLLOFF_35); // DVB-S always has a ROLLOFF of 0.35
1642 }
1643
1646 }
1647 else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
1648 // DVB-C
1649 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1650 SETCMD(DTV_INVERSION, dtp.Inversion());
1651 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1652 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1653 SETCMD(DTV_MODULATION, dtp.Modulation());
1654
1657 }
1658 else if (frontendType == SYS_DVBT || frontendType == SYS_DVBT2) {
1659 // DVB-T/DVB-T2 (common parts)
1660 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1661 SETCMD(DTV_INVERSION, dtp.Inversion());
1662 SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
1663 SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
1664 SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
1665 SETCMD(DTV_MODULATION, dtp.Modulation());
1666 SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
1667 SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
1668 SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
1669 if (frontendType == SYS_DVBT2) {
1670 // DVB-T2
1671 SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1672 if (DvbApiVersion >= 0x0508) {
1674 }
1675 else if (DvbApiVersion >= 0x0503)
1677 }
1680 }
1681 else if (frontendType == SYS_ATSC) {
1682 // ATSC
1683 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1684 SETCMD(DTV_INVERSION, dtp.Inversion());
1685 SETCMD(DTV_MODULATION, dtp.Modulation());
1686
1689 }
1690 else {
1691 esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
1692 return false;
1693 }
1694 SETCMD(DTV_TUNE, 0);
1695 if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1696 esyslog("ERROR: frontend %d/%d: %m (%s:%d)", adapter, frontend, __FILE__, __LINE__);
1697 return false;
1698 }
1699 return true;
1700}
1701
1703{
1704 cTimeMs Timer;
1705 bool LostLock = false;
1706 fe_status_t Status = (fe_status_t)0;
1707 while (Running()) {
1708 int WaitTime = 1000;
1709 fe_status_t NewStatus;
1710 if (GetFrontendStatus(NewStatus))
1711 Status = NewStatus;
1712 cMutexLock MutexLock(&mutex);
1713 switch (tunerStatus) {
1714 case tsIdle:
1715 break; // we want the TimedWait() below!
1716 case tsSet:
1718 continue;
1719 case tsPositioning:
1720 if (cPositioner *p = positioner) {
1721 if (p->IsMoving())
1722 break; // we want the TimedWait() below!
1723 else if (diseqcOffset) {
1724 lastDiseqc = NULL;
1725 tunerStatus = tsSet; // have it process the rest of the DiSEqC sequence
1726 continue;
1727 }
1728 }
1730 device->SectionHandler()->SetStatus(true); // may have been turned off when retuning
1731 Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT : 0));
1732 if (positioner)
1733 continue;
1734 // otherwise run directly into tsTuned...
1735 case tsTuned:
1736 if (Timer.TimedOut()) {
1738 lastDiseqc = NULL;
1739 lastSource = 0;
1740 if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
1741 if (channel.Number()) // no need to log this for transponders that are announced in the NIT but are not currently broadcasting
1742 isyslog("frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1743 lastTimeoutReport = time(NULL);
1744 }
1745 continue;
1746 }
1747 WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
1748 // run into tsLocked...
1749 case tsLocked:
1750 if (Status & FE_REINIT) {
1752 lastDiseqc = NULL;
1753 lastSource = 0;
1754 isyslog("frontend %d/%d was reinitialized", adapter, frontend);
1756 continue;
1757 }
1758 else if (Status & FE_HAS_LOCK) {
1759 if (LostLock) {
1760 isyslog("frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1761 LostLock = false;
1762 }
1763 if (device->SdtFilter()->TransponderWrong()) {
1764 isyslog("frontend %d/%d is not receiving transponder %d for channel %d (%s) - retuning", adapter, frontend, channel.Transponder(), channel.Number(), channel.Name());
1765 device->SectionHandler()->SetStatus(false);
1767 lastDiseqc = NULL;
1768 lastSource = 0;
1769 continue;
1770 }
1772 locked.Broadcast();
1774 }
1775 else if (tunerStatus == tsLocked) {
1776 LostLock = true;
1777 isyslog("frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1779 Timer.Set(lockTimeout);
1781 continue;
1782 }
1783 break;
1784 default: esyslog("ERROR: unknown tuner status %d", tunerStatus.load());
1785 }
1786 newSet.TimedWait(mutex, WaitTime);
1787 }
1788}
1789
1791{
1792 cMutexLock MutexLock(&mutex);
1793 if (On) {
1794 if (fd_frontend != -1) {
1795 dsyslog("closing frontend %d/%d", adapter, frontend);
1797 dvbFrontend->Close();
1798 fd_frontend = -1;
1799 channel = cChannel();
1800 }
1801 }
1802 else {
1803 if (fd_frontend == -1) {
1804 dsyslog("opening frontend %d/%d", adapter, frontend);
1806 lastDiseqc = NULL;
1807 lastSource = 0;
1808 lastUncValue = 0;
1809 lastUncDelta = 0;
1810 lastUncChange = 0;
1811 lnbPowerTurnedOn = false;
1812 }
1813 }
1814}
1815
1816// --- cDvbSourceParam -------------------------------------------------------
1817
1819private:
1823public:
1824 cDvbSourceParam(char Source, const char *Description);
1825 virtual void SetData(cChannel *Channel) override;
1826 virtual void GetData(cChannel *Channel) override;
1827 virtual cOsdItem *GetOsdItem(void) override;
1828 };
1829
1830cDvbSourceParam::cDvbSourceParam(char Source, const char *Description)
1831:cSourceParam(Source, Description)
1832{
1833 param = 0;
1834 srate = 0;
1835}
1836
1838{
1839 srate = Channel->Srate();
1840 dtp.Parse(Channel->Parameters());
1841 param = 0;
1842}
1843
1845{
1846 Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), srate, dtp.ToString(Source()), true);
1847}
1848
1850{
1851 char type = Source();
1852 const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr;
1853#undef ST
1854#define ST(s) if (strchr(s, type))
1855 switch (param++) {
1856 case 0: ST(" S ") return new cMenuEditChrItem( tr("Polarization"), &dtp.polarization, "HVLR"); else return GetOsdItem();
1857 case 1: ST(" ST") return new cMenuEditMapItem( tr("System"), &dtp.system, SystemValues); else return GetOsdItem();
1858 case 2: ST(" CS ") return new cMenuEditIntItem( tr("Srate"), &srate); else return GetOsdItem();
1859 case 3: ST("ACST") return new cMenuEditMapItem( tr("Inversion"), &dtp.inversion, InversionValues); else return GetOsdItem();
1860 case 4: ST(" CST") return new cMenuEditMapItem( tr("CoderateH"), &dtp.coderateH, CoderateValues); else return GetOsdItem();
1861 case 5: ST(" T") return new cMenuEditMapItem( tr("CoderateL"), &dtp.coderateL, CoderateValues); else return GetOsdItem();
1862 case 6: ST("ACST") return new cMenuEditMapItem( tr("Modulation"), &dtp.modulation, ModulationValues); else return GetOsdItem();
1863 case 7: ST(" T") return new cMenuEditMapItem( tr("Bandwidth"), &dtp.bandwidth, BandwidthValues); else return GetOsdItem();
1864 case 8: ST(" T") return new cMenuEditMapItem( tr("Transmission"), &dtp.transmission, TransmissionValues); else return GetOsdItem();
1865 case 9: ST(" T") return new cMenuEditMapItem( tr("Guard"), &dtp.guard, GuardValues); else return GetOsdItem();
1866 case 10: ST(" T") return new cMenuEditMapItem( tr("Hierarchy"), &dtp.hierarchy, HierarchyValues); else return GetOsdItem();
1867 case 11: ST(" S ") return new cMenuEditMapItem( tr("Rolloff"), &dtp.rollOff, RollOffValues); else return GetOsdItem();
1868 case 12: ST(" ST") return new cMenuEditIntItem( tr("StreamId"), &dtp.streamId, 0, 255); else return GetOsdItem();
1869 case 13: ST(" S ") return new cMenuEditMapItem( tr("Pilot"), &dtp.pilot, PilotValues); else return GetOsdItem();
1870 case 14: ST(" T") return new cMenuEditIntItem( tr("T2SystemId"), &dtp.t2systemId, 0, 65535); else return GetOsdItem();
1871 case 15: ST(" T") return new cMenuEditIntItem( tr("SISO/MISO"), &dtp.sisoMiso, 0, 1); else return GetOsdItem();
1872 default: return NULL;
1873 }
1874 return NULL;
1875}
1876
1877// --- cDvbDevice ------------------------------------------------------------
1878
1879bool cDvbDevice::useDvbDevices = true;
1882
1884{
1885 adapter = Adapter;
1887 ciAdapter = NULL;
1888 dvbTuner = NULL;
1889 bondedDevice = NULL;
1891 tsBuffer = NULL;
1892
1893 // Common Interface:
1894
1896 if (fd_ca >= 0)
1898 checkTsBuffer = false;
1899
1900 // The DVR device (will be opened and closed as needed):
1901
1902 fd_dvr = -1;
1903
1904 // We only check the devices that must be present - the others will be checked before accessing them://XXX
1905
1907
1908 dvbTuner = new cDvbTuner(this, adapter, frontend);
1909}
1910
1912{
1913 // Stop the device thread while the vptr still points to cDvbDevice. Its last
1914 // loop iteration calls the virtual CloseDvr(), and members are destroyed below.
1915 // Leaving this to ~cDevice() would be too late - the vptr is demoted by then:
1917 Cancel(3);
1918 delete dvbTuner;
1919 delete ciAdapter;
1921 UnBond();
1922 // We're not explicitly closing any device files here, since this sometimes
1923 // caused segfaults. Besides, the program is about to terminate anyway...
1924}
1925
1926cString DvbName(const char *Name, int Adapter, int Frontend)
1927{
1928 return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE, DEV_DVB_ADAPTER, Adapter, Name, Frontend);
1929}
1930
1931int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
1932{
1933 cString FileName = DvbName(Name, Adapter, Frontend);
1934 int fd = open(FileName, Mode);
1935 if (fd < 0 && ReportError)
1936 LOG_ERROR_STR(*FileName);
1937 return fd;
1938}
1939
1941{
1942 return dvbTuner ? dvbTuner->Frontend() : frontend;
1943}
1944
1946{
1948 if (access(FileName, F_OK) == 0) {
1949 int f = open(FileName, O_RDONLY);
1950 if (f >= 0) {
1951 close(f);
1952 return true;
1953 }
1954 else if (errno != ENODEV && errno != EINVAL)
1955 LOG_ERROR_STR(*FileName);
1956 }
1957 else if (errno != ENOENT)
1958 LOG_ERROR_STR(*FileName);
1959 return false;
1960}
1961
1963{
1965 dsyslog("probing %s", *FileName);
1966 for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
1967 if (dp->Probe(Adapter, Frontend))
1968 return true; // a plugin has created the actual device
1969 }
1970 dsyslog("creating cDvbDevice");
1971 new cDvbDevice(Adapter, Frontend); // it's a "budget" device
1972 return true;
1973}
1974
1976{
1977 if (dvbTuner)
1979 return "";
1980}
1981
1983{
1984 if (dvbTuner)
1985 return dvbTuner->FrontendName();
1986 return "";
1987}
1988
1990{
1991 new cDvbSourceParam('A', "ATSC");
1992 new cDvbSourceParam('C', "DVB-C");
1993 new cDvbSourceParam('S', "DVB-S");
1994 new cDvbSourceParam('T', "DVB-T");
1995 cStringList Nodes;
1996 cReadDir DvbDir(DEV_DVB_BASE);
1997 if (DvbDir.Ok()) {
1998 struct dirent *a;
1999 while ((a = DvbDir.Next()) != NULL) {
2000 if (strstr(a->d_name, DEV_DVB_ADAPTER) == a->d_name) {
2001 int Adapter = strtol(a->d_name + strlen(DEV_DVB_ADAPTER), NULL, 10);
2002 cReadDir AdapterDir(AddDirectory(DEV_DVB_BASE, a->d_name));
2003 if (AdapterDir.Ok()) {
2004 struct dirent *f;
2005 while ((f = AdapterDir.Next()) != NULL) {
2006 if (strstr(f->d_name, DEV_DVB_FRONTEND) == f->d_name) {
2007 int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND), NULL, 10);
2008 if (access(DvbName(DEV_DVB_DEMUX, Adapter, Frontend), F_OK) == 0) { // we only create devices for actual demuxes
2009 dsyslog("detected /dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
2010 Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
2011 }
2012 }
2013 }
2014 }
2015 }
2016 }
2017 }
2018 int Found = 0;
2019 int Used = 0;
2020 if (Nodes.Size() > 0) {
2021 Nodes.Sort();
2022 for (int i = 0; i < Nodes.Size(); i++) {
2023 int Adapter;
2024 int Frontend;
2025 if (2 == sscanf(Nodes[i], "%d %d", &Adapter, &Frontend)) {
2026 if (Exists(Adapter, Frontend)) {
2027 if (Found < MAXDEVICES) {
2028 Found++;
2030 if (Probe(Adapter, Frontend))
2031 Used++;
2032 }
2033 else {
2034 dsyslog("skipped /dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
2035 NextCardIndex(1); // skips this one
2036 }
2037 }
2038 }
2039 }
2040 }
2041 }
2042 if (Found > 0) {
2043 isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "");
2044 if (Used != Found)
2045 isyslog("using only %d DVB device%s", Used, Used != 1 ? "s" : "");
2046 }
2047 else
2048 isyslog("no DVB device found");
2049 return Found > 0;
2050}
2051
2052bool cDvbDevice::BondDevices(const char *Bondings)
2053{
2054 UnBondDevices();
2055 if (Bondings) {
2056 cSatCableNumbers SatCableNumbers(MAXDEVICES, Bondings);
2057 for (int i = 0; i < cDevice::NumDevices(); i++) {
2058 int d = SatCableNumbers.FirstDeviceIndex(i);
2059 if (d >= 0) {
2060 int ErrorDevice = 0;
2061 if (cDevice *Device1 = cDevice::GetDevice(i)) {
2062 if (cDevice *Device2 = cDevice::GetDevice(d)) {
2063 if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
2064 if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
2065 if (!DvbDevice1->Bond(DvbDevice2))
2066 return false; // Bond() has already logged the error
2067 }
2068 else
2069 ErrorDevice = d + 1;
2070 }
2071 else
2072 ErrorDevice = i + 1;
2073 if (ErrorDevice) {
2074 esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
2075 return false;
2076 }
2077 }
2078 else
2079 ErrorDevice = d + 1;
2080 }
2081 else
2082 ErrorDevice = i + 1;
2083 if (ErrorDevice) {
2084 esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
2085 return false;
2086 }
2087 }
2088 }
2089 }
2090 return true;
2091}
2092
2094{
2095 for (int i = 0; i < cDevice::NumDevices(); i++) {
2096 if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i)))
2097 d->UnBond();
2098 }
2099}
2100
2102{
2103 cMutexLock MutexLock(&bondMutex);
2104 if (!bondedDevice) {
2105 if (Device != this) {
2106 if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) {
2107 if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
2108 bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
2109 Device->bondedDevice = this;
2110 dsyslog("device %d bonded with device %d", DeviceNumber() + 1, bondedDevice->DeviceNumber() + 1);
2111 return true;
2112 }
2113 }
2114 else
2115 esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", DeviceNumber() + 1, Device->DeviceNumber() + 1);
2116 }
2117 else
2118 esyslog("ERROR: can't bond device %d with itself", DeviceNumber() + 1);
2119 }
2120 else
2121 esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", DeviceNumber() + 1, bondedDevice->DeviceNumber() + 1, Device->DeviceNumber() + 1);
2122 return false;
2123}
2124
2126{
2127 cMutexLock MutexLock(&bondMutex);
2128 if (cDvbDevice *d = bondedDevice) {
2129 if (dvbTuner)
2130 dvbTuner->UnBond();
2131 dsyslog("device %d unbonded from device %d", DeviceNumber() + 1, bondedDevice->DeviceNumber() + 1);
2132 while (d->bondedDevice != this)
2133 d = d->bondedDevice;
2134 if (d == bondedDevice)
2135 d->bondedDevice = NULL;
2136 else
2137 d->bondedDevice = bondedDevice;
2138 bondedDevice = NULL;
2139 }
2140}
2141
2142bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
2143{
2144 cMutexLock MutexLock(&bondMutex);
2145 if (bondedDevice || Positioner())
2146 return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
2147 return true;
2148}
2149
2151{
2152 return ciAdapter;
2153}
2154
2155bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
2156{
2157 if (Handle->pid) {
2158 dmx_pes_filter_params pesFilterParams;
2159 memset(&pesFilterParams, 0, sizeof(pesFilterParams));
2160 if (On) {
2161 if (Handle->handle < 0) {
2162 Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
2163 if (Handle->handle < 0) {
2164 LOG_ERROR;
2165 return false;
2166 }
2167 }
2168 pesFilterParams.pid = Handle->pid;
2169 pesFilterParams.input = DMX_IN_FRONTEND;
2170 pesFilterParams.output = DMX_OUT_TS_TAP;
2171 pesFilterParams.pes_type= DMX_PES_OTHER;
2172 pesFilterParams.flags = DMX_IMMEDIATE_START;
2173 if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
2174 LOG_ERROR;
2175 return false;
2176 }
2177 }
2178 else if (!Handle->used) {
2179 CHECK(ioctl(Handle->handle, DMX_STOP));
2180 if (Type <= ptTeletext) {
2181 pesFilterParams.pid = 0x1FFF;
2182 pesFilterParams.input = DMX_IN_FRONTEND;
2183 pesFilterParams.output = DMX_OUT_DECODER;
2184 pesFilterParams.pes_type= DMX_PES_OTHER;
2185 pesFilterParams.flags = DMX_IMMEDIATE_START;
2186 CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
2187 }
2188 close(Handle->handle);
2189 Handle->handle = -1;
2190 }
2191 }
2192 return true;
2193}
2194
2195#define RB_NUM_SECTIONS 8 // default: 2 sections = 8192 bytes
2196
2197int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
2198{
2200 int f = open(FileName, O_RDWR | O_NONBLOCK);
2201 if (f >= 0) {
2202 if (Pid == EITPID) { // increase ringbuffer size for EIT
2203 if (ioctl(f, DMX_SET_BUFFER_SIZE, MAX_SECTION_SIZE * RB_NUM_SECTIONS) < 0)
2204 dsyslog("OpenFilter (pid=%d, tid=%02X): ioctl DMX_SET_BUFFER_SIZE failed", Pid, Tid);
2205 }
2206 dmx_sct_filter_params sctFilterParams;
2207 memset(&sctFilterParams, 0, sizeof(sctFilterParams));
2208 sctFilterParams.pid = Pid;
2209 sctFilterParams.timeout = 0;
2210 sctFilterParams.flags = DMX_IMMEDIATE_START;
2211 sctFilterParams.filter.filter[0] = Tid;
2212 sctFilterParams.filter.mask[0] = Mask;
2213 if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
2214 return f;
2215 else {
2216 esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
2217 close(f);
2218 }
2219 }
2220 else
2221 esyslog("ERROR: can't open filter handle on '%s'", *FileName);
2222 return -1;
2223}
2224
2226{
2227 close(Handle);
2228}
2229
2230bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
2231{
2232 return dvbTuner->ProvidesDeliverySystem(DeliverySystem);
2233}
2234
2235bool cDvbDevice::ProvidesSource(int Source) const
2236{
2237 int type = Source & cSource::st_Mask;
2238 return type == cSource::stNone
2239 || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
2240 || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
2241 || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
2243}
2244
2246{
2247 if (!ProvidesSource(Channel->Source()))
2248 return false; // doesn't provide source
2249 if (!dvbTuner->ProvidesFrontend(Channel))
2250 return false; // requires modulation system which frontend doesn't provide
2251 cDvbTransponderParameters dtp(Channel->Parameters());
2252 if (!cSource::IsSat(Channel->Source()) ||
2253 (!Setup.DiSEqC || Diseqcs.Get(DeviceNumber() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
2254 return DeviceHooksProvidesTransponder(Channel);
2255 return false;
2256}
2257
2258bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
2259{
2260 bool result = false;
2261 bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
2262 bool needsDetachReceivers = false;
2264
2265 if (ProvidesTransponder(Channel)) {
2266 result = hasPriority;
2267 if (Priority > IDLEPRIORITY) {
2268 if (Receiving()) {
2269 if (dvbTuner->IsTunedTo(Channel)) {
2270 if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0)) || Channel->Dpid(0) && !HasPid(Channel->Dpid(0))) {
2271 if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
2272 if (CamSlot()->CanDecrypt(Channel))
2273 result = true;
2274 else
2275 needsDetachReceivers = true;
2276 }
2277 else
2278 result = true;
2279 }
2280 else
2281 result = true;
2282 }
2283 else
2284 needsDetachReceivers = Receiving();
2285 }
2286 if (result) {
2287 cMutexLock MutexLock(&bondMutex);
2288 if (!BondingOk(Channel)) {
2289 // This device is bonded, so we need to check the priorities of the others:
2290 for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
2291 if (d->Priority() >= Priority) {
2292 result = false;
2293 break;
2294 }
2295 needsDetachReceivers |= d->Receiving();
2296 }
2298 needsDetachReceivers |= Receiving();
2299 }
2300 }
2301 }
2302 }
2303 if (NeedsDetachReceivers)
2304 *NeedsDetachReceivers = needsDetachReceivers;
2305 return result;
2306}
2307
2309{
2310 return dvbTuner != NULL && DeviceHooksProvidesEIT();
2311}
2312
2314{
2315 return dvbTuner ? dvbTuner->NumProvidedSystems() : 0;
2316}
2317
2319{
2320 return dvbTuner ? dvbTuner->Positioner() : NULL;
2321}
2322
2323bool cDvbDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
2324{
2325 return dvbTuner ? dvbTuner->GetSignalStats(Valid, Strength, Cnr, BerPre, BerPost, Per, Status) : false;
2326}
2327
2329{
2330 return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
2331}
2332
2334{
2335 return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
2336}
2337
2339{
2340 return dvbTuner ? dvbTuner->GetTransponder() : NULL;
2341}
2342
2344{
2345 return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
2346}
2347
2349{
2350 return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
2351}
2352
2354{
2356}
2357
2358bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
2359{
2360 if (dvbTuner->ProvidesFrontend(Channel, true)) {
2361 dvbTuner->SetChannel(Channel);
2362 return true;
2363 }
2364 return false;
2365}
2366
2367bool cDvbDevice::HasLock(int TimeoutMs) const
2368{
2369 return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
2370}
2371
2376
2378{
2379 CloseDvr();
2380 fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
2381 if (fd_dvr >= 0)
2383 return fd_dvr >= 0;
2384}
2385
2387{
2388 if (fd_dvr >= 0) {
2389 delete tsBuffer;
2390 tsBuffer = NULL;
2391 close(fd_dvr);
2392 fd_dvr = -1;
2393 }
2394}
2395
2397{
2398 if (tsBuffer) {
2399 if (cCamSlot *cs = CamSlot()) {
2400 if (cs->WantsTsData()) {
2401 int Available;
2402 Data = tsBuffer->Get(&Available, checkTsBuffer);
2403 if (!Data)
2404 Available = 0;
2405 Data = cs->Decrypt(Data, Available);
2406 tsBuffer->Skip(Available);
2407 checkTsBuffer = Data != NULL;
2408 return true;
2409 }
2410 }
2411 Data = tsBuffer->Get();
2412 return true;
2413 }
2414 return false;
2415}
2416
2418{
2419 cMutexLock MutexLock(&bondMutex);
2420 cDvbDevice *d = this;
2421 do {
2422 d->cDevice::DetachAllReceivers();
2423 d = d->bondedDevice;
2424 } while (d && d != this && needsDetachBondedReceivers);
2426}
2427
2428// --- cDvbDeviceProbe -------------------------------------------------------
2429
2431
2433{
2434 DvbDeviceProbes.Add(this);
2435}
2436
2438{
2439 DvbDeviceProbes.Del(this, false);
2440}
2441
2442uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
2443{
2444 uint32_t SubsystemId = 0;
2445 cString FileName = cString::sprintf("/dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
2446 struct stat st;
2447 if (stat(FileName, &st) == 0) {
2448 cReadDir d("/sys/class/dvb");
2449 if (d.Ok()) {
2450 struct dirent *e;
2451 while ((e = d.Next()) != NULL) {
2452 if (strstr(e->d_name, "frontend")) {
2453 FileName = cString::sprintf("/sys/class/dvb/%s/dev", e->d_name);
2454 if (FILE *f = fopen(FileName, "r")) {
2455 cReadLine ReadLine;
2456 char *s = ReadLine.Read(f);
2457 fclose(f);
2458 unsigned Major;
2459 unsigned Minor;
2460 if (s && 2 == sscanf(s, "%u:%u", &Major, &Minor)) {
2461 if (((Major << 8) | Minor) == st.st_rdev) {
2462 FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
2463 if ((f = fopen(FileName, "r")) != NULL) {
2464 if (char *s = ReadLine.Read(f))
2465 SubsystemId = strtoul(s, NULL, 0) << 16;
2466 fclose(f);
2467 }
2468 else {
2469 FileName = cString::sprintf("/sys/class/dvb/%s/device/idVendor", e->d_name);
2470 if ((f = fopen(FileName, "r")) != NULL) {
2471 if (char *s = ReadLine.Read(f))
2472 SubsystemId = strtoul(s, NULL, 16) << 16;
2473 fclose(f);
2474 }
2475 }
2476 FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_device", e->d_name);
2477 if ((f = fopen(FileName, "r")) != NULL) {
2478 if (char *s = ReadLine.Read(f))
2479 SubsystemId |= strtoul(s, NULL, 0);
2480 fclose(f);
2481 }
2482 else {
2483 FileName = cString::sprintf("/sys/class/dvb/%s/device/idProduct", e->d_name);
2484 if ((f = fopen(FileName, "r")) != NULL) {
2485 if (char *s = ReadLine.Read(f))
2486 SubsystemId |= strtoul(s, NULL, 16);
2487 fclose(f);
2488 }
2489 }
2490 break;
2491 }
2492 }
2493 }
2494 }
2495 }
2496 }
2497 }
2498 return SubsystemId;
2499}
#define CA_ENCRYPTED_MIN
Definition channels.h:44
Definition ci.h:233
int Vpid(void) const
Definition channels.h:154
int Source(void) const
Definition channels.h:152
int Number(void) const
Definition channels.h:187
const char * Name(void) const
Definition channels.c:121
int Dpid(int i) const
Definition channels.h:161
int Apid(int i) const
Definition channels.h:160
const char * Parameters(void) const
Definition channels.h:190
int Ca(int Index=0) const
Definition channels.h:181
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
Definition channels.h:149
bool IsSat(void) const
Definition channels.h:196
bool IsCable(void) const
Definition channels.h:195
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
Definition channels.c:188
bool IsTerr(void) const
Definition channels.h:197
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition channels.c:154
int Srate(void) const
Definition channels.h:153
bool IsAtsc(void) const
Definition channels.h:194
cChannel(void)
Definition channels.c:56
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition thread.c:135
void Broadcast(void)
Definition thread.c:155
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition device.c:156
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition device.c:703
int Priority(bool IgnoreOccupied=false) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition device.c:1807
static bool UseDevice(int n)
Tells whether the device with the given card index shall be used in this instance of VDR.
Definition device.h:141
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition device.c:692
@ ptTeletext
Definition device.h:410
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition device.c:559
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
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...
Definition device.c:832
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:237
cDevice(void)
Definition device.c:80
bool DeviceHooksProvidesEIT(void) const
Definition device.c:762
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:168
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition device.h:223
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition device.c:1827
const cSdtFilter * SdtFilter(void) const
Definition device.h:473
cSectionHandler * SectionHandler(void) const
Definition device.h:474
static int NumDevices(void)
Returns the total number of devices.
Definition device.h:129
cCamSlot * CamSlot(void) const
Returns the CAM slot that is currently used with this device, or NULL if no CAM slot is in use.
Definition device.h:493
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition device.c:683
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition device.c:751
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.
Definition diseqc.c:402
int Position(void) const
Indicates which positioning mode to use in order to move the dish to a given satellite position.
Definition diseqc.h:126
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
Definition diseqc.h:132
eDiseqcActions
Definition diseqc.h:64
@ daMiniB
Definition diseqc.h:71
@ daNone
Definition diseqc.h:65
@ daPositionN
Definition diseqc.h:72
@ daMiniA
Definition diseqc.h:70
@ daCodes
Definition diseqc.h:75
@ daVoltage13
Definition diseqc.h:68
@ daWait
Definition diseqc.h:76
@ daToneOff
Definition diseqc.h:66
@ daToneOn
Definition diseqc.h:67
@ daVoltage18
Definition diseqc.h:69
@ daPositionA
Definition diseqc.h:73
@ daScr
Definition diseqc.h:74
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.
Definition diseqc.c:447
static cDvbCiAdapter * CreateCiAdapter(cDevice *Device, int Fd)
Definition dvbci.c:102
cDvbDeviceProbe(void)
Definition dvbdevice.c:2432
virtual ~cDvbDeviceProbe() override
Definition dvbdevice.c:2437
static uint32_t GetSubsystemId(int Adapter, int Frontend)
Definition dvbdevice.c:2442
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
Definition dvbdevice.h:168
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const override
Returns true if this device can provide the given channel.
Definition dvbdevice.c:2258
static void UnBondDevices(void)
Unbonds all devices.
Definition dvbdevice.c:2093
virtual bool ProvidesTransponder(const cChannel *Channel) const override
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
Definition dvbdevice.c:2245
static void SetTransferModeForDolbyDigital(int Mode)
Definition dvbdevice.c:2372
virtual bool OpenDvr(void) override
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver.
Definition dvbdevice.c:2377
cDvbDevice(int Adapter, int Frontend)
Definition dvbdevice.c:1883
virtual cString DeviceType(void) const override
Returns a string identifying the type of this device (like "DVB-S").
Definition dvbdevice.c:1975
virtual const cPositioner * Positioner(void) const override
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition dvbdevice.c:2318
virtual const cChannel * GetCurrentlyTunedTransponder(void) const override
Returns a pointer to the currently tuned transponder.
Definition dvbdevice.c:2338
virtual cString DeviceName(void) const override
Returns a string identifying the name of this device.
Definition dvbdevice.c:1982
virtual void CloseDvr(void) override
Shuts down the DVR.
Definition dvbdevice.c:2386
static bool Exists(int Adapter, int Frontend)
Checks whether the given adapter/frontend exists.
Definition dvbdevice.c:1945
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition dvbdevice.c:2052
static bool useDvbDevices
Definition dvbdevice.h:175
bool checkTsBuffer
Definition dvbdevice.h:185
cCiAdapter * ciAdapter
Definition dvbdevice.h:227
virtual bool MaySwitchTransponder(const cChannel *Channel) const override
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
Definition dvbdevice.c:2348
cDvbTuner * dvbTuner
Definition dvbdevice.h:232
static bool Initialize(void)
Initializes the DVB devices.
Definition dvbdevice.c:1989
void UnBond(void)
Removes this device from any bonding it might have with other devices.
Definition dvbdevice.c:2125
virtual bool GetTSPacket(uchar *&Data) override
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data.
Definition dvbdevice.c:2396
static cMutex bondMutex
Definition dvbdevice.h:186
virtual int NumProvidedSystems(void) const override
Returns the number of individual "delivery systems" this device provides.
Definition dvbdevice.c:2313
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 ...
Definition dvbdevice.c:2142
virtual void DetachAllReceivers(void) override
Detaches all receivers from this device.
Definition dvbdevice.c:2417
cTSBuffer * tsBuffer
< Controls how the DVB device handles Transfer Mode when replaying Dolby Digital audio.
Definition dvbdevice.h:284
virtual bool SetPid(cPidHandle *Handle, int Type, bool On) override
Does the actual PID setting on this device.
Definition dvbdevice.c:2155
bool needsDetachBondedReceivers
Definition dvbdevice.h:188
virtual bool HasLock(int TimeoutMs=0) const override
Returns true if the device has a lock on the requested transponder.
Definition dvbdevice.c:2367
static int setTransferModeForDolbyDigital
Definition dvbdevice.h:272
virtual bool ProvidesSource(int Source) const override
Returns true if this device can provide the given source.
Definition dvbdevice.c:2235
int Frontend(void) const
Definition dvbdevice.c:1940
virtual int SignalQuality(void) const override
Returns the "quality" of the currently received signal.
Definition dvbdevice.c:2333
bool Bond(cDvbDevice *Device)
Bonds this device with the given Device, making both of them use the same satellite cable and LNB.
Definition dvbdevice.c:2101
virtual bool ProvidesDeliverySystem(int DeliverySystem) const
Definition dvbdevice.c:2230
virtual void CloseFilter(int Handle) override
Closes a file handle that has previously been opened by OpenFilter().
Definition dvbdevice.c:2225
virtual int SignalStrength(void) const override
Returns the "strength" of the currently received signal.
Definition dvbdevice.c:2328
virtual bool ProvidesEIT(void) const override
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...
Definition dvbdevice.c:2308
virtual bool IsTunedToTransponder(const cChannel *Channel) const override
Returns true if this device is currently tuned to the given Channel's transponder.
Definition dvbdevice.c:2343
cDvbDevice * bondedDevice
Definition dvbdevice.h:187
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView) override
Sets the device to the given channel (actual physical setup).
Definition dvbdevice.c:2358
virtual ~cDvbDevice() override
Definition dvbdevice.c:1911
static bool Probe(int Adapter, int Frontend)
Probes for existing DVB devices.
Definition dvbdevice.c:1962
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const override
Returns statistics about the currently received signal (if available).
Definition dvbdevice.c:2323
virtual bool HasCi(void) override
Returns true if this device has a Common Interface.
Definition dvbdevice.c:2150
int Adapter(void) const
Definition dvbdevice.h:192
virtual void SetPowerSaveMode(bool On) override
Puts the device into power save mode, if applicable.
Definition dvbdevice.c:2353
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask) override
Opens a file handle for the given filter data.
Definition dvbdevice.c:2197
int Open(void)
Definition dvbdevice.c:386
uint32_t subsystemId
Definition dvbdevice.c:349
bool ProvidesModulation(int System, int StreamId, int Modulation) const
Definition dvbdevice.c:411
uint32_t SubsystemId(void) const
Definition dvbdevice.c:364
int NumDeliverySystems(void) const
Definition dvbdevice.c:362
const char * FrontendName(void)
Definition dvbdevice.c:359
cDvbFrontend(int Adapter, int Frontend)
Definition dvbdevice.c:367
int NumModulations(void) const
Definition dvbdevice.c:363
bool ProvidesDeliverySystem(int DeliverySystem) const
Definition dvbdevice.c:402
int numModulations
Definition dvbdevice.c:352
void Close(void)
Definition dvbdevice.c:393
cVector< int > deliverySystems
Definition dvbdevice.c:351
bool QueryDeliverySystems(void)
Definition dvbdevice.c:429
dvb_frontend_info frontendInfo
Definition dvbdevice.c:350
cDvbSourceParam(char Source, const char *Description)
Definition dvbdevice.c:1830
virtual cOsdItem * GetOsdItem(void) override
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
Definition dvbdevice.c:1849
cDvbTransponderParameters dtp
Definition dvbdevice.c:1822
virtual void GetData(cChannel *Channel) override
Copies all source specific parameters to the given Channel.
Definition dvbdevice.c:1844
virtual void SetData(cChannel *Channel) override
Sets all source specific parameters to those of the given Channel.
Definition dvbdevice.c:1837
int StreamId(void) const
Definition dvbdevice.h:138
cString ToString(char Type) const
Definition dvbdevice.c:217
const char * ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map=NULL)
Definition dvbdevice.c:241
char Polarization(void) const
Definition dvbdevice.h:127
int Guard(void) const
Definition dvbdevice.h:135
bool Parse(const char *s)
Definition dvbdevice.c:257
int Pilot(void) const
Definition dvbdevice.h:141
int PrintParameter(char *p, char Name, int Value) const
Definition dvbdevice.c:212
int RollOff(void) const
Definition dvbdevice.h:137
int CoderateL(void) const
Definition dvbdevice.h:131
int Transmission(void) const
Definition dvbdevice.h:134
int Bandwidth(void) const
Definition dvbdevice.h:129
int System(void) const
Definition dvbdevice.h:133
int Inversion(void) const
Definition dvbdevice.h:128
cDvbTransponderParameters(const char *Parameters=NULL)
Definition dvbdevice.c:207
int Modulation(void) const
Definition dvbdevice.h:132
int Hierarchy(void) const
Definition dvbdevice.h:136
int CoderateH(void) const
Definition dvbdevice.h:130
std::atomic< int > frontendType
Definition dvbdevice.c:536
int diseqcOffset
Definition dvbdevice.c:553
void UnBond(void)
Definition dvbdevice.c:729
int frontend
Definition dvbdevice.c:540
void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
Definition dvbdevice.c:1497
time_t lastUncChange
Definition dvbdevice.c:550
bool Bond(cDvbTuner *Tuner)
Definition dvbdevice.c:713
cCondVar newSet
Definition dvbdevice.c:561
int lockTimeout
Definition dvbdevice.c:546
bool lnbPowerTurnedOn
Definition dvbdevice.c:557
bool SetFrontend(void)
Definition dvbdevice.c:1562
void ClearEventQueue(void) const
Definition dvbdevice.c:855
cChannel channel
Definition dvbdevice.c:551
int NumProvidedSystems(void) const
Definition dvbdevice.c:583
void SetChannel(const cChannel *Channel)
Definition dvbdevice.c:810
cDvbTuner(const cDvbDevice *Device, int Adapter, int Frontend)
Definition dvbdevice.c:601
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
Definition dvbdevice.c:762
void ResetToneAndVoltage(void)
Definition dvbdevice.c:1554
cPositioner * GetPositioner(void)
Definition dvbdevice.c:1486
const cScr * scr
Definition dvbdevice.c:556
cString GetBondingParams(const cChannel *Channel=NULL) const
Definition dvbdevice.c:745
std::atomic< eTunerStatus > tunerStatus
Definition dvbdevice.c:558
bool Locked(int TimeoutMs=0)
Definition dvbdevice.c:843
int GetSignalQuality(void) const
Definition dvbdevice.c:1304
uint32_t lastUncValue
Definition dvbdevice.c:548
int adapter
Definition dvbdevice.c:539
bool ProvidesModulation(int System, int StreamId, int Modulation) const
Definition dvbdevice.c:678
const cPositioner * Positioner(void) const
Definition dvbdevice.c:592
uint32_t lastUncDelta
Definition dvbdevice.c:549
cVector< cDvbFrontend * > dvbFrontends
Definition dvbdevice.c:541
bool IsBondedMaster(void) const
Definition dvbdevice.c:566
cDvbTuner * GetBondedMaster(void)
Definition dvbdevice.c:778
int tuneTimeout
Definition dvbdevice.c:545
uint32_t SubsystemId(void) const
Definition dvbdevice.c:588
int Frontend(void) const
Definition dvbdevice.c:580
bool GetSignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Definition dvbdevice.c:884
bool bondedMaster
Definition dvbdevice.c:563
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition dvbdevice.c:1702
int fd_frontend
Definition dvbdevice.c:538
bool ProvidesFrontend(const cChannel *Channel, bool Activate=false) const
Definition dvbdevice.c:687
int FrontendType(void) const
Definition dvbdevice.c:581
int lastSource
Definition dvbdevice.c:554
bool IsTunedTo(const cChannel *Channel) const
Definition dvbdevice.c:799
@ tsPositioning
Definition dvbdevice.c:535
virtual ~cDvbTuner() override
Definition dvbdevice.c:652
cDvbFrontend * dvbFrontend
Definition dvbdevice.c:542
static cMutex bondMutex
Definition dvbdevice.c:534
const cDiseqc * lastDiseqc
Definition dvbdevice.c:552
time_t lastTimeoutReport
Definition dvbdevice.c:547
cMutex mutex
Definition dvbdevice.c:559
const cDvbDevice * device
Definition dvbdevice.c:537
std::atomic< cPositioner * > positioner
Definition dvbdevice.c:555
void SetPowerSaveMode(bool On)
Definition dvbdevice.c:1790
int GetSignalStrength(void) const
Definition dvbdevice.c:1236
bool ProvidesDeliverySystem(int DeliverySystem) const
Definition dvbdevice.c:669
cCondVar locked
Definition dvbdevice.c:560
cDvbTuner * bondedTuner
Definition dvbdevice.c:562
bool GetFrontendStatus(fe_status_t &Status) const
Definition dvbdevice.c:865
const cChannel * GetTransponder(void) const
Definition dvbdevice.c:587
int numModulations
Definition dvbdevice.c:544
int numDeliverySystems
Definition dvbdevice.c:543
const char * FrontendName(void)
Definition dvbdevice.c:582
Definition tools.h:650
cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
Definition menuitems.c:336
cMenuEditIntItem(const char *Name, int *Value, int Min=0, int Max=INT_MAX, const char *MinString=NULL, const char *MaxString=NULL)
Definition menuitems.c:66
cMenuEditMapItem(const char *Name, int *Value, const tDvbParameterMap *Map, const char *ZeroString=NULL)
Definition menuitems.c:1194
bool Lock(int TimeoutMs=0, bool *TimedOut=NULL)
Returns true if the mutex was successfully locked.
Definition thread.c:228
void Unlock(void)
Definition thread.c:252
bool Poll(int TimeoutMs=0)
Definition tools.c:1632
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition positioner.c:133
void SetFrontend(int Frontend)
This function is called whenever the positioner is connected to a DVB frontend.
Definition positioner.h:89
virtual bool IsMoving(void) const
Returns true if the dish is currently moving as a result of a call to GotoPosition() or GotoAngle().
Definition positioner.c:127
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
Definition positioner.c:100
virtual void GotoAngle(int Longitude)
Move the dish to the given angular position.
Definition positioner.c:107
struct dirent * Next(void)
Definition tools.c:1657
bool Ok(void)
Definition tools.h:476
char * Read(FILE *f)
Definition tools.c:1574
int FirstDeviceIndex(int DeviceIndex) const
Returns the first device index (starting at 0) that uses the same sat cable number as the device with...
Definition config.c:117
Definition diseqc.h:34
bool TransponderWrong(void) const
Definition sdt.h:35
void SetStatus(bool On)
Definition sections.c:147
int LnbSLOF
Definition config.h:282
int LnbFrequLo
Definition config.h:283
int DiSEqC
Definition config.h:285
int LnbFrequHi
Definition config.h:284
char Source(void) const
cSourceParam(char Source, const char *Description)
Sets up a parameter handler for the given Source.
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise).
Definition sources.h:35
static bool IsSat(int Code)
Definition sources.h:57
@ st_Mask
Definition sources.h:23
@ stCable
Definition sources.h:20
@ stSat
Definition sources.h:21
@ stNone
Definition sources.h:18
@ stAtsc
Definition sources.h:19
@ stTerr
Definition sources.h:22
void Sort(bool IgnoreCase=false)
Definition tools.h:866
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1242
cTSBuffer(int File, int Size, int DeviceNumber)
Definition device.c:2044
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition device.c:2085
void Skip(int Count)
If after a call to Get() more or less than TS_SIZE of the available data has been processed,...
Definition device.c:2115
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition thread.c:330
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition thread.c:293
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition thread.h:110
cThread(const char *Description=NULL, bool LowPriority=false)
Creates a new thread.
Definition thread.c:264
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition thread.c:380
void Set(int Ms=0)
Sets the timer.
Definition tools.c:842
bool TimedOut(void) const
Returns true if the number of milliseconds given in the last call to Set() have passed.
Definition tools.c:850
int Size(void) const
Definition tools.h:773
virtual void Clear(void)
Definition tools.h:828
virtual void Append(T Data)
Definition tools.h:794
cSetup Setup
Definition config.c:373
#define IDLEPRIORITY
Definition config.h:45
#define DTV_STAT_HAS_NONE
Definition device.h:112
#define DTV_STAT_HAS_VITERBI
Definition device.h:115
#define DTV_STAT_VALID_STRENGTH
Definition device.h:105
#define DTV_STAT_VALID_BERPRE
Definition device.h:107
#define DTV_STAT_VALID_NONE
The cDevice class is the base from which actual devices can be derived.
Definition device.h:104
#define DTV_STAT_VALID_PER
Definition device.h:109
#define MAXDEVICES
Definition device.h:29
#define DTV_STAT_HAS_CARRIER
Definition device.h:114
#define DTV_STAT_VALID_CNR
Definition device.h:106
#define DTV_STAT_HAS_LOCK
Definition device.h:117
#define DTV_STAT_VALID_BERPOST
Definition device.h:108
#define DTV_STAT_HAS_SYNC
Definition device.h:116
#define DTV_STAT_HAS_SIGNAL
Definition device.h:113
#define DTV_STAT_VALID_STATUS
Definition device.h:110
cDiseqcs Diseqcs
Definition diseqc.c:439
int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
Definition dvbdevice.c:1931
int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
Definition dvbdevice.c:1094
static const int DeliverySystemNamesMax
Definition dvbdevice.c:327
const tDvbParameterMap CoderateValues[]
Definition dvbdevice.c:68
int dB1000toPercent(int dB1000, int Low, int High)
Definition dvbdevice.c:996
#define DVB_SYSTEM_1
Definition dvbdevice.c:101
const tDvbParameterMap PilotValues[]
Definition dvbdevice.c:43
int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
Definition dvbdevice.c:1017
#define REF_T2(q1, q2, q3, q4)
Definition dvbdevice.c:1014
const tDvbParameterMap GuardValues[]
Definition dvbdevice.c:127
#define DVBC_LOCK_TIMEOUT
Definition dvbdevice.c:31
const tDvbParameterMap SystemValuesSat[]
Definition dvbdevice.c:104
#define SETCMD(c, d)
Definition dvbdevice.c:337
const tDvbParameterMap HierarchyValues[]
Definition dvbdevice.c:139
#define DVBC_TUNE_TIMEOUT
Definition dvbdevice.c:30
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:167
#define REF_C1(q1, q2, q3, q4, q5)
Definition dvbdevice.c:1015
cString DvbName(const char *Name, int Adapter, int Frontend)
Definition dvbdevice.c:1926
#define SCR_RANDOM_TIMEOUT
Definition dvbdevice.c:37
#define RB_NUM_SECTIONS
Definition dvbdevice.c:2195
#define ST(s)
#define BANDWIDTH_HZ_AUTO
Definition dvbdevice.c:26
#define REF_S2(q1, q2, q3, q4)
Definition dvbdevice.c:1012
#define TSBUFFERSIZE
Definition dvbdevice.c:39
const tDvbParameterMap BandwidthValues[]
Definition dvbdevice.c:57
#define DVB_SYSTEM_2
Definition dvbdevice.c:102
static const char * GetDeliverySystemName(int Index)
Definition dvbdevice.c:329
#define TUNER_POLL_TIMEOUT
Definition dvbdevice.c:514
#define LOCK_THRESHOLD
Definition dvbdevice.c:1302
cList< cDvbDeviceProbe > DvbDeviceProbes
Definition dvbdevice.c:2430
#define MAXFRONTENDCMDS
Definition dvbdevice.c:336
const tDvbParameterMap TransmissionValues[]
Definition dvbdevice.c:116
const tDvbParameterMap InversionValues[]
Definition dvbdevice.c:50
static unsigned int FrequencyToHz(unsigned int f)
Definition dvbdevice.c:1479
#define ATSC_TUNE_TIMEOUT
Definition dvbdevice.c:34
const tDvbParameterMap RollOffValues[]
Definition dvbdevice.c:148
const tDvbParameterMap ModulationValues[]
Definition dvbdevice.c:84
const tDvbParameterMap SystemValuesTerr[]
Definition dvbdevice.c:110
#define REF_S1(q1)
Definition dvbdevice.c:1011
#define DVBT_TUNE_TIMEOUT
Definition dvbdevice.c:32
int UserIndex(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:156
#define REF_T1(q1, q2, q3)
Definition dvbdevice.c:1013
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
Definition dvbdevice.c:516
static int DvbApiVersion
Definition dvbdevice.c:24
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition dvbdevice.c:178
const char * MapToUserString(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:189
#define ATSC_LOCK_TIMEOUT
Definition dvbdevice.c:35
#define DVBS_LOCK_TIMEOUT
Definition dvbdevice.c:29
const char * DeliverySystemNames[]
Definition dvbdevice.c:303
int MapToDriver(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:197
#define BER_ERROR_FREE
Definition dvbdevice.c:1092
#define DVBS_TUNE_TIMEOUT
Definition dvbdevice.c:28
#define DVBT_LOCK_TIMEOUT
Definition dvbdevice.c:33
#define DEV_DVB_BASE
Definition dvbdevice.h:71
#define DEV_DVB_DVR
Definition dvbdevice.h:75
const tDvbParameterMap CoderateValues[]
Definition dvbdevice.c:68
@ SYS_DVBT2
Definition dvbdevice.h:52
const tDvbParameterMap PilotValues[]
Definition dvbdevice.c:43
const tDvbParameterMap GuardValues[]
Definition dvbdevice.c:127
#define DEV_DVB_DEMUX
Definition dvbdevice.h:76
@ FE_CAN_MULTISTREAM
Definition dvbdevice.h:62
const tDvbParameterMap SystemValuesSat[]
Definition dvbdevice.c:104
int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError=false)
Definition dvbdevice.c:1931
const tDvbParameterMap HierarchyValues[]
Definition dvbdevice.c:139
@ FE_CAN_TURBO_FEC
Definition dvbdevice.h:36
@ TRANSMISSION_MODE_4K
Definition dvbdevice.h:30
#define DTV_ENUM_DELSYS
Definition dvbdevice.h:57
#define DEV_DVB_ADAPTER
Definition dvbdevice.h:72
cString DvbName(const char *Name, int Adapter, int Frontend)
Definition dvbdevice.c:1926
#define DTV_STREAM_ID
Definition dvbdevice.h:64
@ FE_CAN_2G_MODULATION
Definition dvbdevice.h:27
#define DEV_DVB_CA
Definition dvbdevice.h:79
@ GUARD_INTERVAL_19_128
Definition dvbdevice.h:48
@ GUARD_INTERVAL_19_256
Definition dvbdevice.h:49
@ GUARD_INTERVAL_1_128
Definition dvbdevice.h:47
const tDvbParameterMap BandwidthValues[]
Definition dvbdevice.c:57
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String=NULL)
Definition dvbdevice.c:178
cList< cDvbDeviceProbe > DvbDeviceProbes
Definition dvbdevice.c:2430
const tDvbParameterMap TransmissionValues[]
Definition dvbdevice.c:116
const tDvbParameterMap InversionValues[]
Definition dvbdevice.c:50
@ TRANSMISSION_MODE_16K
Definition dvbdevice.h:43
@ TRANSMISSION_MODE_1K
Definition dvbdevice.h:42
@ TRANSMISSION_MODE_32K
Definition dvbdevice.h:44
const tDvbParameterMap RollOffValues[]
Definition dvbdevice.c:148
const tDvbParameterMap ModulationValues[]
Definition dvbdevice.c:84
#define DVBAPIVERSION
Definition dvbdevice.h:17
#define DTV_DVBT2_PLP_ID_LEGACY
Definition dvbdevice.h:65
#define DEV_DVB_FRONTEND
Definition dvbdevice.h:74
int MapToDriver(int Value, const tDvbParameterMap *Map)
Definition dvbdevice.c:197
#define tr(s)
Definition i18n.h:85
#define trNOOP(s)
Definition i18n.h:88
#define MAX_SECTION_SIZE
Definition remux.h:295
#define EITPID
Definition remux.h:54
const char * userString
Definition dvbdevice.h:84
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:128
cString AddDirectory(const char *DirName, const char *FileName)
Definition tools.c:445
T constrain(T v, T l, T h)
Definition tools.h:70
#define LOG_ERROR_STR(s)
Definition tools.h:40
unsigned char uchar
Definition tools.h:31
#define CHECK(s)
Definition tools.h:51
#define dsyslog(a...)
Definition tools.h:37
T min(T a, T b)
Definition tools.h:63
#define esyslog(a...)
Definition tools.h:35
#define LOG_ERROR
Definition tools.h:39
#define isyslog(a...)
Definition tools.h:36