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  bool SetIdle(bool Idle);
356  bool IsIdle(void) const { return isIdle; }
357  };
358 
360 
361 cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
362 {
363  frontendType = SYS_UNDEFINED;
364  device = Device;
365  fd_frontend = Fd_Frontend;
366  adapter = Adapter;
367  frontend = Frontend;
369  tuneTimeout = 0;
370  lockTimeout = 0;
371  lastTimeoutReport = 0;
372  lastDiseqc = NULL;
373  diseqcOffset = 0;
374  lastSource = 0;
375  positioner = NULL;
376  scr = NULL;
377  lnbPowerTurnedOn = false;
379  bondedTuner = NULL;
380  bondedMaster = false;
381  isIdle = false;
382  SetDescription("frontend %d/%d tuner", adapter, frontend);
383  Start();
384 }
385 
387 {
389  newSet.Broadcast();
390  locked.Broadcast();
391  Cancel(3);
392  UnBond();
393  /* looks like this irritates the SCR switch, so let's leave it out for now
394  if (lastDiseqc && lastDiseqc->IsScr()) {
395  unsigned int Frequency = 0;
396  ExecuteDiseqc(lastDiseqc, &Frequency);
397  }
398  */
399  if (device && device->IsSubDevice())
400  CloseFrontend();
401 }
402 
404 {
405  cMutexLock MutexLock(&bondMutex);
406  if (!bondedTuner) {
408  bondedMaster = false; // makes sure we don't disturb an existing master
409  bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
410  Tuner->bondedTuner = this;
411  dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
412  return true;
413  }
414  else
415  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);
416  return false;
417 }
418 
420 {
421  cMutexLock MutexLock(&bondMutex);
422  if (cDvbTuner *t = bondedTuner) {
423  dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
424  while (t->bondedTuner != this)
425  t = t->bondedTuner;
426  if (t == bondedTuner)
427  t->bondedTuner = NULL;
428  else
429  t->bondedTuner = bondedTuner;
430  bondedMaster = false; // another one will automatically become master whenever necessary
431  bondedTuner = NULL;
432  }
433 }
434 
436 {
437  if (!Channel)
438  Channel = &channel;
439  cDvbTransponderParameters dtp(Channel->Parameters());
440  if (Setup.DiSEqC) {
441  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL))
442  return diseqc->Commands();
443  }
444  else {
445  bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
446  bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
447  return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
448  }
449  return "";
450 }
451 
452 bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
453 {
454  cMutexLock MutexLock(&bondMutex);
455  if (cDvbTuner *t = bondedTuner) {
456  cString BondingParams = GetBondingParams(Channel);
457  do {
458  if (t->device->Priority() > IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
459  if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
460  return false;
461  }
462  t = t->bondedTuner;
463  } while (t != bondedTuner);
464  }
465  return true;
466 }
467 
469 {
470  if (!bondedTuner)
471  return this; // an unbonded tuner is always "master"
472  cMutexLock MutexLock(&bondMutex);
473  if (bondedMaster)
474  return this;
475  // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
476  if (cDvbTuner *t = bondedTuner) {
477  while (t != this) {
478  if (t->bondedMaster)
479  return t;
480  t = t->bondedTuner;
481  }
482  }
483  // None of the other bonded tuners is master, so make this one the master:
484  bondedMaster = true;
485  dsyslog("tuner %d/%d is now bonded master", adapter, frontend);
486  return this;
487 }
488 
489 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
490 {
491  if (tunerStatus == tsIdle)
492  return false; // not tuned to
493  if (channel.Source() != Channel->Source() || channel.Transponder() != Channel->Transponder())
494  return false; // sufficient mismatch
495  // Polarization is already checked as part of the Transponder.
496  return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
497 }
498 
499 void cDvbTuner::SetChannel(const cChannel *Channel)
500 {
501  if (Channel) {
502  if (bondedTuner) {
503  cMutexLock MutexLock(&bondMutex);
504  cDvbTuner *BondedMaster = GetBondedMaster();
505  if (BondedMaster == this) {
506  if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
507  // switching to a completely different band, so set all others to idle:
508  for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
509  t->SetChannel(NULL);
510  }
511  }
512  else if (strcmp(GetBondingParams(Channel), BondedMaster->GetBondingParams()) != 0)
513  BondedMaster->SetChannel(Channel);
514  }
515  cMutexLock MutexLock(&mutex);
516  if (!IsTunedTo(Channel))
517  tunerStatus = tsSet;
518  diseqcOffset = 0;
519  channel = *Channel;
520  lastTimeoutReport = 0;
521  newSet.Broadcast();
522  }
523  else {
524  cMutexLock MutexLock(&mutex);
527  }
529  cDevice::PrimaryDevice()->DelLivePids(); // 'device' is const, so we must do it this way
530 }
531 
532 bool cDvbTuner::Locked(int TimeoutMs)
533 {
534  bool isLocked = (tunerStatus >= tsLocked);
535  if (isLocked || !TimeoutMs)
536  return isLocked;
537 
538  cMutexLock MutexLock(&mutex);
539  if (TimeoutMs && tunerStatus < tsLocked)
540  locked.TimedWait(mutex, TimeoutMs);
541  return tunerStatus >= tsLocked;
542 }
543 
545 {
546  if (!OpenFrontend())
547  return;
548  cPoller Poller(fd_frontend);
549  if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
550  dvb_frontend_event Event;
551  while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
552  ; // just to clear the event queue - we'll read the actual status below
553  }
554 }
555 
556 bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
557 {
558  ClearEventQueue();
559  while (1) {
560  if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
561  return true;
562  if (errno != EINTR)
563  break;
564  }
565  return false;
566 }
567 
568 //#define DEBUG_SIGNALSTRENGTH
569 //#define DEBUG_SIGNALQUALITY
570 
572 {
573  ClearEventQueue();
574  uint16_t Signal;
575  while (1) {
576  if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
577  break;
578  if (errno != EINTR)
579  return -1;
580  }
581  uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
582  // Use the subsystemId to identify individual devices in case they need
583  // special treatment to map their Signal value into the range 0...0xFFFF.
584  switch (subsystemId) {
585  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
586  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
587  MaxSignal = 670; break;
588  }
589  int s = int(Signal) * 100 / MaxSignal;
590  if (s > 100)
591  s = 100;
592 #ifdef DEBUG_SIGNALSTRENGTH
593  fprintf(stderr, "FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
594 #endif
595  return s;
596 }
597 
598 #define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
599 
601 {
602  fe_status_t Status;
603  if (GetFrontendStatus(Status)) {
604  // 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...
605  if ((Status & FE_HAS_LOCK) == 0) {
606  if ((Status & FE_HAS_SIGNAL) == 0)
607  return 0;
608  if ((Status & FE_HAS_CARRIER) == 0)
609  return 1;
610  if ((Status & FE_HAS_VITERBI) == 0)
611  return 2;
612  if ((Status & FE_HAS_SYNC) == 0)
613  return 3;
614  return 4;
615  }
616 #ifdef DEBUG_SIGNALQUALITY
617  bool HasSnr = true;
618 #endif
619  uint16_t Snr;
620  while (1) {
621  if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
622  break;
623  if (errno != EINTR) {
624  Snr = 0xFFFF;
625 #ifdef DEBUG_SIGNALQUALITY
626  HasSnr = false;
627 #endif
628  break;
629  }
630  }
631 #ifdef DEBUG_SIGNALQUALITY
632  bool HasBer = true;
633 #endif
634  uint32_t Ber;
635  while (1) {
636  if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
637  break;
638  if (errno != EINTR) {
639  Ber = 0;
640 #ifdef DEBUG_SIGNALQUALITY
641  HasBer = false;
642 #endif
643  break;
644  }
645  }
646 #ifdef DEBUG_SIGNALQUALITY
647  bool HasUnc = true;
648 #endif
649  uint32_t Unc;
650  while (1) {
651  if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
652  break;
653  if (errno != EINTR) {
654  Unc = 0;
655 #ifdef DEBUG_SIGNALQUALITY
656  HasUnc = false;
657 #endif
658  break;
659  }
660  }
661  uint16_t MinSnr = 0x0000;
662  uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
663  // Use the subsystemId to identify individual devices in case they need
664  // special treatment to map their Snr value into the range 0...0xFFFF.
665  switch (subsystemId) {
666  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
667  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
668  if (frontendType == SYS_DVBS2) {
669  MinSnr = 10;
670  MaxSnr = 70;
671  }
672  else
673  MaxSnr = 200;
674  break;
675  case 0x20130245: // PCTV Systems PCTV 73ESE
676  case 0x2013024F: // PCTV Systems nanoStick T2 290e
677  MaxSnr = 255; break;
678  }
679  int a = int(constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
680  int b = 100 - (Unc * 10 + (Ber / 256) * 5);
681  if (b < 0)
682  b = 0;
683  int q = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
684  if (q > 100)
685  q = 100;
686 #ifdef DEBUG_SIGNALQUALITY
687  fprintf(stderr, "FE %d/%d: %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
688 #endif
689  return q;
690  }
691  return -1;
692 }
693 
694 static unsigned int FrequencyToHz(unsigned int f)
695 {
696  while (f && f < 1000000)
697  f *= 1000;
698  return f;
699 }
700 
702 {
703  if (!positioner) {
706  }
707  return positioner;
708 }
709 
710 void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
711 {
712  if (!lnbPowerTurnedOn) {
713  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
714  lnbPowerTurnedOn = true;
715  }
716  static cMutex Mutex;
717  if (Diseqc->IsScr())
718  Mutex.Lock();
719  struct dvb_diseqc_master_cmd cmd;
720  const char *CurrentAction = NULL;
721  cPositioner *Positioner = NULL;
722  bool Break = false;
723  for (int i = 0; !Break; i++) {
724  cmd.msg_len = sizeof(cmd.msg);
725  cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
726  if (da == cDiseqc::daNone) {
727  diseqcOffset = 0;
728  break;
729  }
730  bool d = i >= diseqcOffset;
731  switch (da) {
732  case cDiseqc::daToneOff: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
733  case cDiseqc::daToneOn: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
734  case cDiseqc::daVoltage13: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
735  case cDiseqc::daVoltage18: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
736  case cDiseqc::daMiniA: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
737  case cDiseqc::daMiniB: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
738  case cDiseqc::daCodes: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break;
739  case cDiseqc::daPositionN: if ((Positioner = GetPositioner()) != NULL) {
740  if (d) {
741  Positioner->GotoPosition(Diseqc->Position(), cSource::Position(channel.Source()));
742  Break = Positioner->IsMoving();
743  }
744  }
745  break;
746  case cDiseqc::daPositionA: if ((Positioner = GetPositioner()) != NULL) {
747  if (d) {
748  Positioner->GotoAngle(cSource::Position(channel.Source()));
749  Break = Positioner->IsMoving();
750  }
751  }
752  break;
753  case cDiseqc::daScr:
754  case cDiseqc::daWait: break;
755  default: esyslog("ERROR: unknown diseqc command %d", da);
756  }
757  if (Break)
758  diseqcOffset = i + 1;
759  }
761  if (scr && !Break)
762  ResetToneAndVoltage(); // makes sure we don't block the bus!
763  if (Diseqc->IsScr())
764  Mutex.Unlock();
765 }
766 
768 {
769  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
770  CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
771 }
772 
773 static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
774 {
775  int ds = SYS_UNDEFINED;
776  if (Channel->IsAtsc())
777  ds = SYS_ATSC;
778  else if (Channel->IsCable())
779  ds = SYS_DVBC_ANNEX_AC;
780  else if (Channel->IsSat())
781  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBS : SYS_DVBS2;
782  else if (Channel->IsTerr())
783  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBT : SYS_DVBT2;
784  else
785  esyslog("ERROR: can't determine frontend type for channel %d (%s)", Channel->Number(), Channel->Name());
786  return ds;
787 }
788 
790 {
791  if (!OpenFrontend())
792  return false;
793 #define MAXFRONTENDCMDS 16
794 #define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\
795  Frontend[CmdSeq.num].u.data = (d);\
796  if (CmdSeq.num++ > MAXFRONTENDCMDS) {\
797  esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\
798  return false;\
799  }\
800  }
801  dtv_property Frontend[MAXFRONTENDCMDS];
802  memset(&Frontend, 0, sizeof(Frontend));
803  dtv_properties CmdSeq;
804  memset(&CmdSeq, 0, sizeof(CmdSeq));
805  CmdSeq.props = Frontend;
806  SETCMD(DTV_CLEAR, 0);
807  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
808  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
809  return false;
810  }
811  CmdSeq.num = 0;
812 
814 
815  // Determine the required frontend type:
817  if (frontendType == SYS_UNDEFINED)
818  return false;
819 
820  SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
821  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
822  unsigned int frequency = channel.Frequency();
823  if (Setup.DiSEqC) {
824  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
825  frequency -= diseqc->Lof();
826  if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
827  if (IsBondedMaster()) {
828  ExecuteDiseqc(diseqc, &frequency);
829  if (frequency == 0)
830  return false;
831  }
832  else
834  lastDiseqc = diseqc;
836  }
837  }
838  else {
839  esyslog("ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
840  return false;
841  }
842  }
843  else {
844  int tone = SEC_TONE_OFF;
845  if (frequency < (unsigned int)Setup.LnbSLOF) {
846  frequency -= Setup.LnbFrequLo;
847  tone = SEC_TONE_OFF;
848  }
849  else {
850  frequency -= Setup.LnbFrequHi;
851  tone = SEC_TONE_ON;
852  }
853  int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
854  if (!IsBondedMaster()) {
855  tone = SEC_TONE_OFF;
856  volt = SEC_VOLTAGE_13;
857  }
858  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
859  CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
860  }
861  frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
862 
863  // DVB-S/DVB-S2 (common parts)
864  SETCMD(DTV_FREQUENCY, frequency * 1000UL);
865  SETCMD(DTV_MODULATION, dtp.Modulation());
866  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
867  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
868  SETCMD(DTV_INVERSION, dtp.Inversion());
869  if (frontendType == SYS_DVBS2) {
870  // DVB-S2
871  SETCMD(DTV_PILOT, dtp.Pilot());
872  SETCMD(DTV_ROLLOFF, dtp.RollOff());
873  if (DvbApiVersion >= 0x0508)
874  SETCMD(DTV_STREAM_ID, dtp.StreamId());
875  }
876  else {
877  // DVB-S
878  SETCMD(DTV_ROLLOFF, ROLLOFF_35); // DVB-S always has a ROLLOFF of 0.35
879  }
880 
883  }
884  else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
885  // DVB-C
886  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
887  SETCMD(DTV_INVERSION, dtp.Inversion());
888  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
889  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
890  SETCMD(DTV_MODULATION, dtp.Modulation());
891 
894  }
895  else if (frontendType == SYS_DVBT || frontendType == SYS_DVBT2) {
896  // DVB-T/DVB-T2 (common parts)
897  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
898  SETCMD(DTV_INVERSION, dtp.Inversion());
899  SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
900  SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
901  SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
902  SETCMD(DTV_MODULATION, dtp.Modulation());
903  SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
904  SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
905  SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
906  if (frontendType == SYS_DVBT2) {
907  // DVB-T2
908  if (DvbApiVersion >= 0x0508) {
909  SETCMD(DTV_STREAM_ID, dtp.StreamId());
910  }
911  else if (DvbApiVersion >= 0x0503)
912  SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId());
913  }
914 
917  }
918  else if (frontendType == SYS_ATSC) {
919  // ATSC
920  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
921  SETCMD(DTV_INVERSION, dtp.Inversion());
922  SETCMD(DTV_MODULATION, dtp.Modulation());
923 
926  }
927  else {
928  esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
929  return false;
930  }
931  SETCMD(DTV_TUNE, 0);
932  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
933  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
934  return false;
935  }
936  return true;
937 }
938 
940 {
941  cTimeMs Timer;
942  bool LostLock = false;
943  fe_status_t Status = (fe_status_t)0;
944  while (Running()) {
945  if (!isIdle) {
946  fe_status_t NewStatus;
947  if (GetFrontendStatus(NewStatus))
948  Status = NewStatus;
949  }
950  cMutexLock MutexLock(&mutex);
951  int WaitTime = 1000;
952  switch (tunerStatus) {
953  case tsIdle:
954  break; // we want the TimedWait() below!
955  case tsSet:
957  continue;
958  case tsPositioning:
959  if (positioner) {
960  if (positioner->IsMoving())
961  break; // we want the TimedWait() below!
962  else if (diseqcOffset) {
963  lastDiseqc = NULL;
964  tunerStatus = tsSet; // have it process the rest of the DiSEqC sequence
965  continue;
966  }
967  }
969  Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT : 0));
970  if (positioner)
971  continue;
972  // otherwise run directly into tsTuned...
973  case tsTuned:
974  if (Timer.TimedOut()) {
975  tunerStatus = tsSet;
976  lastDiseqc = NULL;
977  lastSource = 0;
978  if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
979  isyslog("frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
980  lastTimeoutReport = time(NULL);
981  }
982  continue;
983  }
984  WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
985  // run into tsLocked...
986  case tsLocked:
987  if (Status & FE_REINIT) {
988  tunerStatus = tsSet;
989  lastDiseqc = NULL;
990  lastSource = 0;
991  isyslog("frontend %d/%d was reinitialized", adapter, frontend);
992  lastTimeoutReport = 0;
993  continue;
994  }
995  else if (Status & FE_HAS_LOCK) {
996  if (LostLock) {
997  isyslog("frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
998  LostLock = false;
999  }
1001  locked.Broadcast();
1002  lastTimeoutReport = 0;
1003  }
1004  else if (tunerStatus == tsLocked) {
1005  LostLock = true;
1006  isyslog("frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1007  tunerStatus = tsTuned;
1008  Timer.Set(lockTimeout);
1009  lastTimeoutReport = 0;
1010  continue;
1011  }
1012  break;
1013  default: esyslog("ERROR: unknown tuner status %d", tunerStatus);
1014  }
1015  newSet.TimedWait(mutex, WaitTime);
1016  }
1017 }
1018 
1019 bool cDvbTuner::SetIdle(bool Idle)
1020 {
1021  if (isIdle == Idle)
1022  return true;
1023  isIdle = Idle;
1024  if (Idle)
1025  return CloseFrontend();
1026  return OpenFrontend();
1027 }
1028 
1029 bool cDvbTuner::OpenFrontend(void) const
1030 {
1031  if (fd_frontend >= 0)
1032  return true;
1033  cMutexLock MutexLock(&mutex);
1035  if (fd_frontend < 0)
1036  return false;
1037  isIdle = false;
1038  return true;
1039 }
1040 
1042 {
1043  if (fd_frontend < 0)
1044  return true;
1045  cMutexLock MutexLock(&mutex);
1046  tunerStatus = tsIdle;
1047  newSet.Broadcast();
1048  close(fd_frontend);
1049  fd_frontend = -1;
1050  return true;
1051 }
1052 
1053 // --- cDvbSourceParam -------------------------------------------------------
1054 
1056 private:
1057  int param;
1058  int srate;
1060 public:
1061  cDvbSourceParam(char Source, const char *Description);
1062  virtual void SetData(cChannel *Channel);
1063  virtual void GetData(cChannel *Channel);
1064  virtual cOsdItem *GetOsdItem(void);
1065  };
1066 
1067 cDvbSourceParam::cDvbSourceParam(char Source, const char *Description)
1068 :cSourceParam(Source, Description)
1069 {
1070  param = 0;
1071  srate = 0;
1072 }
1073 
1075 {
1076  srate = Channel->Srate();
1077  dtp.Parse(Channel->Parameters());
1078  param = 0;
1079 }
1080 
1082 {
1083  Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), srate, dtp.ToString(Source()), true);
1084 }
1085 
1087 {
1088  char type = Source();
1089  const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr;
1090 #undef ST
1091 #define ST(s) if (strchr(s, type))
1092  switch (param++) {
1093  case 0: ST(" S ") return new cMenuEditChrItem( tr("Polarization"), &dtp.polarization, "HVLR"); else return GetOsdItem();
1094  case 1: ST(" ST") return new cMenuEditMapItem( tr("System"), &dtp.system, SystemValues); else return GetOsdItem();
1095  case 2: ST(" CS ") return new cMenuEditIntItem( tr("Srate"), &srate); else return GetOsdItem();
1096  case 3: ST("ACST") return new cMenuEditMapItem( tr("Inversion"), &dtp.inversion, InversionValues); else return GetOsdItem();
1097  case 4: ST(" CST") return new cMenuEditMapItem( tr("CoderateH"), &dtp.coderateH, CoderateValues); else return GetOsdItem();
1098  case 5: ST(" T") return new cMenuEditMapItem( tr("CoderateL"), &dtp.coderateL, CoderateValues); else return GetOsdItem();
1099  case 6: ST("ACST") return new cMenuEditMapItem( tr("Modulation"), &dtp.modulation, ModulationValues); else return GetOsdItem();
1100  case 7: ST(" T") return new cMenuEditMapItem( tr("Bandwidth"), &dtp.bandwidth, BandwidthValues); else return GetOsdItem();
1101  case 8: ST(" T") return new cMenuEditMapItem( tr("Transmission"), &dtp.transmission, TransmissionValues); else return GetOsdItem();
1102  case 9: ST(" T") return new cMenuEditMapItem( tr("Guard"), &dtp.guard, GuardValues); else return GetOsdItem();
1103  case 10: ST(" T") return new cMenuEditMapItem( tr("Hierarchy"), &dtp.hierarchy, HierarchyValues); else return GetOsdItem();
1104  case 11: ST(" S ") return new cMenuEditMapItem( tr("Rolloff"), &dtp.rollOff, RollOffValues); else return GetOsdItem();
1105  case 12: ST(" ST") return new cMenuEditIntItem( tr("StreamId"), &dtp.streamId, 0, 255); else return GetOsdItem();
1106  case 13: ST(" S ") return new cMenuEditMapItem( tr("Pilot"), &dtp.pilot, PilotValues); else return GetOsdItem();
1107  case 14: ST(" T") return new cMenuEditIntItem( tr("T2SystemId"), &dtp.t2systemId, 0, 65535); else return GetOsdItem();
1108  case 15: ST(" T") return new cMenuEditIntItem( tr("SISO/MISO"), &dtp.sisoMiso, 0, 1); else return GetOsdItem();
1109  default: return NULL;
1110  }
1111  return NULL;
1112 }
1113 
1114 // --- cDvbDevice ------------------------------------------------------------
1115 
1118 
1119 const char *DeliverySystemNames[] = {
1120  "",
1121  "DVB-C",
1122  "DVB-C",
1123  "DVB-T",
1124  "DSS",
1125  "DVB-S",
1126  "DVB-S2",
1127  "DVB-H",
1128  "ISDBT",
1129  "ISDBS",
1130  "ISDBC",
1131  "ATSC",
1132  "ATSCMH",
1133  "DMBTH",
1134  "CMMB",
1135  "DAB",
1136  "DVB-T2",
1137  "TURBO",
1138  NULL
1139  };
1140 
1141 cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice)
1142 :cDevice(ParentDevice)
1143 {
1144  adapter = Adapter;
1145  frontend = Frontend;
1146  ciAdapter = NULL;
1147  dvbTuner = NULL;
1148  numDeliverySystems = 0;
1149  numModulations = 0;
1150  bondedDevice = NULL;
1152  tsBuffer = NULL;
1153 
1154  // Devices that are present on all card types:
1155 
1156  int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
1157 
1158  // Common Interface:
1159 
1160  fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
1161  if (fd_ca >= 0)
1163 
1164  // The DVR device (will be opened and closed as needed):
1165 
1166  fd_dvr = -1;
1167 
1168  // We only check the devices that must be present - the others will be checked before accessing them://XXX
1169 
1170  if (fd_frontend >= 0) {
1171  if (QueryDeliverySystems(fd_frontend))
1172  dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend);
1173  }
1174  else
1175  esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
1176 
1178 }
1179 
1181 {
1183  delete dvbTuner;
1184  delete ciAdapter;
1185  UnBond();
1186  // We're not explicitly closing any device files here, since this sometimes
1187  // caused segfaults. Besides, the program is about to terminate anyway...
1188 }
1189 
1190 cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
1191 {
1192  return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE, DEV_DVB_ADAPTER, Adapter, Name, Frontend);
1193 }
1194 
1195 int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
1196 {
1197  cString FileName = DvbName(Name, Adapter, Frontend);
1198  int fd = open(FileName, Mode);
1199  if (fd < 0 && ReportError)
1200  LOG_ERROR_STR(*FileName);
1201  return fd;
1202 }
1203 
1204 bool cDvbDevice::Exists(int Adapter, int Frontend)
1205 {
1206  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
1207  if (access(FileName, F_OK) == 0) {
1208  int f = open(FileName, O_RDONLY);
1209  if (f >= 0) {
1210  close(f);
1211  return true;
1212  }
1213  else if (errno != ENODEV && errno != EINVAL)
1214  LOG_ERROR_STR(*FileName);
1215  }
1216  else if (errno != ENOENT)
1217  LOG_ERROR_STR(*FileName);
1218  return false;
1219 }
1220 
1221 bool cDvbDevice::Probe(int Adapter, int Frontend)
1222 {
1223  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
1224  dsyslog("probing %s", *FileName);
1225  for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
1226  if (dp->Probe(Adapter, Frontend))
1227  return true; // a plugin has created the actual device
1228  }
1229  dsyslog("creating cDvbDevice");
1230  new cDvbDevice(Adapter, Frontend); // it's a "budget" device
1231  return true;
1232 }
1233 
1235 {
1236  if (dvbTuner) {
1237  if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1239  if (numDeliverySystems)
1240  return DeliverySystemNames[deliverySystems[0]]; // to have some reasonable default
1241  }
1242  return "";
1243 }
1244 
1246 {
1247  return frontendInfo.name;
1248 }
1249 
1251 {
1252  new cDvbSourceParam('A', "ATSC");
1253  new cDvbSourceParam('C', "DVB-C");
1254  new cDvbSourceParam('S', "DVB-S");
1255  new cDvbSourceParam('T', "DVB-T");
1256  cStringList Nodes;
1257  cReadDir DvbDir(DEV_DVB_BASE);
1258  if (DvbDir.Ok()) {
1259  struct dirent *a;
1260  while ((a = DvbDir.Next()) != NULL) {
1261  if (strstr(a->d_name, DEV_DVB_ADAPTER) == a->d_name) {
1262  int Adapter = strtol(a->d_name + strlen(DEV_DVB_ADAPTER), NULL, 10);
1263  cReadDir AdapterDir(AddDirectory(DEV_DVB_BASE, a->d_name));
1264  if (AdapterDir.Ok()) {
1265  struct dirent *f;
1266  while ((f = AdapterDir.Next()) != NULL) {
1267  if (strstr(f->d_name, DEV_DVB_FRONTEND) == f->d_name) {
1268  int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND), NULL, 10);
1269  Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
1270  }
1271  }
1272  }
1273  }
1274  }
1275  }
1276  int Found = 0;
1277  int Used = 0;
1278  if (Nodes.Size() > 0) {
1279  Nodes.Sort();
1280  for (int i = 0; i < Nodes.Size(); i++) {
1281  int Adapter;
1282  int Frontend;
1283  if (2 == sscanf(Nodes[i], "%d %d", &Adapter, &Frontend)) {
1284  if (Exists(Adapter, Frontend)) {
1285  if (Found < MAXDEVICES) {
1286  Found++;
1287  if (UseDevice(NextCardIndex())) {
1288  if (Probe(Adapter, Frontend))
1289  Used++;
1290  }
1291  else
1292  NextCardIndex(1); // skips this one
1293  }
1294  }
1295  }
1296  }
1297  }
1298  if (Found > 0) {
1299  isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "");
1300  if (Used != Found)
1301  isyslog("using only %d DVB device%s", Used, Used > 1 ? "s" : "");
1302  }
1303  else
1304  isyslog("no DVB device found");
1305  return Found > 0;
1306 }
1307 
1309 {
1310  numDeliverySystems = 0;
1311  if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
1312  LOG_ERROR;
1313  return false;
1314  }
1315  dtv_property Frontend[1];
1316  dtv_properties CmdSeq;
1317  // Determine the version of the running DVB API:
1318  if (!DvbApiVersion) {
1319  memset(&Frontend, 0, sizeof(Frontend));
1320  memset(&CmdSeq, 0, sizeof(CmdSeq));
1321  CmdSeq.props = Frontend;
1322  SETCMD(DTV_API_VERSION, 0);
1323  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1324  LOG_ERROR;
1325  return false;
1326  }
1327  DvbApiVersion = Frontend[0].u.data;
1328  isyslog("DVB API version is 0x%04X (VDR was built with 0x%04X)", DvbApiVersion, DVBAPIVERSION);
1329  }
1330  // Determine the types of delivery systems this device provides:
1331  bool LegacyMode = true;
1332  if (DvbApiVersion >= 0x0505) {
1333  memset(&Frontend, 0, sizeof(Frontend));
1334  memset(&CmdSeq, 0, sizeof(CmdSeq));
1335  CmdSeq.props = Frontend;
1336  SETCMD(DTV_ENUM_DELSYS, 0);
1337  int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
1338  if (Result == 0) {
1339  for (uint i = 0; i < Frontend[0].u.buffer.len; i++) {
1341  esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
1342  break;
1343  }
1344  deliverySystems[numDeliverySystems++] = Frontend[0].u.buffer.data[i];
1345  }
1346  LegacyMode = false;
1347  }
1348  else {
1349  esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
1350  }
1351  }
1352  if (LegacyMode) {
1353  // Legacy mode (DVB-API < 5.5):
1354  switch (frontendInfo.type) {
1355  case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1357  deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1358  break;
1359  case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1362  break;
1363  case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC; break;
1364  case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break;
1365  default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
1366  }
1367  }
1368  if (numDeliverySystems > 0) {
1369  cString ds("");
1370  for (int i = 0; i < numDeliverySystems; i++)
1371  ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", DeliverySystemNames[deliverySystems[i]]);
1372  cString ms("");
1373  if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
1374  if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
1375  if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); }
1376  if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); }
1377  if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); }
1378  if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); }
1379  if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); }
1380  if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); }
1381  if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); }
1382  if (!**ms)
1383  ms = "unknown modulations";
1384  isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
1385  return true;
1386  }
1387  else
1388  esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
1389  return false;
1390 }
1391 
1392 bool cDvbDevice::BondDevices(const char *Bondings)
1393 {
1394  UnBondDevices();
1395  if (Bondings) {
1396  cSatCableNumbers SatCableNumbers(MAXDEVICES, Bondings);
1397  for (int i = 0; i < cDevice::NumDevices(); i++) {
1398  int d = SatCableNumbers.FirstDeviceIndex(i);
1399  if (d >= 0) {
1400  int ErrorDevice = 0;
1401  if (cDevice *Device1 = cDevice::GetDevice(i)) {
1402  if (Device1->HasSubDevice())
1403  Device1 = Device1->SubDevice();
1404  if (cDevice *Device2 = cDevice::GetDevice(d)) {
1405  if (Device2->HasSubDevice())
1406  Device2 = Device2->SubDevice();
1407  if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1408  if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1409  if (!DvbDevice1->Bond(DvbDevice2))
1410  return false; // Bond() has already logged the error
1411  }
1412  else
1413  ErrorDevice = d + 1;
1414  }
1415  else
1416  ErrorDevice = i + 1;
1417  if (ErrorDevice) {
1418  esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
1419  return false;
1420  }
1421  }
1422  else
1423  ErrorDevice = d + 1;
1424  }
1425  else
1426  ErrorDevice = i + 1;
1427  if (ErrorDevice) {
1428  esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
1429  return false;
1430  }
1431  }
1432  }
1433  }
1434  return true;
1435 }
1436 
1438 {
1439  for (int i = 0; i < cDevice::NumDevices(); i++) {
1440  cDevice *dev = cDevice::GetDevice(i);
1441  if (dev && dev->HasSubDevice())
1442  dev = dev->SubDevice();
1443  if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(dev))
1444  d->UnBond();
1445  }
1446 }
1447 
1449 {
1450  cMutexLock MutexLock(&bondMutex);
1451  if (!bondedDevice) {
1452  if (Device != this) {
1453  if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) {
1454  if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
1455  bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
1456  Device->bondedDevice = this;
1457  dsyslog("device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1458  return true;
1459  }
1460  }
1461  else
1462  esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->CardIndex() + 1);
1463  }
1464  else
1465  esyslog("ERROR: can't bond device %d with itself", CardIndex() + 1);
1466  }
1467  else
1468  esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->CardIndex() + 1);
1469  return false;
1470 }
1471 
1473 {
1474  cMutexLock MutexLock(&bondMutex);
1475  if (cDvbDevice *d = bondedDevice) {
1476  if (dvbTuner)
1477  dvbTuner->UnBond();
1478  dsyslog("device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1479  while (d->bondedDevice != this)
1480  d = d->bondedDevice;
1481  if (d == bondedDevice)
1482  d->bondedDevice = NULL;
1483  else
1484  d->bondedDevice = bondedDevice;
1485  bondedDevice = NULL;
1486  }
1487 }
1488 
1489 bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
1490 {
1491  cMutexLock MutexLock(&bondMutex);
1492  if (bondedDevice || Positioner())
1493  return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1494  return true;
1495 }
1496 
1497 bool cDvbDevice::SetIdleDevice(bool Idle, bool TestOnly)
1498 {
1499  if (TestOnly) {
1500  if (ciAdapter)
1501  return ciAdapter->SetIdle(Idle, true);
1502  return true;
1503  }
1504  if (!dvbTuner->SetIdle(Idle))
1505  return false;
1506  if (ciAdapter && !ciAdapter->SetIdle(Idle, false)) {
1507  dvbTuner->SetIdle(!Idle);
1508  return false;
1509  }
1510  if (Idle)
1512  else
1514  return true;
1515 }
1516 
1518 {
1519  return ciAdapter;
1520 }
1521 
1522 bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
1523 {
1524  if (Handle->pid) {
1525  dmx_pes_filter_params pesFilterParams;
1526  memset(&pesFilterParams, 0, sizeof(pesFilterParams));
1527  if (On) {
1528  if (Handle->handle < 0) {
1529  Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
1530  if (Handle->handle < 0) {
1531  LOG_ERROR;
1532  return false;
1533  }
1534  }
1535  pesFilterParams.pid = Handle->pid;
1536  pesFilterParams.input = DMX_IN_FRONTEND;
1537  pesFilterParams.output = DMX_OUT_TS_TAP;
1538  pesFilterParams.pes_type= DMX_PES_OTHER;
1539  pesFilterParams.flags = DMX_IMMEDIATE_START;
1540  if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
1541  LOG_ERROR;
1542  return false;
1543  }
1544  }
1545  else if (!Handle->used) {
1546  CHECK(ioctl(Handle->handle, DMX_STOP));
1547  if (Type <= ptTeletext) {
1548  pesFilterParams.pid = 0x1FFF;
1549  pesFilterParams.input = DMX_IN_FRONTEND;
1550  pesFilterParams.output = DMX_OUT_DECODER;
1551  pesFilterParams.pes_type= DMX_PES_OTHER;
1552  pesFilterParams.flags = DMX_IMMEDIATE_START;
1553  CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
1554  }
1555  close(Handle->handle);
1556  Handle->handle = -1;
1557  }
1558  }
1559  return true;
1560 }
1561 
1562 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
1563 {
1565  int f = open(FileName, O_RDWR | O_NONBLOCK);
1566  if (f >= 0) {
1567  dmx_sct_filter_params sctFilterParams;
1568  memset(&sctFilterParams, 0, sizeof(sctFilterParams));
1569  sctFilterParams.pid = Pid;
1570  sctFilterParams.timeout = 0;
1571  sctFilterParams.flags = DMX_IMMEDIATE_START;
1572  sctFilterParams.filter.filter[0] = Tid;
1573  sctFilterParams.filter.mask[0] = Mask;
1574  if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
1575  return f;
1576  else {
1577  esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
1578  close(f);
1579  }
1580  }
1581  else
1582  esyslog("ERROR: can't open filter handle on '%s'", *FileName);
1583  return -1;
1584 }
1585 
1586 void cDvbDevice::CloseFilter(int Handle)
1587 {
1588  close(Handle);
1589 }
1590 
1591 bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
1592 {
1593  for (int i = 0; i < numDeliverySystems; i++) {
1594  if (deliverySystems[i] == DeliverySystem)
1595  return true;
1596  }
1597  return false;
1598 }
1599 
1600 bool cDvbDevice::ProvidesSource(int Source) const
1601 {
1602  int type = Source & cSource::st_Mask;
1603  return type == cSource::stNone
1604  || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
1605  || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
1606  || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
1608 }
1609 
1610 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
1611 {
1612  if (!ProvidesSource(Channel->Source()))
1613  return false; // doesn't provide source
1614  cDvbTransponderParameters dtp(Channel->Parameters());
1615  if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) ||
1616  dtp.StreamId() != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM) ||
1617  dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
1618  dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
1619  dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
1620  dtp.Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
1621  dtp.Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
1622  dtp.Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
1623  dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
1624  dtp.Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
1625  dtp.Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
1626  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
1627  return false; // requires modulation system which frontend doesn't provide
1628  if (!cSource::IsSat(Channel->Source()) ||
1629  (!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
1630  return DeviceHooksProvidesTransponder(Channel);
1631  return false;
1632 }
1633 
1634 bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
1635 {
1636  bool result = false;
1637  bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
1638  bool needsDetachReceivers = false;
1640 
1641  if (dvbTuner && ProvidesTransponder(Channel)) {
1642  result = hasPriority;
1643  if (Priority > IDLEPRIORITY) {
1644  if (Receiving()) {
1645  if (dvbTuner->IsTunedTo(Channel)) {
1646  if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0)) || Channel->Dpid(0) && !HasPid(Channel->Dpid(0))) {
1647  if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
1648  if (CamSlot()->CanDecrypt(Channel))
1649  result = true;
1650  else
1651  needsDetachReceivers = true;
1652  }
1653  else
1654  result = true;
1655  }
1656  else
1657  result = true;
1658  }
1659  else
1660  needsDetachReceivers = Receiving();
1661  }
1662  if (result) {
1663  cMutexLock MutexLock(&bondMutex);
1664  if (!BondingOk(Channel)) {
1665  // This device is bonded, so we need to check the priorities of the others:
1666  for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
1667  if (d->Priority() >= Priority) {
1668  result = false;
1669  break;
1670  }
1671  needsDetachReceivers |= d->Receiving();
1672  }
1674  needsDetachReceivers |= Receiving();
1675  }
1676  }
1677  }
1678  }
1679  if (NeedsDetachReceivers)
1680  *NeedsDetachReceivers = needsDetachReceivers;
1681  return result;
1682 }
1683 
1684 bool cDvbDevice::ProvidesEIT(void) const
1685 {
1686  return !IsIdle() && (dvbTuner != NULL) && !dvbTuner->IsIdle() && ((ciAdapter == NULL) || !ciAdapter->IsIdle());
1687 }
1688 
1690 {
1692 }
1693 
1695 {
1696  return dvbTuner ? dvbTuner->Positioner() : NULL;
1697 }
1698 
1700 {
1701  return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
1702 }
1703 
1705 {
1706  return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
1707 }
1708 
1710 {
1711  return dvbTuner ? dvbTuner->GetTransponder() : NULL;
1712 }
1713 
1714 bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) const
1715 {
1716  return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
1717 }
1718 
1719 bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
1720 {
1721  return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
1722 }
1723 
1724 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
1725 {
1726  if (dvbTuner)
1727  dvbTuner->SetChannel(Channel);
1728  return true;
1729 }
1730 
1731 bool cDvbDevice::HasLock(int TimeoutMs) const
1732 {
1733  return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
1734 }
1735 
1737 {
1739 }
1740 
1742 {
1743  CloseDvr();
1744  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
1745  if (fd_dvr >= 0)
1746  tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5), CardIndex() + 1);
1747  return fd_dvr >= 0;
1748 }
1749 
1751 {
1752  if (fd_dvr >= 0) {
1753  delete tsBuffer;
1754  tsBuffer = NULL;
1755  close(fd_dvr);
1756  fd_dvr = -1;
1757  }
1758 }
1759 
1761 {
1762  if (tsBuffer) {
1763  if (cCamSlot *cs = CamSlot()) {
1764  if (cs->WantsTsData()) {
1765  int Available;
1766  Data = tsBuffer->Get(&Available);
1767  if (Data) {
1768  Data = cs->Decrypt(Data, Available);
1769  tsBuffer->Skip(Available);
1770  }
1771  return true;
1772  }
1773  }
1774  Data = tsBuffer->Get();
1775  return true;
1776  }
1777  return false;
1778 }
1779 
1781 {
1782  cMutexLock MutexLock(&bondMutex);
1783  cDvbDevice *d = this;
1784  do {
1785  d->cDevice::DetachAllReceivers();
1786  d = d->bondedDevice;
1787  } while (d && d != this && needsDetachBondedReceivers);
1789 }
1790 
1791 // --- cDvbDeviceProbe -------------------------------------------------------
1792 
1794 
1796 {
1797  DvbDeviceProbes.Add(this);
1798 }
1799 
1801 {
1802  DvbDeviceProbes.Del(this, false);
1803 }
1804 
1805 uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
1806 {
1807  uint32_t SubsystemId = 0;
1808  cString FileName = cString::sprintf("/dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
1809  struct stat st;
1810  if (stat(FileName, &st) == 0) {
1811  cReadDir d("/sys/class/dvb");
1812  if (d.Ok()) {
1813  struct dirent *e;
1814  while ((e = d.Next()) != NULL) {
1815  if (strstr(e->d_name, "frontend")) {
1816  FileName = cString::sprintf("/sys/class/dvb/%s/dev", e->d_name);
1817  if (FILE *f = fopen(FileName, "r")) {
1818  cReadLine ReadLine;
1819  char *s = ReadLine.Read(f);
1820  fclose(f);
1821  unsigned Major;
1822  unsigned Minor;
1823  if (s && 2 == sscanf(s, "%u:%u", &Major, &Minor)) {
1824  if (((Major << 8) | Minor) == st.st_rdev) {
1825  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
1826  if ((f = fopen(FileName, "r")) != NULL) {
1827  if (char *s = ReadLine.Read(f))
1828  SubsystemId = strtoul(s, NULL, 0) << 16;
1829  fclose(f);
1830  }
1831  else {
1832  FileName = cString::sprintf("/sys/class/dvb/%s/device/idVendor", e->d_name);
1833  if ((f = fopen(FileName, "r")) != NULL) {
1834  if (char *s = ReadLine.Read(f))
1835  SubsystemId = strtoul(s, NULL, 16) << 16;
1836  fclose(f);
1837  }
1838  }
1839  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_device", e->d_name);
1840  if ((f = fopen(FileName, "r")) != NULL) {
1841  if (char *s = ReadLine.Read(f))
1842  SubsystemId |= strtoul(s, NULL, 0);
1843  fclose(f);
1844  }
1845  else {
1846  FileName = cString::sprintf("/sys/class/dvb/%s/device/idProduct", e->d_name);
1847  if ((f = fopen(FileName, "r")) != NULL) {
1848  if (char *s = ReadLine.Read(f))
1849  SubsystemId |= strtoul(s, NULL, 16);
1850  fclose(f);
1851  }
1852  }
1853  break;
1854  }
1855  }
1856  }
1857  }
1858  }
1859  }
1860  }
1861  return SubsystemId;
1862 }
static unsigned int FrequencyToHz(unsigned int f)
Definition: dvbdevice.c:694
#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:1800
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:1119
virtual ~cDvbTuner()
Definition: dvbdevice.c:386
cDvbTransponderParameters(const char *Parameters=NULL)
Definition: dvbdevice.c:202
unsigned char uchar
Definition: tools.h:30
virtual ~cDvbDevice()
Definition: dvbdevice.c:1180
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:1600
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:1234
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:119
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:1204
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:767
#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:1714
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:1250
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:1760
#define LOG_ERROR
Definition: tools.h:38
cDvbTuner * dvbTuner
Definition: dvbdevice.h:238
#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:1694
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:1472
cTSBuffer * tsBuffer
< Controls how the DVB device handles Transfer Mode when replaying Dolby Digital audio.
Definition: dvbdevice.h:288
#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:544
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:1704
virtual cOsdItem * GetOsdItem(void)
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
Definition: dvbdevice.c:1086
#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:710
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:1795
static uint32_t GetSubsystemId(int Adapter, int Frontend)
Definition: dvbdevice.c:1805
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:1724
bool SetIdle(bool Idle)
Definition: dvbdevice.c:1019
#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:489
#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:571
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:468
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:1308
cPositioner * GetPositioner(void)
Definition: dvbdevice.c:701
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:1141
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:233
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:1392
#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:1221
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:1522
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:1074
void Broadcast(void)
Definition: thread.c:135
cDvbDevice * bondedDevice
Definition: dvbdevice.h:190
cDvbSourceParam(char Source, const char *Description)
Definition: dvbdevice.c:1067
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:1793
static cMutex bondMutex
Definition: dvbdevice.h:189
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition: dvbdevice.c:1245
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:1750
#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:1586
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:419
Definition: ci.h:130
#define ATSC_LOCK_TIMEOUT
Definition: dvbdevice.c:33
bool OpenFrontend(void) const
Definition: dvbdevice.c:1029
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:532
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:1741
int LnbFrequHi
Definition: config.h:273
#define DEV_DVB_DVR
Definition: dvbdevice.h:77
int GetSignalQuality(void) const
Definition: dvbdevice.c:600
bool IsIdle(void) const
Definition: dvbdevice.c:356
int diseqcOffset
Definition: dvbdevice.c:314
bool Bond(cDvbTuner *Tuner)
Definition: dvbdevice.c:403
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition: dvbdevice.c:1780
static void UnBondDevices(void)
Unbonds all devices.
Definition: dvbdevice.c:1437
#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:1709
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition: dvbdevice.c:1517
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:1731
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: dvbdevice.c:1689
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:120
const cDiseqc * lastDiseqc
Definition: dvbdevice.c:313
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
Definition: dvbdevice.c:773
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:361
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:1591
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:276
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:1041
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:1448
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:1610
#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:1634
bool SetFrontend(void)
Definition: dvbdevice.c:789
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:452
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:1497
void SetChannel(const cChannel *Channel)
Definition: dvbdevice.c:499
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:598
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:556
#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:939
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:1489
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:1562
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:1699
bool IsAtsc(void) const
Definition: channels.h:185
cString GetBondingParams(const cChannel *Channel=NULL) const
Definition: dvbdevice.c:435
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:1719
cDvbTransponderParameters dtp
Definition: dvbdevice.c:1059
static cString DvbName(const char *Name, int Adapter, int Frontend)
Definition: dvbdevice.c:1190
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:1195
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:1081
const tDvbParameterMap TransmissionValues[]
Definition: dvbdevice.c:111
static void SetTransferModeForDolbyDigital(int Mode)
Definition: dvbdevice.c:1736
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:1684
int DiSEqC
Definition: config.h:274