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