vdr  2.2.0
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 3.14 2015/01/14 12:09:19 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 
24 static int DvbApiVersion = 0x0000; // the version of the DVB driver actually in use (will be determined by the first device created)
25 
26 #define DVBS_TUNE_TIMEOUT 9000 //ms
27 #define DVBS_LOCK_TIMEOUT 2000 //ms
28 #define DVBC_TUNE_TIMEOUT 9000 //ms
29 #define DVBC_LOCK_TIMEOUT 2000 //ms
30 #define DVBT_TUNE_TIMEOUT 9000 //ms
31 #define DVBT_LOCK_TIMEOUT 2000 //ms
32 #define ATSC_TUNE_TIMEOUT 9000 //ms
33 #define ATSC_LOCK_TIMEOUT 2000 //ms
34 
35 #define SCR_RANDOM_TIMEOUT 500 // ms (add random value up to this when tuning SCR device to avoid lockups)
36 
37 // --- DVB Parameter Maps ----------------------------------------------------
38 
40  { 0, PILOT_OFF, trNOOP("off") },
41  { 1, PILOT_ON, trNOOP("on") },
42  { 999, PILOT_AUTO, trNOOP("auto") },
43  { -1, 0, NULL }
44  };
45 
47  { 0, INVERSION_OFF, trNOOP("off") },
48  { 1, INVERSION_ON, trNOOP("on") },
49  { 999, INVERSION_AUTO, trNOOP("auto") },
50  { -1, 0, NULL }
51  };
52 
54  { 5, 5000000, "5 MHz" },
55  { 6, 6000000, "6 MHz" },
56  { 7, 7000000, "7 MHz" },
57  { 8, 8000000, "8 MHz" },
58  { 10, 10000000, "10 MHz" },
59  { 1712, 1712000, "1.712 MHz" },
60  { -1, 0, NULL }
61  };
62 
64  { 0, FEC_NONE, trNOOP("none") },
65  { 12, FEC_1_2, "1/2" },
66  { 23, FEC_2_3, "2/3" },
67  { 34, FEC_3_4, "3/4" },
68  { 35, FEC_3_5, "3/5" },
69  { 45, FEC_4_5, "4/5" },
70  { 56, FEC_5_6, "5/6" },
71  { 67, FEC_6_7, "6/7" },
72  { 78, FEC_7_8, "7/8" },
73  { 89, FEC_8_9, "8/9" },
74  { 910, FEC_9_10, "9/10" },
75  { 999, FEC_AUTO, trNOOP("auto") },
76  { -1, 0, NULL }
77  };
78 
80  { 16, QAM_16, "QAM16" },
81  { 32, QAM_32, "QAM32" },
82  { 64, QAM_64, "QAM64" },
83  { 128, QAM_128, "QAM128" },
84  { 256, QAM_256, "QAM256" },
85  { 2, QPSK, "QPSK" },
86  { 5, PSK_8, "8PSK" },
87  { 6, APSK_16, "16APSK" },
88  { 7, APSK_32, "32APSK" },
89  { 10, VSB_8, "VSB8" },
90  { 11, VSB_16, "VSB16" },
91  { 12, DQPSK, "DQPSK" },
92  { 999, QAM_AUTO, trNOOP("auto") },
93  { -1, 0, NULL }
94  };
95 
96 #define DVB_SYSTEM_1 0 // see also nit.c
97 #define DVB_SYSTEM_2 1
98 
100  { 0, DVB_SYSTEM_1, "DVB-S" },
101  { 1, DVB_SYSTEM_2, "DVB-S2" },
102  { -1, 0, NULL }
103  };
104 
106  { 0, DVB_SYSTEM_1, "DVB-T" },
107  { 1, DVB_SYSTEM_2, "DVB-T2" },
108  { -1, 0, NULL }
109  };
110 
112  { 1, TRANSMISSION_MODE_1K, "1K" },
113  { 2, TRANSMISSION_MODE_2K, "2K" },
114  { 4, TRANSMISSION_MODE_4K, "4K" },
115  { 8, TRANSMISSION_MODE_8K, "8K" },
116  { 16, TRANSMISSION_MODE_16K, "16K" },
117  { 32, TRANSMISSION_MODE_32K, "32K" },
118  { 999, TRANSMISSION_MODE_AUTO, trNOOP("auto") },
119  { -1, 0, NULL }
120  };
121 
123  { 4, GUARD_INTERVAL_1_4, "1/4" },
124  { 8, GUARD_INTERVAL_1_8, "1/8" },
125  { 16, GUARD_INTERVAL_1_16, "1/16" },
126  { 32, GUARD_INTERVAL_1_32, "1/32" },
127  { 128, GUARD_INTERVAL_1_128, "1/128" },
128  { 19128, GUARD_INTERVAL_19_128, "19/128" },
129  { 19256, GUARD_INTERVAL_19_256, "19/256" },
130  { 999, GUARD_INTERVAL_AUTO, trNOOP("auto") },
131  { -1, 0, NULL }
132  };
133 
135  { 0, HIERARCHY_NONE, trNOOP("none") },
136  { 1, HIERARCHY_1, "1" },
137  { 2, HIERARCHY_2, "2" },
138  { 4, HIERARCHY_4, "4" },
139  { 999, HIERARCHY_AUTO, trNOOP("auto") },
140  { -1, 0, NULL }
141  };
142 
144  { 0, ROLLOFF_AUTO, trNOOP("auto") },
145  { 20, ROLLOFF_20, "0.20" },
146  { 25, ROLLOFF_25, "0.25" },
147  { 35, ROLLOFF_35, "0.35" },
148  { -1, 0, NULL }
149  };
150 
151 int UserIndex(int Value, const tDvbParameterMap *Map)
152 {
153  const tDvbParameterMap *map = Map;
154  while (map && map->userValue != -1) {
155  if (map->userValue == Value)
156  return map - Map;
157  map++;
158  }
159  return -1;
160 }
161 
162 int DriverIndex(int Value, const tDvbParameterMap *Map)
163 {
164  const tDvbParameterMap *map = Map;
165  while (map && map->userValue != -1) {
166  if (map->driverValue == Value)
167  return map - Map;
168  map++;
169  }
170  return -1;
171 }
172 
173 int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
174 {
175  int n = DriverIndex(Value, Map);
176  if (n >= 0) {
177  if (String)
178  *String = tr(Map[n].userString);
179  return Map[n].userValue;
180  }
181  return -1;
182 }
183 
184 const char *MapToUserString(int Value, const tDvbParameterMap *Map)
185 {
186  int n = DriverIndex(Value, Map);
187  if (n >= 0)
188  return Map[n].userString;
189  return "???";
190 }
191 
192 int MapToDriver(int Value, const tDvbParameterMap *Map)
193 {
194  int n = UserIndex(Value, Map);
195  if (n >= 0)
196  return Map[n].driverValue;
197  return -1;
198 }
199 
200 // --- cDvbTransponderParameters ---------------------------------------------
201 
203 {
204  polarization = 0;
205  inversion = INVERSION_AUTO;
206  bandwidth = 8000000;
207  coderateH = FEC_AUTO;
208  coderateL = FEC_AUTO;
209  modulation = QPSK;
211  transmission = TRANSMISSION_MODE_AUTO;
212  guard = GUARD_INTERVAL_AUTO;
213  hierarchy = HIERARCHY_AUTO;
214  rollOff = ROLLOFF_AUTO;
215  streamId = 0;
216  t2systemId = 0;
217  sisoMiso = 0;
218  pilot = PILOT_AUTO;
219  Parse(Parameters);
220 }
221 
222 int cDvbTransponderParameters::PrintParameter(char *p, char Name, int Value) const
223 {
224  return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0;
225 }
226 
228 {
229 #define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*')))
230  char buffer[64];
231  char *q = buffer;
232  *q = 0;
233  ST(" S *") q += sprintf(q, "%c", polarization);
234  ST(" T*") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues));
235  ST(" CST*") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues));
236  ST(" T*") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues));
237  ST(" T*") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues));
238  ST("ACST*") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues));
239  ST("ACST*") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues));
240  ST(" S 2") q += PrintParameter(q, 'N', MapToUser(pilot, PilotValues));
241  ST(" S 2") q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues));
242  ST(" ST2") q += PrintParameter(q, 'P', streamId);
243  ST(" T2") q += PrintParameter(q, 'Q', t2systemId);
244  ST(" ST*") q += PrintParameter(q, 'S', MapToUser(system, SystemValuesSat)); // we only need the numerical value, so Sat or Terr doesn't matter
245  ST(" T*") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues));
246  ST(" T2") q += PrintParameter(q, 'X', sisoMiso);
247  ST(" T*") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues));
248  return buffer;
249 }
250 
251 const char *cDvbTransponderParameters::ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map)
252 {
253  if (*++s) {
254  char *p = NULL;
255  errno = 0;
256  int n = strtol(s, &p, 10);
257  if (!errno && p != s) {
258  Value = Map ? MapToDriver(n, Map) : n;
259  if (Value >= 0)
260  return p;
261  }
262  }
263  esyslog("ERROR: invalid value for parameter '%c'", *(s - 1));
264  return NULL;
265 }
266 
268 {
269  while (s && *s) {
270  switch (toupper(*s)) {
271  case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break;
272  case 'C': s = ParseParameter(s, coderateH, CoderateValues); break;
273  case 'D': s = ParseParameter(s, coderateL, CoderateValues); break;
274  case 'G': s = ParseParameter(s, guard, GuardValues); break;
275  case 'H': polarization = 'H'; s++; break;
276  case 'I': s = ParseParameter(s, inversion, InversionValues); break;
277  case 'L': polarization = 'L'; s++; break;
278  case 'M': s = ParseParameter(s, modulation, ModulationValues); break;
279  case 'N': s = ParseParameter(s, pilot, PilotValues); break;
280  case 'O': s = ParseParameter(s, rollOff, RollOffValues); break;
281  case 'P': s = ParseParameter(s, streamId); break;
282  case 'Q': s = ParseParameter(s, t2systemId); break;
283  case 'R': polarization = 'R'; s++; break;
284  case 'S': s = ParseParameter(s, system, SystemValuesSat); break; // we only need the numerical value, so Sat or Terr doesn't matter
285  case 'T': s = ParseParameter(s, transmission, TransmissionValues); break;
286  case 'V': polarization = 'V'; s++; break;
287  case 'X': s = ParseParameter(s, sisoMiso); break;
288  case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break;
289  default: esyslog("ERROR: unknown parameter key '%c'", *s);
290  return false;
291  }
292  }
293  return true;
294 }
295 
296 // --- cDvbTuner -------------------------------------------------------------
297 
298 #define TUNER_POLL_TIMEOUT 10 // ms
299 
300 class cDvbTuner : public cThread {
301 private:
306  mutable int fd_frontend;
308  uint32_t subsystemId;
317  const cScr *scr;
320  mutable cMutex mutex;
325  bool SetFrontendType(const cChannel *Channel);
326  cString GetBondingParams(const cChannel *Channel = NULL) const;
327  cDvbTuner *GetBondedMaster(void);
328  bool IsBondedMaster(void) const { return !bondedTuner || bondedMaster; }
329  void ClearEventQueue(void) const;
330  bool GetFrontendStatus(fe_status_t &Status) const;
331  cPositioner *GetPositioner(void);
332  void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency);
333  void ResetToneAndVoltage(void);
334  bool SetFrontend(void);
335  virtual void Action(void);
336 
337  mutable bool isIdle;
338  bool OpenFrontend(void) const;
339  bool CloseFrontend(void);
340 public:
341  cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
342  virtual ~cDvbTuner();
343  int FrontendType(void) const { return frontendType; }
344  bool Bond(cDvbTuner *Tuner);
345  void UnBond(void);
346  bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
347  const cChannel *GetTransponder(void) const { return &channel; }
348  uint32_t SubsystemId(void) const { return subsystemId; }
349  bool IsTunedTo(const cChannel *Channel) const;
350  void SetChannel(const cChannel *Channel);
351  bool Locked(int TimeoutMs = 0);
352  const cPositioner *Positioner(void) const { return positioner; }
353  int GetSignalStrength(void) const;
354  int GetSignalQuality(void) const;
355 
356  bool SetIdle(bool Idle);
357  bool IsIdle(void) const { return isIdle; }
358  };
359 
361 
362 cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
363 {
364  frontendType = SYS_UNDEFINED;
365  device = Device;
366  fd_frontend = Fd_Frontend;
367  adapter = Adapter;
368  frontend = Frontend;
370  tuneTimeout = 0;
371  lockTimeout = 0;
372  lastTimeoutReport = 0;
373  lastDiseqc = NULL;
374  diseqcOffset = 0;
375  lastSource = 0;
376  positioner = NULL;
377  scr = NULL;
378  lnbPowerTurnedOn = false;
380  bondedTuner = NULL;
381  bondedMaster = false;
382  isIdle = false;
383  SetDescription("frontend %d/%d tuner", adapter, frontend);
384  Start();
385 }
386 
388 {
390  newSet.Broadcast();
391  locked.Broadcast();
392  Cancel(3);
393  UnBond();
394  /* looks like this irritates the SCR switch, so let's leave it out for now
395  if (lastDiseqc && lastDiseqc->IsScr()) {
396  unsigned int Frequency = 0;
397  ExecuteDiseqc(lastDiseqc, &Frequency);
398  }
399  */
400  if (device && device->IsSubDevice())
401  CloseFrontend();
402 }
403 
405 {
406  cMutexLock MutexLock(&bondMutex);
407  if (!bondedTuner) {
409  bondedMaster = false; // makes sure we don't disturb an existing master
410  bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
411  Tuner->bondedTuner = this;
412  dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
413  return true;
414  }
415  else
416  esyslog("ERROR: tuner %d/%d already bonded with tuner %d/%d, can't bond with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend, Tuner->adapter, Tuner->frontend);
417  return false;
418 }
419 
421 {
422  cMutexLock MutexLock(&bondMutex);
423  if (cDvbTuner *t = bondedTuner) {
424  dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
425  while (t->bondedTuner != this)
426  t = t->bondedTuner;
427  if (t == bondedTuner)
428  t->bondedTuner = NULL;
429  else
430  t->bondedTuner = bondedTuner;
431  bondedMaster = false; // another one will automatically become master whenever necessary
432  bondedTuner = NULL;
433  }
434 }
435 
437 {
438  if (!Channel)
439  Channel = &channel;
440  cDvbTransponderParameters dtp(Channel->Parameters());
441  if (Setup.DiSEqC) {
442  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL))
443  return diseqc->Commands();
444  }
445  else {
446  bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
447  bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
448  return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
449  }
450  return "";
451 }
452 
453 bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
454 {
455  cMutexLock MutexLock(&bondMutex);
456  if (cDvbTuner *t = bondedTuner) {
457  cString BondingParams = GetBondingParams(Channel);
458  do {
459  if (t->device->Priority() > IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
460  if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
461  return false;
462  }
463  t = t->bondedTuner;
464  } while (t != bondedTuner);
465  }
466  return true;
467 }
468 
470 {
471  if (!bondedTuner)
472  return this; // an unbonded tuner is always "master"
473  cMutexLock MutexLock(&bondMutex);
474  if (bondedMaster)
475  return this;
476  // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
477  if (cDvbTuner *t = bondedTuner) {
478  while (t != this) {
479  if (t->bondedMaster)
480  return t;
481  t = t->bondedTuner;
482  }
483  }
484  // None of the other bonded tuners is master, so make this one the master:
485  bondedMaster = true;
486  dsyslog("tuner %d/%d is now bonded master", adapter, frontend);
487  return this;
488 }
489 
490 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
491 {
492  if (tunerStatus == tsIdle)
493  return false; // not tuned to
494  if (channel.Source() != Channel->Source() || channel.Transponder() != Channel->Transponder())
495  return false; // sufficient mismatch
496  // Polarization is already checked as part of the Transponder.
497  return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
498 }
499 
500 void cDvbTuner::SetChannel(const cChannel *Channel)
501 {
502  if (Channel) {
503  if (bondedTuner) {
504  cMutexLock MutexLock(&bondMutex);
505  cDvbTuner *BondedMaster = GetBondedMaster();
506  if (BondedMaster == this) {
507  if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
508  // switching to a completely different band, so set all others to idle:
509  for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
510  t->SetChannel(NULL);
511  }
512  }
513  else if (strcmp(GetBondingParams(Channel), BondedMaster->GetBondingParams()) != 0)
514  BondedMaster->SetChannel(Channel);
515  }
516  cMutexLock MutexLock(&mutex);
517  if (!IsTunedTo(Channel))
518  tunerStatus = tsSet;
519  diseqcOffset = 0;
520  channel = *Channel;
521  lastTimeoutReport = 0;
522  newSet.Broadcast();
523  }
524  else {
525  cMutexLock MutexLock(&mutex);
528  }
530  cDevice::PrimaryDevice()->DelLivePids(); // 'device' is const, so we must do it this way
531 }
532 
533 bool cDvbTuner::Locked(int TimeoutMs)
534 {
535  bool isLocked = (tunerStatus >= tsLocked);
536  if (isLocked || !TimeoutMs)
537  return isLocked;
538 
539  cMutexLock MutexLock(&mutex);
540  if (TimeoutMs && tunerStatus < tsLocked)
541  locked.TimedWait(mutex, TimeoutMs);
542  return tunerStatus >= tsLocked;
543 }
544 
546 {
547  if (!OpenFrontend())
548  return;
549  cPoller Poller(fd_frontend);
550  if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
551  dvb_frontend_event Event;
552  while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
553  ; // just to clear the event queue - we'll read the actual status below
554  }
555 }
556 
557 bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
558 {
559  ClearEventQueue();
560  while (1) {
561  if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
562  return true;
563  if (errno != EINTR)
564  break;
565  }
566  return false;
567 }
568 
569 //#define DEBUG_SIGNALSTRENGTH
570 //#define DEBUG_SIGNALQUALITY
571 
573 {
574  ClearEventQueue();
575  uint16_t Signal;
576  while (1) {
577  if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
578  break;
579  if (errno != EINTR)
580  return -1;
581  }
582  uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
583  // Use the subsystemId to identify individual devices in case they need
584  // special treatment to map their Signal value into the range 0...0xFFFF.
585  switch (subsystemId) {
586  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
587  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
588  MaxSignal = 670; break;
589  }
590  int s = int(Signal) * 100 / MaxSignal;
591  if (s > 100)
592  s = 100;
593 #ifdef DEBUG_SIGNALSTRENGTH
594  fprintf(stderr, "FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
595 #endif
596  return s;
597 }
598 
599 #define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
600 
602 {
603  fe_status_t Status;
604  if (GetFrontendStatus(Status)) {
605  // 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...
606  if ((Status & FE_HAS_LOCK) == 0) {
607  if ((Status & FE_HAS_SIGNAL) == 0)
608  return 0;
609  if ((Status & FE_HAS_CARRIER) == 0)
610  return 1;
611  if ((Status & FE_HAS_VITERBI) == 0)
612  return 2;
613  if ((Status & FE_HAS_SYNC) == 0)
614  return 3;
615  return 4;
616  }
617 #ifdef DEBUG_SIGNALQUALITY
618  bool HasSnr = true;
619 #endif
620  uint16_t Snr;
621  while (1) {
622  if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
623  break;
624  if (errno != EINTR) {
625  Snr = 0xFFFF;
626 #ifdef DEBUG_SIGNALQUALITY
627  HasSnr = false;
628 #endif
629  break;
630  }
631  }
632 #ifdef DEBUG_SIGNALQUALITY
633  bool HasBer = true;
634 #endif
635  uint32_t Ber;
636  while (1) {
637  if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
638  break;
639  if (errno != EINTR) {
640  Ber = 0;
641 #ifdef DEBUG_SIGNALQUALITY
642  HasBer = false;
643 #endif
644  break;
645  }
646  }
647 #ifdef DEBUG_SIGNALQUALITY
648  bool HasUnc = true;
649 #endif
650  uint32_t Unc;
651  while (1) {
652  if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
653  break;
654  if (errno != EINTR) {
655  Unc = 0;
656 #ifdef DEBUG_SIGNALQUALITY
657  HasUnc = false;
658 #endif
659  break;
660  }
661  }
662  uint16_t MinSnr = 0x0000;
663  uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
664  // Use the subsystemId to identify individual devices in case they need
665  // special treatment to map their Snr value into the range 0...0xFFFF.
666  switch (subsystemId) {
667  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
668  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
669  if (frontendType == SYS_DVBS2) {
670  MinSnr = 10;
671  MaxSnr = 70;
672  }
673  else
674  MaxSnr = 200;
675  break;
676  case 0x20130245: // PCTV Systems PCTV 73ESE
677  case 0x2013024F: // PCTV Systems nanoStick T2 290e
678  MaxSnr = 255; break;
679  }
680  int a = int(constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
681  int b = 100 - (Unc * 10 + (Ber / 256) * 5);
682  if (b < 0)
683  b = 0;
684  int q = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
685  if (q > 100)
686  q = 100;
687 #ifdef DEBUG_SIGNALQUALITY
688  fprintf(stderr, "FE %d/%d: %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
689 #endif
690  return q;
691  }
692  return -1;
693 }
694 
695 static unsigned int FrequencyToHz(unsigned int f)
696 {
697  while (f && f < 1000000)
698  f *= 1000;
699  return f;
700 }
701 
703 {
704  if (!positioner) {
707  }
708  return positioner;
709 }
710 
711 void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
712 {
713  if (!lnbPowerTurnedOn) {
714  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
715  lnbPowerTurnedOn = true;
716  }
717  static cMutex Mutex;
718  if (Diseqc->IsScr())
719  Mutex.Lock();
720  struct dvb_diseqc_master_cmd cmd;
721  const char *CurrentAction = NULL;
722  cPositioner *Positioner = NULL;
723  bool Break = false;
724  for (int i = 0; !Break; i++) {
725  cmd.msg_len = sizeof(cmd.msg);
726  cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
727  if (da == cDiseqc::daNone) {
728  diseqcOffset = 0;
729  break;
730  }
731  bool d = i >= diseqcOffset;
732  switch (da) {
733  case cDiseqc::daToneOff: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
734  case cDiseqc::daToneOn: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
735  case cDiseqc::daVoltage13: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
736  case cDiseqc::daVoltage18: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
737  case cDiseqc::daMiniA: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
738  case cDiseqc::daMiniB: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
739  case cDiseqc::daCodes: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break;
740  case cDiseqc::daPositionN: if ((Positioner = GetPositioner()) != NULL) {
741  if (d) {
742  Positioner->GotoPosition(Diseqc->Position(), cSource::Position(channel.Source()));
743  Break = Positioner->IsMoving();
744  }
745  }
746  break;
747  case cDiseqc::daPositionA: if ((Positioner = GetPositioner()) != NULL) {
748  if (d) {
749  Positioner->GotoAngle(cSource::Position(channel.Source()));
750  Break = Positioner->IsMoving();
751  }
752  }
753  break;
754  case cDiseqc::daScr:
755  case cDiseqc::daWait: break;
756  default: esyslog("ERROR: unknown diseqc command %d", da);
757  }
758  if (Break)
759  diseqcOffset = i + 1;
760  }
762  if (scr && !Break)
763  ResetToneAndVoltage(); // makes sure we don't block the bus!
764  if (Diseqc->IsScr())
765  Mutex.Unlock();
766 }
767 
769 {
770  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
771  CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
772 }
773 
774 static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
775 {
776  int ds = SYS_UNDEFINED;
777  if (Channel->IsAtsc())
778  ds = SYS_ATSC;
779  else if (Channel->IsCable())
780  ds = SYS_DVBC_ANNEX_AC;
781  else if (Channel->IsSat())
782  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBS : SYS_DVBS2;
783  else if (Channel->IsTerr())
784  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBT : SYS_DVBT2;
785  else
786  esyslog("ERROR: can't determine frontend type for channel %d (%s)", Channel->Number(), Channel->Name());
787  return ds;
788 }
789 
791 {
792  if (!OpenFrontend())
793  return false;
794 #define MAXFRONTENDCMDS 16
795 #define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\
796  Frontend[CmdSeq.num].u.data = (d);\
797  if (CmdSeq.num++ > MAXFRONTENDCMDS) {\
798  esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\
799  return false;\
800  }\
801  }
802  dtv_property Frontend[MAXFRONTENDCMDS];
803  memset(&Frontend, 0, sizeof(Frontend));
804  dtv_properties CmdSeq;
805  memset(&CmdSeq, 0, sizeof(CmdSeq));
806  CmdSeq.props = Frontend;
807  SETCMD(DTV_CLEAR, 0);
808  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
809  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
810  return false;
811  }
812  CmdSeq.num = 0;
813 
815 
816  // Determine the required frontend type:
818  if (frontendType == SYS_UNDEFINED)
819  return false;
820 
821  SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
822  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
823  unsigned int frequency = channel.Frequency();
824  if (Setup.DiSEqC) {
825  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
826  frequency -= diseqc->Lof();
827  if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
828  if (IsBondedMaster()) {
829  ExecuteDiseqc(diseqc, &frequency);
830  if (frequency == 0)
831  return false;
832  }
833  else
835  lastDiseqc = diseqc;
837  }
838  }
839  else {
840  esyslog("ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
841  return false;
842  }
843  }
844  else {
845  int tone = SEC_TONE_OFF;
846  if (frequency < (unsigned int)Setup.LnbSLOF) {
847  frequency -= Setup.LnbFrequLo;
848  tone = SEC_TONE_OFF;
849  }
850  else {
851  frequency -= Setup.LnbFrequHi;
852  tone = SEC_TONE_ON;
853  }
854  int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
855  if (!IsBondedMaster()) {
856  tone = SEC_TONE_OFF;
857  volt = SEC_VOLTAGE_13;
858  }
859  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
860  CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
861  }
862  frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
863 
864  // DVB-S/DVB-S2 (common parts)
865  SETCMD(DTV_FREQUENCY, frequency * 1000UL);
866  SETCMD(DTV_MODULATION, dtp.Modulation());
867  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
868  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
869  SETCMD(DTV_INVERSION, dtp.Inversion());
870  if (frontendType == SYS_DVBS2) {
871  // DVB-S2
872  SETCMD(DTV_PILOT, dtp.Pilot());
873  SETCMD(DTV_ROLLOFF, dtp.RollOff());
874  if (DvbApiVersion >= 0x0508)
875  SETCMD(DTV_STREAM_ID, dtp.StreamId());
876  }
877  else {
878  // DVB-S
879  SETCMD(DTV_ROLLOFF, ROLLOFF_35); // DVB-S always has a ROLLOFF of 0.35
880  }
881 
884  }
885  else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
886  // DVB-C
887  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
888  SETCMD(DTV_INVERSION, dtp.Inversion());
889  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
890  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
891  SETCMD(DTV_MODULATION, dtp.Modulation());
892 
895  }
896  else if (frontendType == SYS_DVBT || frontendType == SYS_DVBT2) {
897  // DVB-T/DVB-T2 (common parts)
898  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
899  SETCMD(DTV_INVERSION, dtp.Inversion());
900  SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
901  SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
902  SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
903  SETCMD(DTV_MODULATION, dtp.Modulation());
904  SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
905  SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
906  SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
907  if (frontendType == SYS_DVBT2) {
908  // DVB-T2
909  if (DvbApiVersion >= 0x0508) {
910  SETCMD(DTV_STREAM_ID, dtp.StreamId());
911  }
912  else if (DvbApiVersion >= 0x0503)
913  SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId());
914  }
915 
918  }
919  else if (frontendType == SYS_ATSC) {
920  // ATSC
921  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
922  SETCMD(DTV_INVERSION, dtp.Inversion());
923  SETCMD(DTV_MODULATION, dtp.Modulation());
924 
927  }
928  else {
929  esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
930  return false;
931  }
932  SETCMD(DTV_TUNE, 0);
933  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
934  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
935  return false;
936  }
937  return true;
938 }
939 
941 {
942  cTimeMs Timer;
943  bool LostLock = false;
944  fe_status_t Status = (fe_status_t)0;
945  while (Running()) {
946  if (!isIdle) {
947  fe_status_t NewStatus;
948  if (GetFrontendStatus(NewStatus))
949  Status = NewStatus;
950  }
951  cMutexLock MutexLock(&mutex);
952  int WaitTime = 1000;
953  switch (tunerStatus) {
954  case tsIdle:
955  break; // we want the TimedWait() below!
956  case tsSet:
958  continue;
959  case tsPositioning:
960  if (positioner) {
961  if (positioner->IsMoving())
962  break; // we want the TimedWait() below!
963  else if (diseqcOffset) {
964  lastDiseqc = NULL;
965  tunerStatus = tsSet; // have it process the rest of the DiSEqC sequence
966  continue;
967  }
968  }
970  Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT : 0));
971  if (positioner)
972  continue;
973  // otherwise run directly into tsTuned...
974  case tsTuned:
975  if (Timer.TimedOut()) {
976  tunerStatus = tsSet;
977  lastDiseqc = NULL;
978  lastSource = 0;
979  if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
980  isyslog("frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
981  lastTimeoutReport = time(NULL);
982  }
983  continue;
984  }
985  WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
986  // run into tsLocked...
987  case tsLocked:
988  if (Status & FE_REINIT) {
989  tunerStatus = tsSet;
990  lastDiseqc = NULL;
991  lastSource = 0;
992  isyslog("frontend %d/%d was reinitialized", adapter, frontend);
993  lastTimeoutReport = 0;
994  continue;
995  }
996  else if (Status & FE_HAS_LOCK) {
997  if (LostLock) {
998  isyslog("frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
999  LostLock = false;
1000  }
1002  locked.Broadcast();
1003  lastTimeoutReport = 0;
1004  }
1005  else if (tunerStatus == tsLocked) {
1006  LostLock = true;
1007  isyslog("frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1008  tunerStatus = tsTuned;
1009  Timer.Set(lockTimeout);
1010  lastTimeoutReport = 0;
1011  continue;
1012  }
1013  break;
1014  default: esyslog("ERROR: unknown tuner status %d", tunerStatus);
1015  }
1016  newSet.TimedWait(mutex, WaitTime);
1017  }
1018 }
1019 
1020 bool cDvbTuner::SetIdle(bool Idle)
1021 {
1022  if (isIdle == Idle)
1023  return true;
1024  isIdle = Idle;
1025  if (Idle)
1026  return CloseFrontend();
1027  return OpenFrontend();
1028 }
1029 
1030 bool cDvbTuner::OpenFrontend(void) const
1031 {
1032  if (fd_frontend >= 0)
1033  return true;
1034  cMutexLock MutexLock(&mutex);
1036  if (fd_frontend < 0)
1037  return false;
1038  isIdle = false;
1039  return true;
1040 }
1041 
1043 {
1044  if (fd_frontend < 0)
1045  return true;
1046  cMutexLock MutexLock(&mutex);
1047  tunerStatus = tsIdle;
1048  newSet.Broadcast();
1049  close(fd_frontend);
1050  fd_frontend = -1;
1051  return true;
1052 }
1053 
1054 // --- cDvbSourceParam -------------------------------------------------------
1055 
1057 private:
1058  int param;
1059  int srate;
1061 public:
1062  cDvbSourceParam(char Source, const char *Description);
1063  virtual void SetData(cChannel *Channel);
1064  virtual void GetData(cChannel *Channel);
1065  virtual cOsdItem *GetOsdItem(void);
1066  };
1067 
1068 cDvbSourceParam::cDvbSourceParam(char Source, const char *Description)
1069 :cSourceParam(Source, Description)
1070 {
1071  param = 0;
1072  srate = 0;
1073 }
1074 
1076 {
1077  srate = Channel->Srate();
1078  dtp.Parse(Channel->Parameters());
1079  param = 0;
1080 }
1081 
1083 {
1084  Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), srate, dtp.ToString(Source()), true);
1085 }
1086 
1088 {
1089  char type = Source();
1090  const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr;
1091 #undef ST
1092 #define ST(s) if (strchr(s, type))
1093  switch (param++) {
1094  case 0: ST(" S ") return new cMenuEditChrItem( tr("Polarization"), &dtp.polarization, "HVLR"); else return GetOsdItem();
1095  case 1: ST(" ST") return new cMenuEditMapItem( tr("System"), &dtp.system, SystemValues); else return GetOsdItem();
1096  case 2: ST(" CS ") return new cMenuEditIntItem( tr("Srate"), &srate); else return GetOsdItem();
1097  case 3: ST("ACST") return new cMenuEditMapItem( tr("Inversion"), &dtp.inversion, InversionValues); else return GetOsdItem();
1098  case 4: ST(" CST") return new cMenuEditMapItem( tr("CoderateH"), &dtp.coderateH, CoderateValues); else return GetOsdItem();
1099  case 5: ST(" T") return new cMenuEditMapItem( tr("CoderateL"), &dtp.coderateL, CoderateValues); else return GetOsdItem();
1100  case 6: ST("ACST") return new cMenuEditMapItem( tr("Modulation"), &dtp.modulation, ModulationValues); else return GetOsdItem();
1101  case 7: ST(" T") return new cMenuEditMapItem( tr("Bandwidth"), &dtp.bandwidth, BandwidthValues); else return GetOsdItem();
1102  case 8: ST(" T") return new cMenuEditMapItem( tr("Transmission"), &dtp.transmission, TransmissionValues); else return GetOsdItem();
1103  case 9: ST(" T") return new cMenuEditMapItem( tr("Guard"), &dtp.guard, GuardValues); else return GetOsdItem();
1104  case 10: ST(" T") return new cMenuEditMapItem( tr("Hierarchy"), &dtp.hierarchy, HierarchyValues); else return GetOsdItem();
1105  case 11: ST(" S ") return new cMenuEditMapItem( tr("Rolloff"), &dtp.rollOff, RollOffValues); else return GetOsdItem();
1106  case 12: ST(" ST") return new cMenuEditIntItem( tr("StreamId"), &dtp.streamId, 0, 255); else return GetOsdItem();
1107  case 13: ST(" S ") return new cMenuEditMapItem( tr("Pilot"), &dtp.pilot, PilotValues); else return GetOsdItem();
1108  case 14: ST(" T") return new cMenuEditIntItem( tr("T2SystemId"), &dtp.t2systemId, 0, 65535); else return GetOsdItem();
1109  case 15: ST(" T") return new cMenuEditIntItem( tr("SISO/MISO"), &dtp.sisoMiso, 0, 1); else return GetOsdItem();
1110  default: return NULL;
1111  }
1112  return NULL;
1113 }
1114 
1115 // --- cDvbDevice ------------------------------------------------------------
1116 
1119 
1120 const char *DeliverySystemNames[] = {
1121  "",
1122  "DVB-C",
1123  "DVB-C",
1124  "DVB-T",
1125  "DSS",
1126  "DVB-S",
1127  "DVB-S2",
1128  "DVB-H",
1129  "ISDBT",
1130  "ISDBS",
1131  "ISDBC",
1132  "ATSC",
1133  "ATSCMH",
1134  "DMBTH",
1135  "CMMB",
1136  "DAB",
1137  "DVB-T2",
1138  "TURBO",
1139  NULL
1140  };
1141 
1142 cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice)
1143 :cDevice(ParentDevice)
1144 {
1145  adapter = Adapter;
1146  frontend = Frontend;
1147  ciAdapter = NULL;
1148  dvbTuner = NULL;
1149  numDeliverySystems = 0;
1150  numModulations = 0;
1151  bondedDevice = NULL;
1153  tsBuffer = NULL;
1154 
1155  // Devices that are present on all card types:
1156 
1157  int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
1158 
1159  // Common Interface:
1160 
1161  fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
1162  if (fd_ca >= 0)
1164 
1165  // The DVR device (will be opened and closed as needed):
1166 
1167  fd_dvr = -1;
1168 
1169  // We only check the devices that must be present - the others will be checked before accessing them://XXX
1170 
1171  if (fd_frontend >= 0) {
1172  if (QueryDeliverySystems(fd_frontend))
1173  dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend);
1174  }
1175  else
1176  esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
1177 
1179 }
1180 
1182 {
1184  delete dvbTuner;
1185  delete ciAdapter;
1186  UnBond();
1187  // We're not explicitly closing any device files here, since this sometimes
1188  // caused segfaults. Besides, the program is about to terminate anyway...
1189 }
1190 
1191 cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
1192 {
1193  return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE, DEV_DVB_ADAPTER, Adapter, Name, Frontend);
1194 }
1195 
1196 int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
1197 {
1198  cString FileName = DvbName(Name, Adapter, Frontend);
1199  int fd = open(FileName, Mode);
1200  if (fd < 0 && ReportError)
1201  LOG_ERROR_STR(*FileName);
1202  return fd;
1203 }
1204 
1205 bool cDvbDevice::Exists(int Adapter, int Frontend)
1206 {
1207  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
1208  if (access(FileName, F_OK) == 0) {
1209  int f = open(FileName, O_RDONLY);
1210  if (f >= 0) {
1211  close(f);
1212  return true;
1213  }
1214  else if (errno != ENODEV && errno != EINVAL)
1215  LOG_ERROR_STR(*FileName);
1216  }
1217  else if (errno != ENOENT)
1218  LOG_ERROR_STR(*FileName);
1219  return false;
1220 }
1221 
1222 bool cDvbDevice::Probe(int Adapter, int Frontend)
1223 {
1224  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
1225  dsyslog("probing %s", *FileName);
1226  for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
1227  if (dp->Probe(Adapter, Frontend))
1228  return true; // a plugin has created the actual device
1229  }
1230  dsyslog("creating cDvbDevice");
1231  new cDvbDevice(Adapter, Frontend); // it's a "budget" device
1232  return true;
1233 }
1234 
1236 {
1237  if (dvbTuner) {
1238  if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1240  if (numDeliverySystems)
1241  return DeliverySystemNames[deliverySystems[0]]; // to have some reasonable default
1242  }
1243  return "";
1244 }
1245 
1247 {
1248  return frontendInfo.name;
1249 }
1250 
1252 {
1253  new cDvbSourceParam('A', "ATSC");
1254  new cDvbSourceParam('C', "DVB-C");
1255  new cDvbSourceParam('S', "DVB-S");
1256  new cDvbSourceParam('T', "DVB-T");
1257  cStringList Nodes;
1258  cReadDir DvbDir(DEV_DVB_BASE);
1259  if (DvbDir.Ok()) {
1260  struct dirent *a;
1261  while ((a = DvbDir.Next()) != NULL) {
1262  if (strstr(a->d_name, DEV_DVB_ADAPTER) == a->d_name) {
1263  int Adapter = strtol(a->d_name + strlen(DEV_DVB_ADAPTER), NULL, 10);
1264  cReadDir AdapterDir(AddDirectory(DEV_DVB_BASE, a->d_name));
1265  if (AdapterDir.Ok()) {
1266  struct dirent *f;
1267  while ((f = AdapterDir.Next()) != NULL) {
1268  if (strstr(f->d_name, DEV_DVB_FRONTEND) == f->d_name) {
1269  int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND), NULL, 10);
1270  Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
1271  }
1272  }
1273  }
1274  }
1275  }
1276  }
1277  int Found = 0;
1278  int Used = 0;
1279  if (Nodes.Size() > 0) {
1280  Nodes.Sort();
1281  for (int i = 0; i < Nodes.Size(); i++) {
1282  int Adapter;
1283  int Frontend;
1284  if (2 == sscanf(Nodes[i], "%d %d", &Adapter, &Frontend)) {
1285  if (Exists(Adapter, Frontend)) {
1286  if (Found < MAXDEVICES) {
1287  Found++;
1288  if (UseDevice(NextCardIndex())) {
1289  if (Probe(Adapter, Frontend))
1290  Used++;
1291  }
1292  else
1293  NextCardIndex(1); // skips this one
1294  }
1295  }
1296  }
1297  }
1298  }
1299  if (Found > 0) {
1300  isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "");
1301  if (Used != Found)
1302  isyslog("using only %d DVB device%s", Used, Used > 1 ? "s" : "");
1303  }
1304  else
1305  isyslog("no DVB device found");
1306  return Found > 0;
1307 }
1308 
1310 {
1311  numDeliverySystems = 0;
1312  if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
1313  LOG_ERROR;
1314  return false;
1315  }
1316  dtv_property Frontend[1];
1317  dtv_properties CmdSeq;
1318  // Determine the version of the running DVB API:
1319  if (!DvbApiVersion) {
1320  memset(&Frontend, 0, sizeof(Frontend));
1321  memset(&CmdSeq, 0, sizeof(CmdSeq));
1322  CmdSeq.props = Frontend;
1323  SETCMD(DTV_API_VERSION, 0);
1324  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1325  LOG_ERROR;
1326  return false;
1327  }
1328  DvbApiVersion = Frontend[0].u.data;
1329  isyslog("DVB API version is 0x%04X (VDR was built with 0x%04X)", DvbApiVersion, DVBAPIVERSION);
1330  }
1331  // Determine the types of delivery systems this device provides:
1332  bool LegacyMode = true;
1333  if (DvbApiVersion >= 0x0505) {
1334  memset(&Frontend, 0, sizeof(Frontend));
1335  memset(&CmdSeq, 0, sizeof(CmdSeq));
1336  CmdSeq.props = Frontend;
1337  SETCMD(DTV_ENUM_DELSYS, 0);
1338  int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
1339  if (Result == 0) {
1340  for (uint i = 0; i < Frontend[0].u.buffer.len; i++) {
1342  esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
1343  break;
1344  }
1345  deliverySystems[numDeliverySystems++] = Frontend[0].u.buffer.data[i];
1346  }
1347  LegacyMode = false;
1348  }
1349  else {
1350  esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
1351  }
1352  }
1353  if (LegacyMode) {
1354  // Legacy mode (DVB-API < 5.5):
1355  switch (frontendInfo.type) {
1356  case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1358  deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1359  break;
1360  case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1363  break;
1364  case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC; break;
1365  case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break;
1366  default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
1367  }
1368  }
1369  if (numDeliverySystems > 0) {
1370  cString ds("");
1371  for (int i = 0; i < numDeliverySystems; i++)
1372  ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", DeliverySystemNames[deliverySystems[i]]);
1373  cString ms("");
1374  if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
1375  if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
1376  if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); }
1377  if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); }
1378  if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); }
1379  if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); }
1380  if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); }
1381  if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); }
1382  if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); }
1383  if (!**ms)
1384  ms = "unknown modulations";
1385  isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
1386  return true;
1387  }
1388  else
1389  esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
1390  return false;
1391 }
1392 
1393 bool cDvbDevice::BondDevices(const char *Bondings)
1394 {
1395  UnBondDevices();
1396  if (Bondings) {
1397  cSatCableNumbers SatCableNumbers(MAXDEVICES, Bondings);
1398  for (int i = 0; i < cDevice::NumDevices(); i++) {
1399  int d = SatCableNumbers.FirstDeviceIndex(i);
1400  if (d >= 0) {
1401  int ErrorDevice = 0;
1402  if (cDevice *Device1 = cDevice::GetDevice(i)) {
1403  if (Device1->HasSubDevice())
1404  Device1 = Device1->SubDevice();
1405  if (cDevice *Device2 = cDevice::GetDevice(d)) {
1406  if (Device2->HasSubDevice())
1407  Device2 = Device2->SubDevice();
1408  if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1409  if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1410  if (!DvbDevice1->Bond(DvbDevice2))
1411  return false; // Bond() has already logged the error
1412  }
1413  else
1414  ErrorDevice = d + 1;
1415  }
1416  else
1417  ErrorDevice = i + 1;
1418  if (ErrorDevice) {
1419  esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
1420  return false;
1421  }
1422  }
1423  else
1424  ErrorDevice = d + 1;
1425  }
1426  else
1427  ErrorDevice = i + 1;
1428  if (ErrorDevice) {
1429  esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
1430  return false;
1431  }
1432  }
1433  }
1434  }
1435  return true;
1436 }
1437 
1439 {
1440  for (int i = 0; i < cDevice::NumDevices(); i++) {
1441  cDevice *dev = cDevice::GetDevice(i);
1442  if (dev && dev->HasSubDevice())
1443  dev = dev->SubDevice();
1444  if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(dev))
1445  d->UnBond();
1446  }
1447 }
1448 
1450 {
1451  cMutexLock MutexLock(&bondMutex);
1452  if (!bondedDevice) {
1453  if (Device != this) {
1454  if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) {
1455  if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
1456  bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
1457  Device->bondedDevice = this;
1458  dsyslog("device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1459  return true;
1460  }
1461  }
1462  else
1463  esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->CardIndex() + 1);
1464  }
1465  else
1466  esyslog("ERROR: can't bond device %d with itself", CardIndex() + 1);
1467  }
1468  else
1469  esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->CardIndex() + 1);
1470  return false;
1471 }
1472 
1474 {
1475  cMutexLock MutexLock(&bondMutex);
1476  if (cDvbDevice *d = bondedDevice) {
1477  if (dvbTuner)
1478  dvbTuner->UnBond();
1479  dsyslog("device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1480  while (d->bondedDevice != this)
1481  d = d->bondedDevice;
1482  if (d == bondedDevice)
1483  d->bondedDevice = NULL;
1484  else
1485  d->bondedDevice = bondedDevice;
1486  bondedDevice = NULL;
1487  }
1488 }
1489 
1490 bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
1491 {
1492  cMutexLock MutexLock(&bondMutex);
1493  if (bondedDevice || Positioner())
1494  return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1495  return true;
1496 }
1497 
1498 bool cDvbDevice::SetIdleDevice(bool Idle, bool TestOnly)
1499 {
1500  if (TestOnly) {
1501  if (ciAdapter)
1502  return ciAdapter->SetIdle(Idle, true);
1503  return true;
1504  }
1505  if (!dvbTuner->SetIdle(Idle))
1506  return false;
1507  if (ciAdapter && !ciAdapter->SetIdle(Idle, false)) {
1508  dvbTuner->SetIdle(!Idle);
1509  return false;
1510  }
1511  if (Idle)
1513  else
1515  return true;
1516 }
1517 
1519 {
1520  return ciAdapter;
1521 }
1522 
1523 bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
1524 {
1525  if (Handle->pid) {
1526  dmx_pes_filter_params pesFilterParams;
1527  memset(&pesFilterParams, 0, sizeof(pesFilterParams));
1528  if (On) {
1529  if (Handle->handle < 0) {
1530  Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
1531  if (Handle->handle < 0) {
1532  LOG_ERROR;
1533  return false;
1534  }
1535  }
1536  pesFilterParams.pid = Handle->pid;
1537  pesFilterParams.input = DMX_IN_FRONTEND;
1538  pesFilterParams.output = DMX_OUT_TS_TAP;
1539  pesFilterParams.pes_type= DMX_PES_OTHER;
1540  pesFilterParams.flags = DMX_IMMEDIATE_START;
1541  if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
1542  LOG_ERROR;
1543  return false;
1544  }
1545  }
1546  else if (!Handle->used) {
1547  CHECK(ioctl(Handle->handle, DMX_STOP));
1548  if (Type <= ptTeletext) {
1549  pesFilterParams.pid = 0x1FFF;
1550  pesFilterParams.input = DMX_IN_FRONTEND;
1551  pesFilterParams.output = DMX_OUT_DECODER;
1552  pesFilterParams.pes_type= DMX_PES_OTHER;
1553  pesFilterParams.flags = DMX_IMMEDIATE_START;
1554  CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
1555  }
1556  close(Handle->handle);
1557  Handle->handle = -1;
1558  }
1559  }
1560  return true;
1561 }
1562 
1563 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
1564 {
1566  int f = open(FileName, O_RDWR | O_NONBLOCK);
1567  if (f >= 0) {
1568  dmx_sct_filter_params sctFilterParams;
1569  memset(&sctFilterParams, 0, sizeof(sctFilterParams));
1570  sctFilterParams.pid = Pid;
1571  sctFilterParams.timeout = 0;
1572  sctFilterParams.flags = DMX_IMMEDIATE_START;
1573  sctFilterParams.filter.filter[0] = Tid;
1574  sctFilterParams.filter.mask[0] = Mask;
1575  if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
1576  return f;
1577  else {
1578  esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
1579  close(f);
1580  }
1581  }
1582  else
1583  esyslog("ERROR: can't open filter handle on '%s'", *FileName);
1584  return -1;
1585 }
1586 
1587 void cDvbDevice::CloseFilter(int Handle)
1588 {
1589  close(Handle);
1590 }
1591 
1592 bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
1593 {
1594  for (int i = 0; i < numDeliverySystems; i++) {
1595  if (deliverySystems[i] == DeliverySystem)
1596  return true;
1597  }
1598  return false;
1599 }
1600 
1601 bool cDvbDevice::ProvidesSource(int Source) const
1602 {
1603  int type = Source & cSource::st_Mask;
1604  return type == cSource::stNone
1605  || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
1606  || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
1607  || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
1609 }
1610 
1611 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
1612 {
1613  if (!ProvidesSource(Channel->Source()))
1614  return false; // doesn't provide source
1615  cDvbTransponderParameters dtp(Channel->Parameters());
1616  if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) ||
1617  dtp.StreamId() != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM) ||
1618  dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
1619  dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
1620  dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
1621  dtp.Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
1622  dtp.Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
1623  dtp.Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
1624  dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
1625  dtp.Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
1626  dtp.Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
1627  dtp.Modulation() == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
1628  return false; // requires modulation system which frontend doesn't provide
1629  if (!cSource::IsSat(Channel->Source()) ||
1630  (!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
1631  return DeviceHooksProvidesTransponder(Channel);
1632  return false;
1633 }
1634 
1635 bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
1636 {
1637  bool result = false;
1638  bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
1639  bool needsDetachReceivers = false;
1641 
1642  if (dvbTuner && ProvidesTransponder(Channel)) {
1643  result = hasPriority;
1644  if (Priority > IDLEPRIORITY) {
1645  if (Receiving()) {
1646  if (dvbTuner->IsTunedTo(Channel)) {
1647  if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0)) || Channel->Dpid(0) && !HasPid(Channel->Dpid(0))) {
1648  if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
1649  if (CamSlot()->CanDecrypt(Channel))
1650  result = true;
1651  else
1652  needsDetachReceivers = true;
1653  }
1654  else
1655  result = true;
1656  }
1657  else
1658  result = true;
1659  }
1660  else
1661  needsDetachReceivers = Receiving();
1662  }
1663  if (result) {
1664  cMutexLock MutexLock(&bondMutex);
1665  if (!BondingOk(Channel)) {
1666  // This device is bonded, so we need to check the priorities of the others:
1667  for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
1668  if (d->Priority() >= Priority) {
1669  result = false;
1670  break;
1671  }
1672  needsDetachReceivers |= d->Receiving();
1673  }
1675  needsDetachReceivers |= Receiving();
1676  }
1677  }
1678  }
1679  }
1680  if (NeedsDetachReceivers)
1681  *NeedsDetachReceivers = needsDetachReceivers;
1682  return result;
1683 }
1684 
1685 bool cDvbDevice::ProvidesEIT(void) const
1686 {
1687  return !IsIdle() && (dvbTuner != NULL) && !dvbTuner->IsIdle() && ((ciAdapter == NULL) || !ciAdapter->IsIdle());
1688 }
1689 
1691 {
1693 }
1694 
1696 {
1697  return dvbTuner ? dvbTuner->Positioner() : NULL;
1698 }
1699 
1701 {
1702  return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
1703 }
1704 
1706 {
1707  return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
1708 }
1709 
1711 {
1712  return dvbTuner ? dvbTuner->GetTransponder() : NULL;
1713 }
1714 
1715 bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) const
1716 {
1717  return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
1718 }
1719 
1720 bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
1721 {
1722  return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
1723 }
1724 
1725 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
1726 {
1727  if (dvbTuner)
1728  dvbTuner->SetChannel(Channel);
1729  return true;
1730 }
1731 
1732 bool cDvbDevice::HasLock(int TimeoutMs) const
1733 {
1734  return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
1735 }
1736 
1738 {
1740 }
1741 
1743 {
1744  CloseDvr();
1745  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
1746  if (fd_dvr >= 0)
1747  tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5), CardIndex() + 1);
1748  return fd_dvr >= 0;
1749 }
1750 
1752 {
1753  if (fd_dvr >= 0) {
1754  delete tsBuffer;
1755  tsBuffer = NULL;
1756  close(fd_dvr);
1757  fd_dvr = -1;
1758  }
1759 }
1760 
1762 {
1763  if (tsBuffer) {
1764  if (cCamSlot *cs = CamSlot()) {
1765  if (cs->WantsTsData()) {
1766  int Available;
1767  Data = tsBuffer->Get(&Available);
1768  if (Data) {
1769  Data = cs->Decrypt(Data, Available);
1770  tsBuffer->Skip(Available);
1771  }
1772  return true;
1773  }
1774  }
1775  Data = tsBuffer->Get();
1776  return true;
1777  }
1778  return false;
1779 }
1780 
1782 {
1783  cMutexLock MutexLock(&bondMutex);
1784  cDvbDevice *d = this;
1785  do {
1786  d->cDevice::DetachAllReceivers();
1787  d = d->bondedDevice;
1788  } while (d && d != this && needsDetachBondedReceivers);
1790 }
1791 
1792 // --- cDvbDeviceProbe -------------------------------------------------------
1793 
1795 
1797 {
1798  DvbDeviceProbes.Add(this);
1799 }
1800 
1802 {
1803  DvbDeviceProbes.Del(this, false);
1804 }
1805 
1806 uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
1807 {
1808  uint32_t SubsystemId = 0;
1809  cString FileName = cString::sprintf("/dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
1810  struct stat st;
1811  if (stat(FileName, &st) == 0) {
1812  cReadDir d("/sys/class/dvb");
1813  if (d.Ok()) {
1814  struct dirent *e;
1815  while ((e = d.Next()) != NULL) {
1816  if (strstr(e->d_name, "frontend")) {
1817  FileName = cString::sprintf("/sys/class/dvb/%s/dev", e->d_name);
1818  if (FILE *f = fopen(FileName, "r")) {
1819  cReadLine ReadLine;
1820  char *s = ReadLine.Read(f);
1821  fclose(f);
1822  unsigned Major;
1823  unsigned Minor;
1824  if (s && 2 == sscanf(s, "%u:%u", &Major, &Minor)) {
1825  if (((Major << 8) | Minor) == st.st_rdev) {
1826  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
1827  if ((f = fopen(FileName, "r")) != NULL) {
1828  if (char *s = ReadLine.Read(f))
1829  SubsystemId = strtoul(s, NULL, 0) << 16;
1830  fclose(f);
1831  }
1832  else {
1833  FileName = cString::sprintf("/sys/class/dvb/%s/device/idVendor", e->d_name);
1834  if ((f = fopen(FileName, "r")) != NULL) {
1835  if (char *s = ReadLine.Read(f))
1836  SubsystemId = strtoul(s, NULL, 16) << 16;
1837  fclose(f);
1838  }
1839  }
1840  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_device", e->d_name);
1841  if ((f = fopen(FileName, "r")) != NULL) {
1842  if (char *s = ReadLine.Read(f))
1843  SubsystemId |= strtoul(s, NULL, 0);
1844  fclose(f);
1845  }
1846  else {
1847  FileName = cString::sprintf("/sys/class/dvb/%s/device/idProduct", e->d_name);
1848  if ((f = fopen(FileName, "r")) != NULL) {
1849  if (char *s = ReadLine.Read(f))
1850  SubsystemId |= strtoul(s, NULL, 16);
1851  fclose(f);
1852  }
1853  }
1854  break;
1855  }
1856  }
1857  }
1858  }
1859  }
1860  }
1861  }
1862  return SubsystemId;
1863 }
static unsigned int FrequencyToHz(unsigned int f)
Definition: dvbdevice.c:695
#define SETCMD(c, d)
#define DVB_SYSTEM_1
Definition: dvbdevice.c:96
struct dirent * Next(void)
Definition: tools.c:1466
int lastSource
Definition: dvbdevice.c:315
virtual ~cDvbDeviceProbe()
Definition: dvbdevice.c:1801
cDiseqcs Diseqcs
Definition: diseqc.c:439
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:130
const char * DeliverySystemNames[]
Definition: dvbdevice.c:1120
virtual ~cDvbTuner()
Definition: dvbdevice.c:387
cDvbTransponderParameters(const char *Parameters=NULL)
Definition: dvbdevice.c:202
unsigned char uchar
Definition: tools.h:30
virtual ~cDvbDevice()
Definition: dvbdevice.c:1181
void Lock(void)
Definition: thread.c:191
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: dvbdevice.c:1601
int PrintParameter(char *p, char Name, int Value) const
Definition: dvbdevice.c:222
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition: dvbdevice.c:1235
bool IsBondedMaster(void) const
Definition: dvbdevice.c:328
uchar * Get(int *Available=NULL)
Returns a pointer to the first TS packet in the buffer.
Definition: device.c:1857
virtual bool SetIdle(bool Idle, bool TestOnly)
Definition: ci.h:120
int Vpid(void) const
Definition: channels.h:154
#define DEV_DVB_BASE
Definition: dvbdevice.h:73
static bool Exists(int Adapter, int Frontend)
Checks whether the given adapter/frontend exists.
Definition: dvbdevice.c:1205
int Number(void) const
Definition: channels.h:179
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
Definition: diseqc.h:132
cPositioner * positioner
Definition: dvbdevice.c:316
void ResetToneAndVoltage(void)
Definition: dvbdevice.c:768
#define SCR_RANDOM_TIMEOUT
Definition: dvbdevice.c:35
#define dsyslog(a...)
Definition: tools.h:36
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:350
#define CA_ENCRYPTED_MIN
Definition: channels.h:48
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition: device.c:1634
void Set(int Ms=0)
Definition: tools.c:738
const char * ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map=NULL)
Definition: dvbdevice.c:251
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: dvbdevice.c:1715
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
static bool Initialize(void)
Initializes the DVB devices.
Definition: dvbdevice.c:1251
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition: thread.c:236
virtual bool GetTSPacket(uchar *&Data)
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data...
Definition: dvbdevice.c:1761
#define LOG_ERROR
Definition: tools.h:38
cDvbTuner * dvbTuner
Definition: dvbdevice.h:237
#define DVBT_TUNE_TIMEOUT
Definition: dvbdevice.c:30
int UserIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:151
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2014
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition: dvbdevice.c:1695
int fd_dvr
Definition: dvbdevice.h:188
int fd_frontend
Definition: dvbdevice.c:306
void UnBond(void)
Removes this device from any bonding it might have with other devices.
Definition: dvbdevice.c:1473
cTSBuffer * tsBuffer
< Controls how the DVB device handles Transfer Mode when replaying Dolby Digital audio.
Definition: dvbdevice.h:287
#define DVBC_TUNE_TIMEOUT
Definition: dvbdevice.c:28
int Ca(int Index=0) const
Definition: channels.h:173
void ClearEventQueue(void) const
Definition: dvbdevice.c:545
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition: device.c:680
int Dpid(int i) const
Definition: channels.h:161
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition: dvbdevice.c:1705
virtual cOsdItem * GetOsdItem(void)
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
Definition: dvbdevice.c:1087
#define DVBS_LOCK_TIMEOUT
Definition: dvbdevice.c:27
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
Definition: positioner.c:100
void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
Definition: dvbdevice.c:711
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1080
#define DVBC_LOCK_TIMEOUT
Definition: dvbdevice.c:29
int Adapter(void) const
Definition: dvbdevice.h:196
const tDvbParameterMap SystemValuesSat[]
Definition: dvbdevice.c:99
virtual void Append(T Data)
Definition: tools.h:571
void SetFrontend(int Frontend)
This function is called whenever the positioner is connected to a DVB frontend.
Definition: positioner.h:89
#define DVBT_LOCK_TIMEOUT
Definition: dvbdevice.c:31
cDvbDeviceProbe(void)
Definition: dvbdevice.c:1796
static uint32_t GetSubsystemId(int Adapter, int Frontend)
Definition: dvbdevice.c:1806
const tDvbParameterMap InversionValues[]
Definition: dvbdevice.c:46
#define MAXDEVICES
Definition: device.h:29
#define esyslog(a...)
Definition: tools.h:34
int Srate(void) const
Definition: channels.h:153
bool Parse(const char *s)
Definition: dvbdevice.c:267
int frontend
Definition: dvbdevice.c:307
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:261
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition: dvbdevice.c:1725
bool SetIdle(bool Idle)
Definition: dvbdevice.c:1020
#define LOG_ERROR_STR(s)
Definition: tools.h:39
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
Parses the DiSEqC commands and returns the appropriate action code with every call.
Definition: diseqc.c:402
Definition: tools.h:489
int frontendType
Definition: dvbdevice.c:304
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:118
#define DEV_DVB_ADAPTER
Definition: dvbdevice.h:74
bool IsTunedTo(const cChannel *Channel) const
Definition: dvbdevice.c:490
#define TUNER_POLL_TIMEOUT
Definition: dvbdevice.c:298
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition: device.c:600
int GetSignalStrength(void) const
Definition: dvbdevice.c:572
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:157
cDvbTuner * GetBondedMaster(void)
Definition: dvbdevice.c:469
cString ToString(char Type) const
Definition: dvbdevice.c:227
bool Poll(int TimeoutMs=0)
Definition: tools.c:1443
uint32_t subsystemId
Definition: dvbdevice.c:308
int MapToDriver(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:192
bool isIdle
Definition: dvbdevice.c:337
int adapter
Definition: dvbdevice.c:307
char * Read(FILE *f)
Definition: tools.c:1398
bool QueryDeliverySystems(int fd_frontend)
Definition: dvbdevice.c:1309
cPositioner * GetPositioner(void)
Definition: dvbdevice.c:702
Definition: diseqc.h:62
const char * Parameters(void) const
Definition: channels.h:182
bool needsDetachBondedReceivers
Definition: dvbdevice.h:191
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition: device.c:185
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
Definition: channels.c:196
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition: positioner.c:133
int frontend
Definition: dvbdevice.h:182
int LnbFrequLo
Definition: config.h:272
bool IsPrimaryDevice(void) const
Definition: device.h:830
A steerable satellite dish generally points to the south on the northern hemisphere, and to the north on the southern hemisphere (unless you're located directly on the equator, in which case the general direction is "up").
Definition: positioner.h:31
cMutex mutex
Definition: dvbdevice.c:320
static int DvbApiVersion
Definition: dvbdevice.c:24
virtual void GotoAngle(int Longitude)
Move the dish to the given angular position.
Definition: positioner.c:107
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:833
cCondVar newSet
Definition: dvbdevice.c:322
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:745
cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice=NULL)
Definition: dvbdevice.c:1142
const tDvbParameterMap HierarchyValues[]
Definition: dvbdevice.c:134
#define IDLEPRIORITY
Definition: config.h:47
const char * Name(void) const
Definition: channels.c:122
int Frontend(void) const
Definition: dvbdevice.h:197
cCiAdapter * ciAdapter
Definition: dvbdevice.h:232
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition: device.c:608
int Source(void) const
Definition: channels.h:152
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:1393
#define trNOOP(s)
Definition: i18n.h:88
#define CHECK(s)
Definition: tools.h:50
cChannel channel
Definition: dvbdevice.c:312
static bool Probe(int Adapter, int Frontend)
Probes for existing DVB devices.
Definition: dvbdevice.c:1222
bool bondedMaster
Definition: dvbdevice.c:324
T constrain(T v, T l, T h)
Definition: tools.h:60
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
Definition: dvbdevice.c:1523
uint32_t SubsystemId(void) const
Definition: dvbdevice.c:348
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition: device.c:623
int numModulations
Definition: dvbdevice.h:187
const cScr * scr
Definition: dvbdevice.c:317
#define MAXDELIVERYSYSTEMS
Definition: dvbdevice.h:70
virtual bool CanDecrypt(const cChannel *Channel)
Returns true if there is a CAM in this slot that is able to decrypt the given Channel (or at least cl...
Definition: ci.c:2163
static cMutex bondMutex
Definition: dvbdevice.c:302
virtual void SetData(cChannel *Channel)
Sets all source specific parameters to those of the given Channel.
Definition: dvbdevice.c:1075
void Broadcast(void)
Definition: thread.c:135
cDvbDevice * bondedDevice
Definition: dvbdevice.h:190
cDvbSourceParam(char Source, const char *Description)
Definition: dvbdevice.c:1068
int LnbSLOF
Definition: config.h:271
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition: dvbdevice.c:173
bool TimedOut(void) const
Definition: tools.c:743
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
#define DVBAPIVERSION
Definition: dvbdevice.h:17
cList< cDvbDeviceProbe > DvbDeviceProbes
Definition: dvbdevice.c:1794
static cMutex bondMutex
Definition: dvbdevice.h:189
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition: dvbdevice.c:1246
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:273
virtual void CloseDvr(void)
Shuts down the DVR.
Definition: dvbdevice.c:1751
#define DEV_DVB_FRONTEND
Definition: dvbdevice.h:76
#define DVBS_TUNE_TIMEOUT
Definition: dvbdevice.c:26
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
Definition: dvbdevice.c:1587
static bool IsSat(int Code)
Definition: sources.h:57
bool Ok(void)
Definition: tools.h:379
#define DEV_DVB_CA
Definition: dvbdevice.h:81
bool HasSubDevice(void) const
Definition: device.h:837
cSetup Setup
Definition: config.c:372
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:162
int adapter
Definition: dvbdevice.h:182
#define MAXFRONTENDCMDS
void UnBond(void)
Definition: dvbdevice.c:420
Definition: ci.h:131
#define ATSC_LOCK_TIMEOUT
Definition: dvbdevice.c:33
bool OpenFrontend(void) const
Definition: dvbdevice.c:1030
const tDvbParameterMap ModulationValues[]
Definition: dvbdevice.c:79
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:99
int deliverySystems[MAXDELIVERYSYSTEMS]
Definition: dvbdevice.h:185
bool lnbPowerTurnedOn
Definition: dvbdevice.c:318
Definition: thread.h:63
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:117
bool Locked(int TimeoutMs=0)
Definition: dvbdevice.c:533
static cDvbCiAdapter * CreateCiAdapter(cDevice *Device, int Fd, int Adapter=-1, int Frontend=-1)
Definition: dvbci.c:145
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
Definition: channels.h:149
#define DVB_SYSTEM_2
Definition: dvbdevice.c:97
int Size(void) const
Definition: tools.h:551
cDevice * parentDevice
Definition: device.h:823
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:1885
virtual bool OpenDvr(void)
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver...
Definition: dvbdevice.c:1742
int LnbFrequHi
Definition: config.h:273
#define DEV_DVB_DVR
Definition: dvbdevice.h:77
int GetSignalQuality(void) const
Definition: dvbdevice.c:601
bool IsIdle(void) const
Definition: dvbdevice.c:357
int diseqcOffset
Definition: dvbdevice.c:314
bool Bond(cDvbTuner *Tuner)
Definition: dvbdevice.c:404
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition: dvbdevice.c:1781
static void UnBondDevices(void)
Unbonds all devices.
Definition: dvbdevice.c:1438
#define DTV_ENUM_DELSYS
Definition: dvbdevice.h:57
const char * MapToUserString(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:184
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition: dvbdevice.c:1710
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition: dvbdevice.c:1518
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:831
const tDvbParameterMap PilotValues[]
Definition: dvbdevice.c:39
int Priority(void) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY), or IDLEPRIORITY if no receiver is currently active.
Definition: device.c:1614
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition: dvbdevice.c:1732
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: dvbdevice.c:1690
dvb_frontend_info frontendInfo
Definition: dvbdevice.h:184
int FrontendType(void) const
Definition: dvbdevice.c:343
bool IsSat(void) const
Definition: channels.h:187
#define MEGABYTE(n)
Definition: tools.h:44
char Source(void) const
Definition: sourceparams.h:31
eTunerStatus tunerStatus
Definition: dvbdevice.c:319
virtual bool IsIdle(void) const
Definition: ci.h:121
const cDiseqc * lastDiseqc
Definition: dvbdevice.c:313
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
Definition: dvbdevice.c:774
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2046
cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
Definition: dvbdevice.c:362
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:116
virtual bool ProvidesDeliverySystem(int DeliverySystem) const
Definition: dvbdevice.c:1592
const tDvbParameterMap RollOffValues[]
Definition: dvbdevice.c:143
bool IsTerr(void) const
Definition: channels.h:188
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:137
static int setTransferModeForDolbyDigital
Definition: dvbdevice.h:275
Definition: diseqc.h:34
const tDvbParameterMap CoderateValues[]
Definition: dvbdevice.c:63
int Apid(int i) const
Definition: channels.h:160
#define tr(s)
Definition: i18n.h:85
bool IsSubDevice(void) const
Definition: device.h:836
unsigned char u_char
Definition: headers.h:24
bool CloseFrontend(void)
Definition: dvbdevice.c:1042
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:1449
const cPositioner * Positioner(void) const
Definition: dvbdevice.c:352
#define DEV_DVB_DEMUX
Definition: dvbdevice.h:78
const cChannel * GetTransponder(void) const
Definition: dvbdevice.c:347
virtual bool ProvidesTransponder(const cChannel *Channel) const
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
Definition: dvbdevice.c:1611
#define ST(s)
#define isyslog(a...)
Definition: tools.h:35
eDiseqcActions
Definition: diseqc.h:64
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
Definition: thread.h:77
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const
Returns true if this device can provide the given channel.
Definition: dvbdevice.c:1635
bool SetFrontend(void)
Definition: dvbdevice.c:790
void Sort(bool IgnoreCase=false)
Definition: tools.h:629
#define DTV_STREAM_ID
Definition: dvbdevice.h:64
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
Definition: dvbdevice.c:453
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API...
Definition: dvbdevice.h:167
virtual bool SetIdleDevice(bool Idle, bool TestOnly)
Called by SetIdle if TestOnly, don't do anything, just return, if the device can be set to the new id...
Definition: dvbdevice.c:1498
void SetChannel(const cChannel *Channel)
Definition: dvbdevice.c:500
Definition: tools.h:333
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise)...
Definition: sources.h:35
#define LOCK_THRESHOLD
Definition: dvbdevice.c:599
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition: device.c:492
bool GetFrontendStatus(fe_status_t &Status) const
Definition: dvbdevice.c:557
#define DTV_DVBT2_PLP_ID_LEGACY
Definition: dvbdevice.h:65
const tDvbParameterMap SystemValuesTerr[]
Definition: dvbdevice.c:105
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: dvbdevice.c:940
cDevice * SubDevice(void) const
Definition: device.h:838
const tDvbParameterMap BandwidthValues[]
Definition: dvbdevice.c:53
int lockTimeout
Definition: dvbdevice.c:310
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:1490
bool IsCable(void) const
Definition: channels.h:186
int System(void) const
Definition: dvbdevice.h:135
int tuneTimeout
Definition: dvbdevice.c:309
bool IsIdle(void) const
Definition: device.h:839
cCondVar locked
Definition: dvbdevice.c:321
Definition: tools.h:357
Derived cDevice classes that can receive channels will have to provide Transport Stream (TS) packets ...
Definition: device.h:856
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
Definition: dvbdevice.c:1563
time_t lastTimeoutReport
Definition: dvbdevice.c:311
int numDeliverySystems
Definition: dvbdevice.h:186
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:323
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition: dvbdevice.c:1700
bool IsAtsc(void) const
Definition: channels.h:185
cString GetBondingParams(const cChannel *Channel=NULL) const
Definition: dvbdevice.c:436
bool SetFrontendType(const cChannel *Channel)
#define ATSC_TUNE_TIMEOUT
Definition: dvbdevice.c:32
const char * userString
Definition: dvbdevice.h:86
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: dvbdevice.c:1720
cDvbTransponderParameters dtp
Definition: dvbdevice.c:1060
static cString DvbName(const char *Name, int Adapter, int Frontend)
Definition: dvbdevice.c:1191
The cDevice class is the base from which actual devices can be derived.
Definition: device.h:109
Definition: tools.h:168
static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError=false)
Definition: dvbdevice.c:1196
cDvbTuner * bondedTuner
Definition: dvbdevice.c:323
const cDvbDevice * device
Definition: dvbdevice.c:305
const tDvbParameterMap GuardValues[]
Definition: dvbdevice.c:122
virtual void GetData(cChannel *Channel)
Copies all source specific parameters to the given Channel.
Definition: dvbdevice.c:1082
const tDvbParameterMap TransmissionValues[]
Definition: dvbdevice.c:111
static void SetTransferModeForDolbyDigital(int Mode)
Definition: dvbdevice.c:1737
void Unlock(void)
Definition: thread.c:197
virtual bool ProvidesEIT(void) const
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...
Definition: dvbdevice.c:1685
int DiSEqC
Definition: config.h:274