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