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