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:
303  enum eTunerStatus { tsIdle, tsSet, tsPositioning, tsTuned, tsLocked };
306  mutable int fd_frontend;
307  int adapter, 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;
368  subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, 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;
378  tunerStatus = tsIdle;
379  bondedTuner = NULL;
380  bondedMaster = false;
381  isIdle = false;
382  SetDescription("frontend %d/%d tuner", adapter, frontend);
383  Start();
384 }
385 
387 {
388  tunerStatus = tsIdle;
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) {
407  ResetToneAndVoltage();
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);
525  tunerStatus = tsIdle;
526  ResetToneAndVoltage();
527  }
528  if (bondedTuner && device->IsPrimaryDevice())
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) {
704  positioner = cPositioner::GetPositioner();
705  positioner->SetFrontend(fd_frontend);
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  }
760  positioner = Positioner;
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 
813  cDvbTransponderParameters dtp(channel.Parameters());
814 
815  // Determine the required frontend type:
816  frontendType = GetRequiredDeliverySystem(&channel, &dtp);
817  if (frontendType == SYS_UNDEFINED)
818  return false;
819 
820  SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
821  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
822  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, (unsigned int *)&frequency);
829  if (frequency == 0)
830  return false;
831  }
832  else
833  ResetToneAndVoltage();
834  lastDiseqc = diseqc;
835  lastSource = channel.Source();
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 < 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 
881  tuneTimeout = DVBS_TUNE_TIMEOUT;
882  lockTimeout = DVBS_LOCK_TIMEOUT;
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 
892  tuneTimeout = DVBC_TUNE_TIMEOUT;
893  lockTimeout = DVBC_LOCK_TIMEOUT;
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 
915  tuneTimeout = DVBT_TUNE_TIMEOUT;
916  lockTimeout = DVBT_LOCK_TIMEOUT;
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 
924  tuneTimeout = ATSC_TUNE_TIMEOUT;
925  lockTimeout = ATSC_LOCK_TIMEOUT;
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:
956  tunerStatus = SetFrontend() ? tsPositioning : tsIdle;
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  }
968  tunerStatus = tsTuned;
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  }
1000  tunerStatus = tsLocked;
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);
1034  fd_frontend = cDvbDevice::DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
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 
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 
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 
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
friend class cDvbSourceParam
Definition: dvbdevice.h:108
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&#39;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
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
#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
A steerable satellite dish generally points to the south on the northern hemisphere, and to the north on the southern hemisphere (unless you&#39;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&#39;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
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
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
int deliverySystems[MAXDELIVERYSYSTEMS]
Definition: dvbdevice.h:185
bool lnbPowerTurnedOn
Definition: dvbdevice.c:318
Definition: thread.h:63
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 &#39;channels.conf&#39;.
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
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&#39;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
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
#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&#39;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