vdr  2.4.0
dvbdevice.c
Go to the documentation of this file.
1 /*
2  * dvbdevice.c: The DVB device tuner interface
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: dvbdevice.c 4.16 2018/02/15 15:37:01 kls Exp $
8  */
9 
10 #include "dvbdevice.h"
11 #include <ctype.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <linux/dvb/dmx.h>
15 #include <linux/dvb/frontend.h>
16 #include <sys/ioctl.h>
17 #include <sys/mman.h>
18 #include "channels.h"
19 #include "diseqc.h"
20 #include "dvbci.h"
21 #include "menuitems.h"
22 #include "sourceparams.h"
23 
24 static int DvbApiVersion = 0x0000; // the version of the DVB driver actually in use (will be determined by the first device created)
25 
26 #define DVBS_TUNE_TIMEOUT 9000 //ms
27 #define DVBS_LOCK_TIMEOUT 2000 //ms
28 #define DVBC_TUNE_TIMEOUT 9000 //ms
29 #define DVBC_LOCK_TIMEOUT 2000 //ms
30 #define DVBT_TUNE_TIMEOUT 9000 //ms
31 #define DVBT_LOCK_TIMEOUT 2000 //ms
32 #define ATSC_TUNE_TIMEOUT 9000 //ms
33 #define ATSC_LOCK_TIMEOUT 2000 //ms
34 
35 #define SCR_RANDOM_TIMEOUT 500 // ms (add random value up to this when tuning SCR device to avoid lockups)
36 
37 // --- DVB Parameter Maps ----------------------------------------------------
38 
40  { 0, PILOT_OFF, trNOOP("off") },
41  { 1, PILOT_ON, trNOOP("on") },
42  { 999, PILOT_AUTO, trNOOP("auto") },
43  { -1, 0, NULL }
44  };
45 
47  { 0, INVERSION_OFF, trNOOP("off") },
48  { 1, INVERSION_ON, trNOOP("on") },
49  { 999, INVERSION_AUTO, trNOOP("auto") },
50  { -1, 0, NULL }
51  };
52 
54  { 5, 5000000, "5 MHz" },
55  { 6, 6000000, "6 MHz" },
56  { 7, 7000000, "7 MHz" },
57  { 8, 8000000, "8 MHz" },
58  { 10, 10000000, "10 MHz" },
59  { 1712, 1712000, "1.712 MHz" },
60  { -1, 0, NULL }
61  };
62 
64  { 0, FEC_NONE, trNOOP("none") },
65  { 12, FEC_1_2, "1/2" },
66  { 23, FEC_2_3, "2/3" },
67  { 34, FEC_3_4, "3/4" },
68  { 35, FEC_3_5, "3/5" },
69  { 45, FEC_4_5, "4/5" },
70  { 56, FEC_5_6, "5/6" },
71  { 67, FEC_6_7, "6/7" },
72  { 78, FEC_7_8, "7/8" },
73  { 89, FEC_8_9, "8/9" },
74  { 910, FEC_9_10, "9/10" },
75  { 999, FEC_AUTO, trNOOP("auto") },
76  { -1, 0, NULL }
77  };
78 
80  { 16, QAM_16, "QAM16" },
81  { 32, QAM_32, "QAM32" },
82  { 64, QAM_64, "QAM64" },
83  { 128, QAM_128, "QAM128" },
84  { 256, QAM_256, "QAM256" },
85  { 2, QPSK, "QPSK" },
86  { 5, PSK_8, "8PSK" },
87  { 6, APSK_16, "16APSK" },
88  { 7, APSK_32, "32APSK" },
89  { 10, VSB_8, "VSB8" },
90  { 11, VSB_16, "VSB16" },
91  { 12, DQPSK, "DQPSK" },
92  { 999, QAM_AUTO, trNOOP("auto") },
93  { -1, 0, NULL }
94  };
95 
96 #define DVB_SYSTEM_1 0 // see also nit.c
97 #define DVB_SYSTEM_2 1
98 
100  { 0, DVB_SYSTEM_1, "DVB-S" },
101  { 1, DVB_SYSTEM_2, "DVB-S2" },
102  { -1, 0, NULL }
103  };
104 
106  { 0, DVB_SYSTEM_1, "DVB-T" },
107  { 1, DVB_SYSTEM_2, "DVB-T2" },
108  { -1, 0, NULL }
109  };
110 
112  { 1, TRANSMISSION_MODE_1K, "1K" },
113  { 2, TRANSMISSION_MODE_2K, "2K" },
114  { 4, TRANSMISSION_MODE_4K, "4K" },
115  { 8, TRANSMISSION_MODE_8K, "8K" },
116  { 16, TRANSMISSION_MODE_16K, "16K" },
117  { 32, TRANSMISSION_MODE_32K, "32K" },
118  { 999, TRANSMISSION_MODE_AUTO, trNOOP("auto") },
119  { -1, 0, NULL }
120  };
121 
123  { 4, GUARD_INTERVAL_1_4, "1/4" },
124  { 8, GUARD_INTERVAL_1_8, "1/8" },
125  { 16, GUARD_INTERVAL_1_16, "1/16" },
126  { 32, GUARD_INTERVAL_1_32, "1/32" },
127  { 128, GUARD_INTERVAL_1_128, "1/128" },
128  { 19128, GUARD_INTERVAL_19_128, "19/128" },
129  { 19256, GUARD_INTERVAL_19_256, "19/256" },
130  { 999, GUARD_INTERVAL_AUTO, trNOOP("auto") },
131  { -1, 0, NULL }
132  };
133 
135  { 0, HIERARCHY_NONE, trNOOP("none") },
136  { 1, HIERARCHY_1, "1" },
137  { 2, HIERARCHY_2, "2" },
138  { 4, HIERARCHY_4, "4" },
139  { 999, HIERARCHY_AUTO, trNOOP("auto") },
140  { -1, 0, NULL }
141  };
142 
144  { 0, ROLLOFF_AUTO, trNOOP("auto") },
145  { 20, ROLLOFF_20, "0.20" },
146  { 25, ROLLOFF_25, "0.25" },
147  { 35, ROLLOFF_35, "0.35" },
148  { -1, 0, NULL }
149  };
150 
151 int UserIndex(int Value, const tDvbParameterMap *Map)
152 {
153  const tDvbParameterMap *map = Map;
154  while (map && map->userValue != -1) {
155  if (map->userValue == Value)
156  return map - Map;
157  map++;
158  }
159  return -1;
160 }
161 
162 int DriverIndex(int Value, const tDvbParameterMap *Map)
163 {
164  const tDvbParameterMap *map = Map;
165  while (map && map->userValue != -1) {
166  if (map->driverValue == Value)
167  return map - Map;
168  map++;
169  }
170  return -1;
171 }
172 
173 int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
174 {
175  int n = DriverIndex(Value, Map);
176  if (n >= 0) {
177  if (String)
178  *String = tr(Map[n].userString);
179  return Map[n].userValue;
180  }
181  return -1;
182 }
183 
184 const char *MapToUserString(int Value, const tDvbParameterMap *Map)
185 {
186  int n = DriverIndex(Value, Map);
187  if (n >= 0)
188  return Map[n].userString;
189  return "???";
190 }
191 
192 int MapToDriver(int Value, const tDvbParameterMap *Map)
193 {
194  int n = UserIndex(Value, Map);
195  if (n >= 0)
196  return Map[n].driverValue;
197  return -1;
198 }
199 
200 // --- cDvbTransponderParameters ---------------------------------------------
201 
203 {
204  Parse(Parameters);
205 }
206 
207 int cDvbTransponderParameters::PrintParameter(char *p, char Name, int Value) const
208 {
209  return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0;
210 }
211 
213 {
214 #define ST(s) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*')))
215  char buffer[64];
216  char *q = buffer;
217  *q = 0;
218  ST(" S *") q += sprintf(q, "%c", polarization);
219  ST(" T*") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues));
220  ST(" CST*") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues));
221  ST(" T*") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues));
222  ST(" T*") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues));
223  ST("ACST*") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues));
224  ST("ACST*") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues));
225  ST(" S 2") q += PrintParameter(q, 'N', MapToUser(pilot, PilotValues));
226  ST(" S 2") q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues));
227  ST(" ST2") q += PrintParameter(q, 'P', streamId);
228  ST(" T2") q += PrintParameter(q, 'Q', t2systemId);
229  ST(" ST*") q += PrintParameter(q, 'S', MapToUser(system, SystemValuesSat)); // we only need the numerical value, so Sat or Terr doesn't matter
231  ST(" T2") q += PrintParameter(q, 'X', sisoMiso);
232  ST(" T*") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues));
233  return buffer;
234 }
235 
236 const char *cDvbTransponderParameters::ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map)
237 {
238  if (*++s) {
239  char *p = NULL;
240  errno = 0;
241  int n = strtol(s, &p, 10);
242  if (!errno && p != s) {
243  Value = Map ? MapToDriver(n, Map) : n;
244  if (Value >= 0)
245  return p;
246  }
247  }
248  esyslog("ERROR: invalid value for parameter '%c'", *(s - 1));
249  return NULL;
250 }
251 
253 {
254  polarization = 0;
255  inversion = INVERSION_AUTO;
256  bandwidth = 8000000;
257  coderateH = FEC_AUTO;
258  coderateL = FEC_AUTO;
259  modulation = QPSK;
261  transmission = TRANSMISSION_MODE_AUTO;
262  guard = GUARD_INTERVAL_AUTO;
263  hierarchy = HIERARCHY_AUTO;
264  rollOff = ROLLOFF_AUTO;
265  streamId = 0;
266  t2systemId = 0;
267  sisoMiso = 0;
268  pilot = PILOT_AUTO;
269  while (s && *s) {
270  switch (toupper(*s)) {
271  case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break;
272  case 'C': s = ParseParameter(s, coderateH, CoderateValues); break;
273  case 'D': s = ParseParameter(s, coderateL, CoderateValues); break;
274  case 'G': s = ParseParameter(s, guard, GuardValues); break;
275  case 'H': polarization = 'H'; s++; break;
276  case 'I': s = ParseParameter(s, inversion, InversionValues); break;
277  case 'L': polarization = 'L'; s++; break;
278  case 'M': s = ParseParameter(s, modulation, ModulationValues); break;
279  case 'N': s = ParseParameter(s, pilot, PilotValues); break;
280  case 'O': s = ParseParameter(s, rollOff, RollOffValues); break;
281  case 'P': s = ParseParameter(s, streamId); break;
282  case 'Q': s = ParseParameter(s, t2systemId); break;
283  case 'R': polarization = 'R'; s++; break;
284  case 'S': s = ParseParameter(s, system, SystemValuesSat); break; // we only need the numerical value, so Sat or Terr doesn't matter
285  case 'T': s = ParseParameter(s, transmission, TransmissionValues); break;
286  case 'V': polarization = 'V'; s++; break;
287  case 'X': s = ParseParameter(s, sisoMiso); break;
288  case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break;
289  default: esyslog("ERROR: unknown parameter key '%c'", *s);
290  return false;
291  }
292  }
293  return true;
294 }
295 
296 // --- cDvbTuner -------------------------------------------------------------
297 
298 #define TUNER_POLL_TIMEOUT 10 // ms
299 
300 class cDvbTuner : public cThread {
301 private:
308  uint32_t subsystemId;
312  mutable uint32_t lastUncValue;
313  mutable uint32_t lastUncDelta;
314  mutable time_t lastUncChange;
320  const cScr *scr;
328  bool SetFrontendType(const cChannel *Channel);
329  cString GetBondingParams(const cChannel *Channel = NULL) const;
330  cDvbTuner *GetBondedMaster(void);
331  bool IsBondedMaster(void) const { return !bondedTuner || bondedMaster; }
332  void ClearEventQueue(void) const;
333  bool GetFrontendStatus(fe_status_t &Status) const;
334  cPositioner *GetPositioner(void);
335  void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency);
336  void ResetToneAndVoltage(void);
337  bool SetFrontend(void);
338  virtual void Action(void);
339 public:
340  cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
341  virtual ~cDvbTuner();
342  int FrontendType(void) const { return frontendType; }
343  bool Bond(cDvbTuner *Tuner);
344  void UnBond(void);
345  bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
346  const cChannel *GetTransponder(void) const { return &channel; }
347  uint32_t SubsystemId(void) const { return subsystemId; }
348  bool IsTunedTo(const cChannel *Channel) const;
349  void SetChannel(const cChannel *Channel);
350  bool Locked(int TimeoutMs = 0);
351  const cPositioner *Positioner(void) const { return positioner; }
352  bool GetSignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
353  int GetSignalStrength(void) const;
354  int GetSignalQuality(void) const;
355  };
356 
358 
359 cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
360 {
361  frontendType = SYS_UNDEFINED;
362  device = Device;
363  fd_frontend = Fd_Frontend;
364  adapter = Adapter;
365  frontend = Frontend;
367  tuneTimeout = 0;
368  lockTimeout = 0;
369  lastTimeoutReport = 0;
370  lastUncValue = 0;
371  lastUncDelta = 0;
372  lastUncChange = 0;
373  lastDiseqc = NULL;
374  diseqcOffset = 0;
375  lastSource = 0;
376  positioner = NULL;
377  scr = NULL;
378  lnbPowerTurnedOn = false;
380  bondedTuner = NULL;
381  bondedMaster = false;
382  SetDescription("frontend %d/%d tuner", adapter, frontend);
383  Start();
384 }
385 
387 {
389  newSet.Broadcast();
390  locked.Broadcast();
391  Cancel(3);
392  UnBond();
393  /* looks like this irritates the SCR switch, so let's leave it out for now
394  if (lastDiseqc && lastDiseqc->IsScr()) {
395  unsigned int Frequency = 0;
396  ExecuteDiseqc(lastDiseqc, &Frequency);
397  }
398  */
399 }
400 
402 {
403  cMutexLock MutexLock(&bondMutex);
404  if (!bondedTuner) {
406  bondedMaster = false; // makes sure we don't disturb an existing master
407  bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
408  Tuner->bondedTuner = this;
409  dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
410  return true;
411  }
412  else
413  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);
414  return false;
415 }
416 
418 {
419  cMutexLock MutexLock(&bondMutex);
420  if (cDvbTuner *t = bondedTuner) {
421  dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend);
422  while (t->bondedTuner != this)
423  t = t->bondedTuner;
424  if (t == bondedTuner)
425  t->bondedTuner = NULL;
426  else
427  t->bondedTuner = bondedTuner;
428  bondedMaster = false; // another one will automatically become master whenever necessary
429  bondedTuner = NULL;
430  }
431 }
432 
434 {
435  if (!Channel)
436  Channel = &channel;
437  cDvbTransponderParameters dtp(Channel->Parameters());
438  if (Setup.DiSEqC) {
439  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL))
440  return diseqc->Commands();
441  }
442  else {
443  bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
444  bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
445  return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
446  }
447  return "";
448 }
449 
450 bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
451 {
452  cMutexLock MutexLock(&bondMutex);
453  if (cDvbTuner *t = bondedTuner) {
454  cString BondingParams = GetBondingParams(Channel);
455  do {
456  if (t->device->Priority() > IDLEPRIORITY || ConsiderOccupied && t->device->Occupied()) {
457  if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
458  return false;
459  }
460  t = t->bondedTuner;
461  } while (t != bondedTuner);
462  }
463  return true;
464 }
465 
467 {
468  if (!bondedTuner)
469  return this; // an unbonded tuner is always "master"
470  cMutexLock MutexLock(&bondMutex);
471  if (bondedMaster)
472  return this;
473  // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
474  if (cDvbTuner *t = bondedTuner) {
475  while (t != this) {
476  if (t->bondedMaster)
477  return t;
478  t = t->bondedTuner;
479  }
480  }
481  // None of the other bonded tuners is master, so make this one the master:
482  bondedMaster = true;
483  dsyslog("tuner %d/%d is now bonded master", adapter, frontend);
484  return this;
485 }
486 
487 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
488 {
489  if (tunerStatus == tsIdle)
490  return false; // not tuned to
491  if (channel.Source() != Channel->Source() || channel.Transponder() != Channel->Transponder())
492  return false; // sufficient mismatch
493  // Polarization is already checked as part of the Transponder.
494  return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
495 }
496 
497 void cDvbTuner::SetChannel(const cChannel *Channel)
498 {
499  if (Channel) {
500  if (bondedTuner) {
501  cMutexLock MutexLock(&bondMutex);
502  cDvbTuner *BondedMaster = GetBondedMaster();
503  if (BondedMaster == this) {
504  if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
505  // switching to a completely different band, so set all others to idle:
506  for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
507  t->SetChannel(NULL);
508  }
509  }
510  else if (strcmp(GetBondingParams(Channel), BondedMaster->GetBondingParams()) != 0)
511  BondedMaster->SetChannel(Channel);
512  }
513  cMutexLock MutexLock(&mutex);
514  if (!IsTunedTo(Channel))
515  tunerStatus = tsSet;
516  diseqcOffset = 0;
517  channel = *Channel;
518  lastTimeoutReport = 0;
519  newSet.Broadcast();
520  }
521  else {
522  cMutexLock MutexLock(&mutex);
525  }
527  cDevice::PrimaryDevice()->DelLivePids(); // 'device' is const, so we must do it this way
528 }
529 
530 bool cDvbTuner::Locked(int TimeoutMs)
531 {
532  bool isLocked = (tunerStatus >= tsLocked);
533  if (isLocked || !TimeoutMs)
534  return isLocked;
535 
536  cMutexLock MutexLock(&mutex);
537  if (TimeoutMs && tunerStatus < tsLocked)
538  locked.TimedWait(mutex, TimeoutMs);
539  return tunerStatus >= tsLocked;
540 }
541 
543 {
544  cPoller Poller(fd_frontend);
545  if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
546  dvb_frontend_event Event;
547  while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
548  ; // just to clear the event queue - we'll read the actual status below
549  }
550 }
551 
552 bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
553 {
554  ClearEventQueue();
555  while (1) {
556  if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
557  return true;
558  if (errno != EINTR)
559  break;
560  }
561  return false;
562 }
563 
564 //#define DEBUG_SIGNALSTATS
565 //#define DEBUG_SIGNALSTRENGTH
566 //#define DEBUG_SIGNALQUALITY
567 
568 #define MAXFRONTENDCMDS 16
569 #define SETCMD(c, d) { Props[CmdSeq.num].cmd = (c);\
570  Props[CmdSeq.num].u.data = (d);\
571  if (CmdSeq.num++ > MAXFRONTENDCMDS) {\
572  esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\
573  return false;\
574  }\
575  }
576 
577 bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
578 {
579  ClearEventQueue();
580  fe_status_t FeStatus;
581  dtv_property Props[MAXFRONTENDCMDS];
582  dtv_properties CmdSeq;
583  memset(&Props, 0, sizeof(Props));
584  memset(&CmdSeq, 0, sizeof(CmdSeq));
585  CmdSeq.props = Props;
586  Valid = DTV_STAT_VALID_NONE;
587  if (ioctl(fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
588  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
589  return false;
590  }
591  if (Status) {
592  *Status = DTV_STAT_HAS_NONE;
593  if (FeStatus & FE_HAS_SIGNAL) *Status |= DTV_STAT_HAS_SIGNAL;
594  if (FeStatus & FE_HAS_CARRIER) *Status |= DTV_STAT_HAS_CARRIER;
595  if (FeStatus & FE_HAS_VITERBI) *Status |= DTV_STAT_HAS_VITERBI;
596  if (FeStatus & FE_HAS_SYNC) *Status |= DTV_STAT_HAS_SYNC;
597  if (FeStatus & FE_HAS_LOCK) *Status |= DTV_STAT_HAS_LOCK;
598  Valid |= DTV_STAT_VALID_STATUS;
599  }
600  if (Strength) SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
601  if (Cnr) SETCMD(DTV_STAT_CNR, 0);
602  if (BerPre) { SETCMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0);
603  SETCMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0); }
604  if (BerPost) { SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
605  SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0); }
606  if (Per) { SETCMD(DTV_STAT_ERROR_BLOCK_COUNT, 0);
607  SETCMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0); }
608  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
609  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
610  return false;
611  }
612  int i = 0;
613  if (Strength) {
614  if (Props[i].u.st.len > 0) {
615  switch (Props[i].u.st.stat[0].scale) {
616  case FE_SCALE_DECIBEL: *Strength = double(Props[i].u.st.stat[0].svalue) / 1000;
617  Valid |= DTV_STAT_VALID_STRENGTH;
618  break;
619  default: ;
620  }
621  }
622  i++;
623  }
624  if (Cnr) {
625  if (Props[i].u.st.len > 0) {
626  switch (Props[i].u.st.stat[0].scale) {
627  case FE_SCALE_DECIBEL: *Cnr = double(Props[i].u.st.stat[0].svalue) / 1000;
628  Valid |= DTV_STAT_VALID_CNR;
629  break;
630  default: ;
631  }
632  }
633  i++;
634  }
635  if (BerPre) {
636  if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
637  if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
638  uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error bit count
639  uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total bit count
640  if (tbc > 0) {
641  *BerPre = double(ebc) / tbc;
642  Valid |= DTV_STAT_VALID_BERPRE;
643  }
644  }
645  }
646  i += 2;
647  }
648  if (BerPost) {
649  if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
650  if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
651  uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error bit count
652  uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total bit count
653  if (tbc > 0) {
654  *BerPost = double(ebc) / tbc;
655  Valid |= DTV_STAT_VALID_BERPOST;
656  }
657  }
658  }
659  i += 2;
660  }
661  if (Per) {
662  if (Props[i].u.st.len > 0 && Props[i + 1].u.st.len > 0) {
663  if (Props[i].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[i + 1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
664  uint64_t ebc = Props[i].u.st.stat[0].uvalue; // error block count
665  uint64_t tbc = Props[i + 1].u.st.stat[0].uvalue; // total block count
666  if (tbc > 0) {
667  *Per = double(ebc) / tbc;
668  Valid |= DTV_STAT_VALID_PER;
669  }
670  }
671  }
672  i += 2;
673  }
674 #ifdef DEBUG_SIGNALSTATS
675  fprintf(stderr, "FE %d/%d: API5 %04X", adapter, frontend, Valid);
676  if ((Valid & DTV_STAT_VALID_STATUS) != 0) fprintf(stderr, " STAT=%04X", *Status);
677  if ((Valid & DTV_STAT_VALID_STRENGTH) != 0) fprintf(stderr, " STR=%1.1fdBm", *Strength);
678  if ((Valid & DTV_STAT_VALID_CNR) != 0) fprintf(stderr, " CNR=%1.1fdB", *Cnr);
679  if ((Valid & DTV_STAT_VALID_BERPRE) != 0) fprintf(stderr, " BERPRE=%1.1e", *BerPre);
680  if ((Valid & DTV_STAT_VALID_BERPOST) != 0) fprintf(stderr, " BERPOST=%1.1e", *BerPost);
681  if ((Valid & DTV_STAT_VALID_PER) != 0) fprintf(stderr, " PER=%1.1e", *Per);
682  fprintf(stderr, "\n");
683 #endif
684  return Valid != DTV_STAT_VALID_NONE;
685 }
686 
687 int dB1000toPercent(int dB1000, int Low, int High)
688 {
689  // Convert the given value, which is in 1/1000 dBm, to a percentage in the
690  // range 0..100. Anything below Low is considered 0%, and anything above
691  // High counts as 100%.
692  if (dB1000 < Low)
693  return 0;
694  if (dB1000 > High)
695  return 100;
696  // return 100 - 100 * (High - dB1000) / (High - Low); // linear conversion
697  // return 100 - 100 * sqr(dB1000 - High) / sqr(Low - High); // quadratic conversion, see https://www.adriangranados.com/blog/dbm-to-percent-conversion
698  double v = 10.0 * (dB1000 - High) / (Low - High); // avoids the sqr() function
699  return 100 - v * v;
700 }
701 
702 #define REF_S1(q1) (mod == QPSK) ? q1 : 0
703 #define REF_S2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == PSK_8) ? q2 : (mod == APSK_16) ? q3 : (mod == APSK_32) ? q4 : 0
704 #define REF_T1(q1, q2, q3) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : 0
705 #define REF_T2(q1, q2, q3, q4) (mod == QPSK) ? q1 : (mod == QAM_16) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_256) ? q4 : 0
706 #define REF_C1(q1, q2, q3, q4, q5) (mod == QAM_16) ? q1 : (mod == QAM_32) ? q2 : (mod == QAM_64) ? q3 : (mod == QAM_128) ? q4 : (mod == QAM_256) ? q5: 0
707 
708 int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
709 {
710  // Strength in 0.001dBm (dBm x 1000)
711  cDvbTransponderParameters dtp(Channel->Parameters());
712  int ssi = 0; // 0-100
713  int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
714  int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
715  int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
716  if (Channel->IsTerr()) {
717  int pref = 0;
718  // NorDig Unified Ver. 2.6 - 3.4.4.6 Page 43 ff.
719  // reference values : pref-15dBm = 0%, pref+35dBm = 100%
720  if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
721  fec = cod; // adjustment for DVB-T
722  if (mod == QAM_AUTO) mod = QPSK;
723  switch (fec) { // dBm: Q4 Q16 Q64
724  case FEC_1_2: pref = REF_T1(-93, -87, -82); break;
725  default:
726  case FEC_2_3: pref = REF_T1(-91, -85, -80); break;
727  case FEC_3_4: pref = REF_T1(-90, -84, -78); break;
728  case FEC_5_6: pref = REF_T1(-89, -83, -77); break;
729  case FEC_7_8: pref = REF_T1(-88, -82, -76); break;
730  }
731  }
732  else { // DVB-T2
733  if (mod == QAM_AUTO) mod = QAM_64;
734  switch (fec) { // dBm: Q4 Q16 Q64 Q256
735  case FEC_1_2: pref = REF_T2(-96, -91, -86, -82); break;
736  default:
737  case FEC_3_5: pref = REF_T2(-95, -89, -85, -80); break;
738  case FEC_2_3: pref = REF_T2(-94, -88, -83, -78); break;
739  case FEC_3_4: pref = REF_T2(-93, -87, -82, -76); break;
740  case FEC_4_5: pref = REF_T2(-92, -86, -81, -75); break;
741  case FEC_5_6: pref = REF_T2(-92, -86, -80, -74); break;
742  }
743  }
744  if (pref) {
745  int prel = (Strength / 1000) - pref;
746  ssi = (prel < -15) ? 0 :
747  (prel < 0) ? (prel + 15) * 2 / 3 : // 0% - 10%
748  (prel < 20) ? prel * 4 + 10 : // 10% - 90%
749  (prel < 35) ? (prel - 20) * 2 / 3 + 90 : // 90% - 100%
750  100;
751 #ifdef DEBUG_SIGNALSTRENGTH
752  fprintf(stderr, "SSI-T: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(sys:%d, mod:%d, fec:%d)\n", Strength, pref, prel, ssi, dtp.System(), mod, fec);
753 #endif
754  }
755  }
756  else if (Channel->IsCable()) { // ! COMPLETELY UNTESTED !
757  // Formula: pref(dB) = -174.0 + NoiseFigure + SymRef + CnRef
758  // NoiseFigure = 6.5 dB; -> Tuner specific - range: 3.5 .. 9.0 dB
759  // SymRef = 10*log(6900000) = 68.5 dB; -> for Symbolrate of 6900 kSym/sec (TV: 6900, 6750 or 6111 kSym/sec)
760  // ==> pref(dB) = -174.0 + 6.5 + 68.5 + CnRef[modulation]{20,23,26,29,32}; (+/- 3 dB tuner specific)
761  if (mod == QAM_AUTO) mod = QAM_256;
762  // Q16 Q32 Q64 Q128 Q256
763  int pref = REF_C1(-79, -76, -73, -70, -67);
764  if (pref) {
765  int prel = (Strength / 1000) - pref;
766  ssi = (prel < -15) ? 0 :
767  (prel < 0) ? (prel + 15) * 2 / 3 : // 0% - 10%
768  (prel < 20) ? prel * 4 + 10 : // 10% - 90%
769  (prel < 35) ? (prel - 20) * 2 / 3 + 90 : // 90% - 100%
770  100;
771 #ifdef DEBUG_SIGNALSTRENGTH
772  fprintf(stderr, "SSI-C: STR:%d, Pref:%d, Prel:%d, ssi:%d%%(mod:%d)\n", Strength, pref, prel, ssi, mod);
773 #endif
774  }
775  }
776  else if (Channel->IsSat())
777  ssi = dB1000toPercent(Strength, -95000, -20000); // defaults
778  return ssi;
779 }
780 
781 // Due to missing values or the different meanings of the reported error rate, ber_sqi is currently not taken into account
782 #define IGNORE_BER 1
783 #define BER_ERROR_FREE (1000*1000*1000) // 1/10^-9
784 
785 int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
786 {
787 #if IGNORE_BER
788  Ber = BER_ERROR_FREE; // assume/pretend to be biterror free
789 #endif
790  // Signal in 0.001dB (dB x 1000)
791  cDvbTransponderParameters dtp(Channel->Parameters());
792  int sqi = 0; // 0-100
793  int mod = (FeModulation >= 0) ? FeModulation : dtp.Modulation();
794  int cod = (FeCoderateH >= 0) ? FeCoderateH : dtp.CoderateH(); // DVB-T
795  int fec = (FeFec >= 0) ? FeFec : dtp.CoderateH();
796  if (Channel->IsTerr()) { // QEF: BER 10^-6
797  int cnref = 0;
798  // NorDig Unified Ver. 2.6 - 3.4.4.7 Page 45 ff.
799  // reference values for QEF (BER 10^-11 at MPEG2 demux input)
800  if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
801  fec = cod; // adjustment for DVB-T
802  if (mod == QAM_AUTO) mod = QPSK;
803  switch (fec) { // 0.1 dB Q4 Q16 Q64 (Hierarchy=None)
804  case FEC_1_2: cnref = REF_T1(51, 108, 165); break;
805  default:
806  case FEC_2_3: cnref = REF_T1(69, 131, 187); break;
807  case FEC_3_4: cnref = REF_T1(79, 146, 202); break;
808  case FEC_5_6: cnref = REF_T1(89, 156, 216); break;
809  case FEC_7_8: cnref = REF_T1(97, 160, 225); break;
810  }
811  }
812  else { // DVB-T2
813  if (mod == QAM_AUTO) mod = QAM_64;
814  switch (fec) { // 0.1 dB Q4 Q16 Q64 Q256
815  case FEC_1_2: cnref = REF_T2(35, 87, 130, 170); break;
816  default:
817  case FEC_3_5: cnref = REF_T2(47, 101, 148, 194); break;
818  case FEC_2_3: cnref = REF_T2(56, 114, 162, 208); break;
819  case FEC_3_4: cnref = REF_T2(66, 125, 177, 229); break;
820  case FEC_4_5: cnref = REF_T2(72, 133, 187, 243); break;
821  case FEC_5_6: cnref = REF_T2(77, 138, 194, 251); break;
822  }
823  }
824  if (cnref) {
825  int cnrel = (Signal/100) - cnref; // 0.1 dB
826  int ber_sqi = 100; // 100%
827  int cnr_sqi = 0; // 0%
828  if (dtp.System() == DVB_SYSTEM_1) { // DVB-T
829  ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
830  (Ber >= 10000000) ? 100 : // <= 10^-7
831  (int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
832  // scale: -7dB/+3dB to reference-value
833  cnr_sqi = (cnrel < -70) ? 0 :
834  (cnrel < +30) ? (100 + (cnrel - 30)) :
835  100;
836  sqi = (cnr_sqi * ber_sqi) / 100;
837  // alternative: stretched scale: cnref-7dB = 0%, 30dB = 100%
838  // sqi = dB1000toPercent(Signal, (100*cnref)-7000, 30000);
839  }
840  else { // DVB-T2
841  ber_sqi = (Ber < 10000) ? 0 : // > 10^-4
842  (Ber >= 10000000) ? 100 * 100 / 6 : // <= 10^-7 : 16.67% -> SQI 0% .. 100%
843  (100 * 100 / 15); // 6.67% -> SQI 0% .. 40% || 100%
844  // scale: -3dB/+3dB to reference-value
845  sqi = (cnrel < -30) ? 0 :
846  (cnrel <= +30) ? (cnrel + 30) * ber_sqi / 1000 : // (0 .. 6) * 16,67 || 6.67
847  100;
848  // alternative: stretched scale: cnref-3dB = 0%, 32dB = 100%
849  // sqi = dB1000toPercent(Signal, (100*cnref)-3000, 32000);
850  }
851 #ifdef DEBUG_SIGNALQUALITY
852  fprintf(stderr, "SQI-T: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
853 #endif
854  }
855  }
856  else if (Channel->IsCable()) { // ! COMPLETELY UNTESTED !
857  if (mod == QAM_AUTO) mod = QAM_256;
858  // 0.1 dB Q16 Q32 Q64 Q128 Q256
859  int cnref = REF_C1(200, 230, 260, 290, 320); // minimum for BER<10^-4
860  if (cnref) {
861  int cnrel = (Signal / 100) - cnref; // 0.1 dB
862  int ber_sqi = (Ber < 1000) ? 0 : // > 10^-3
863  (Ber >= 10000000) ? 100 : // <= 10^-7
864  (int)(20 * log10(Ber)) - 40; // 20*log10(1/BER)-40 -> 20% .. 100%
865  // scale: -7dB/+3dB to reference-value
866  int cnr_sqi = (cnrel < -70) ? 0 :
867  (cnrel < +30) ? (100 + (cnrel - 30)) :
868  100;
869  sqi = (cnr_sqi * ber_sqi) / 100;
870  // alternative: stretched scale: cnref-7dB = 0%, 40dB = 100%
871  // sqi = dB1000toPercent(Signal, (100*cnref)-7000, 40000);
872 #ifdef DEBUG_SIGNALQUALITY
873  dsyslog("SQI-C: SIG:%d, BER:%d, CNref:%d, CNrel:%d, bersqi:%d, sqi:%d%%(sys:%d, mod:%d, fec:%d)\n", Signal, Ber, cnref, cnrel, ber_sqi, sqi, dtp.System(), mod, fec);
874 #endif
875  }
876  }
877  else if (Channel->IsSat()) {
878  int cnref = 0;
879  if (dtp.System() == DVB_SYSTEM_1) { // DVB-S
880  if (mod == QAM_AUTO) mod = QPSK;
881  switch (fec) { // 0.1 dB: Q4 : 10^-7
882  case FEC_1_2: cnref = REF_S1(38); break;
883  default:
884  case FEC_2_3: cnref = REF_S1(56); break;
885  case FEC_3_4: cnref = REF_S1(67); break;
886  case FEC_5_6: cnref = REF_S1(77); break;
887  case FEC_7_8: cnref = REF_S1(84); break;
888  }
889  if (cnref) {
890  //cnrel = (Signal/100) - cnref; // 0.1 dB
891  // scale: cnref-4dB = 0%, 15dB = 100%
892  sqi = dB1000toPercent(Signal, (100*cnref)-4000, 15000);
893 #ifdef DEBUG_SIGNALQUALITY
894  dsyslog("SQI-S1: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
895 #endif
896  }
897  }
898  else { // DVB-S2
899  if (mod == QAM_AUTO) mod = QAM_64;
900  switch (fec) { // 0.1 dB Q4 Q8 16A* 32A*
901  //case FEC_1_4: cnref = REF_S2(-14, 65, 90, 126); break;
902  //case FEC_1_3: cnref = REF_S2( -2, 65, 90, 126); break;
903  case FEC_2_5: cnref = REF_S2( 7, 65, 90, 126); break;
904  case FEC_1_2: cnref = REF_S2( 20, 65, 90, 126); break;
905  case FEC_3_5: cnref = REF_S2( 32, 65, 90, 126); break;
906  default:
907  case FEC_2_3: cnref = REF_S2( 41, 76, 90, 126); break;
908  case FEC_3_4: cnref = REF_S2( 50, 66, 102, 126); break;
909  case FEC_4_5: cnref = REF_S2( 57, 89, 110, 136); break;
910  case FEC_5_6: cnref = REF_S2( 62, 104, 116, 143); break;
911  case FEC_8_9: cnref = REF_S2( 72, 117, 129, 157); break;
912  case FEC_9_10: cnref = REF_S2( 74, 120, 131, 161); break;
913  }
914  if (cnref) {
915  // cnrel = (Signal/100) - cnref; // 0.1 dB
916  // scale: cnref-4dB = 0%, 20dB = 100%
917  sqi = dB1000toPercent(Signal, (100*cnref)-4000, 20000);
918 #ifdef DEBUG_SIGNALQUALITY
919  dsyslog("SQI-S2: SIG:%d, BER:%d, CNref:%d, sqi:%d%%(mod:%d, fec:%d)\n", Signal, Ber, cnref, sqi, mod, fec);
920 #endif
921  }
922  }
923  }
924  return sqi;
925 }
926 
928 {
929  ClearEventQueue();
930  // Try DVB API 5:
931  for (int i = 0; i < 1; i++) { // just a trick to break out with 'continue' ;-)
932  dtv_property Props[MAXFRONTENDCMDS];
933  dtv_properties CmdSeq;
934  memset(&Props, 0, sizeof(Props));
935  memset(&CmdSeq, 0, sizeof(CmdSeq));
936  CmdSeq.props = Props;
937  SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
938  SETCMD(DTV_MODULATION, 0);
939  SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
940  SETCMD(DTV_INNER_FEC, 0);
941  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
942  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
943  return -1;
944  }
945  int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
946  int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
947  int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
948  int Signal = 0;
949  if (Props[0].u.st.len > 0) {
950  switch (Props[0].u.st.stat[0].scale) {
951  case FE_SCALE_DECIBEL: Signal = StrengthToSSI(&channel, Props[0].u.st.stat[0].svalue, FeMod, FeCod, FeFec);
952  break;
953  case FE_SCALE_RELATIVE: Signal = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
954  break;
955  default: ;
956  }
957 #ifdef DEBUG_SIGNALSTRENGTH
958  fprintf(stderr, "FE %d/%d: API5 %d %08X %.1f S = %d\n", adapter, frontend, Props[0].u.st.stat[0].scale, int(Props[0].u.st.stat[0].svalue), int(Props[0].u.st.stat[0].svalue) / 1000.0, Signal);
959 #endif
960  }
961  else
962  continue;
963  return Signal;
964  }
965  // Fall back to DVB API 3:
966  uint16_t Signal;
967  while (1) {
968  if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
969  break;
970  if (errno != EINTR)
971  return -1;
972  }
973  uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
974  // Use the subsystemId to identify individual devices in case they need
975  // special treatment to map their Signal value into the range 0...0xFFFF.
976  switch (subsystemId) {
977  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
978  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
979  MaxSignal = 670; break;
980  }
981  int s = int(Signal) * 100 / MaxSignal;
982  if (s > 100)
983  s = 100;
984 #ifdef DEBUG_SIGNALSTRENGTH
985  fprintf(stderr, "FE %d/%d: API3 %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
986 #endif
987  return s;
988 }
989 
990 #define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
991 
993 {
994  // Try DVB API 5:
995  for (int i = 0; i < 1; i++) { // just a trick to break out with 'continue' ;-)
996  dtv_property Props[MAXFRONTENDCMDS];
997  dtv_properties CmdSeq;
998  memset(&Props, 0, sizeof(Props));
999  memset(&CmdSeq, 0, sizeof(CmdSeq));
1000  CmdSeq.props = Props;
1001  SETCMD(DTV_STAT_CNR, 0);
1002  SETCMD(DTV_MODULATION, 0);
1003  SETCMD(DTV_CODE_RATE_HP, 0); // DVB-T only
1004  SETCMD(DTV_INNER_FEC, 0);
1005  SETCMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0);
1006  SETCMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0);
1007  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1008  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
1009  return -1;
1010  }
1011  int FeMod = (Props[1].u.st.len > 0) ? (int)Props[1].u.data : -1;
1012  int FeCod = (Props[2].u.st.len > 0) ? (int)Props[2].u.data : -1;
1013  int FeFec = (Props[3].u.st.len > 0) ? (int)Props[3].u.data : -1;
1014  int Ber = BER_ERROR_FREE; // 1/10^-9
1015  if (Props[4].u.st.len > 0 && Props[4].u.st.stat[0].scale == FE_SCALE_COUNTER && Props[5].u.st.len > 0 && Props[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
1016  uint64_t ebc = Props[4].u.st.stat[0].uvalue; // error bit count
1017  uint64_t tbc = Props[5].u.st.stat[0].uvalue; // total bit count
1018  if (ebc > 0) {
1019  uint64_t BerRev = tbc / ebc; // reversed, for integer arithmetic
1020  if (BerRev < BER_ERROR_FREE)
1021  Ber = (int)BerRev;
1022  }
1023  }
1024  int Cnr = 0;
1025  if (Props[0].u.st.len > 0) {
1026  switch (Props[0].u.st.stat[0].scale) {
1027  case FE_SCALE_DECIBEL: Cnr = SignalToSQI(&channel, Props[0].u.st.stat[0].svalue, Ber, FeMod, FeCod, FeFec);
1028  break;
1029  case FE_SCALE_RELATIVE: Cnr = 100 * Props[0].u.st.stat[0].uvalue / 0xFFFF;
1030  break;
1031  default: ;
1032  }
1033 #ifdef DEBUG_SIGNALQUALITY
1034  fprintf(stderr, "FE %d/%d: API5 %d %08X %.1f Q = %d\n", adapter, frontend, Props[0].u.st.stat[0].scale, int(Props[0].u.st.stat[0].svalue), int(Props[0].u.st.stat[0].svalue) / 1000.0, Cnr);
1035 #endif
1036  }
1037  else
1038  continue;
1039  return Cnr;
1040  }
1041  // Fall back to DVB API 3:
1042  fe_status_t Status;
1043  if (GetFrontendStatus(Status)) {
1044  // 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...
1045  if ((Status & FE_HAS_LOCK) == 0) {
1046  if ((Status & FE_HAS_SIGNAL) == 0)
1047  return 0;
1048  if ((Status & FE_HAS_CARRIER) == 0)
1049  return 1;
1050  if ((Status & FE_HAS_VITERBI) == 0)
1051  return 2;
1052  if ((Status & FE_HAS_SYNC) == 0)
1053  return 3;
1054  return 4;
1055  }
1056 #ifdef DEBUG_SIGNALQUALITY
1057  bool HasSnr = true;
1058 #endif
1059  uint16_t Snr;
1060  while (1) {
1061  if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
1062  break;
1063  if (errno != EINTR) {
1064  Snr = 0xFFFF;
1065 #ifdef DEBUG_SIGNALQUALITY
1066  HasSnr = false;
1067 #endif
1068  break;
1069  }
1070  }
1071 #ifdef DEBUG_SIGNALQUALITY
1072  bool HasBer = true;
1073 #endif
1074  uint32_t Ber;
1075  while (1) {
1076  if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
1077  break;
1078  if (errno != EINTR) {
1079  Ber = 0;
1080 #ifdef DEBUG_SIGNALQUALITY
1081  HasBer = false;
1082 #endif
1083  break;
1084  }
1085  }
1086 #ifdef DEBUG_SIGNALQUALITY
1087  bool HasUnc = true;
1088 #endif
1089  uint32_t Unc;
1090  while (1) {
1091  if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1) {
1092  if (Unc != lastUncValue) {
1093 #ifdef DEBUG_SIGNALQUALITY
1094  fprintf(stderr, "FE %d/%d: API3 UNC = %u %u %u\n", adapter, frontend, Unc, lastUncValue, lastUncDelta);
1095 #endif
1096  lastUncDelta = (Unc >= lastUncValue) ? Unc - lastUncValue : lastUncValue - Unc;
1097  lastUncValue = Unc;
1098  lastUncChange = time(NULL);
1099  }
1100  // The number of uncorrected blocks is a counter, which is normally
1101  // at a constant value and only increases if there are new uncorrected
1102  // blocks. So a change in the Unc value indicates reduced signal quality.
1103  // Whenever the Unc counter changes, we take the delta between the old
1104  // and new value into account for calculating the overall signal quality.
1105  // The impact of Unc is considered for 2 seconds, and after that it is
1106  // bisected with every passing second in order to phase it out. Otherwise
1107  // once one or more uncorrected blocks occur, the signal quality would
1108  // be considered low even if there haven't been any more uncorrected bocks
1109  // for quite a while.
1110  Unc = lastUncDelta;
1111  if (Unc > 0) {
1112  int t = time(NULL) - lastUncChange - 2;
1113  if (t > 0)
1114  Unc >>= min(t, int(sizeof(Unc) * 8 - 1));
1115  if (Unc == 0)
1116  lastUncDelta = 0;
1117 #ifdef DEBUG_SIGNALQUALITY
1118  fprintf(stderr, "FE %d/%d: API3 UNC = %u\n", adapter, frontend, Unc);
1119 #endif
1120  }
1121  break;
1122  }
1123  if (errno != EINTR) {
1124  Unc = 0;
1125 #ifdef DEBUG_SIGNALQUALITY
1126  HasUnc = false;
1127 #endif
1128  break;
1129  }
1130  }
1131  uint16_t MinSnr = 0x0000;
1132  uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
1133  // Use the subsystemId to identify individual devices in case they need
1134  // special treatment to map their Snr value into the range 0...0xFFFF.
1135  switch (subsystemId) {
1136  case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
1137  case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
1138  if (frontendType == SYS_DVBS2) {
1139  MinSnr = 10;
1140  MaxSnr = 70;
1141  }
1142  else
1143  MaxSnr = 200;
1144  break;
1145  case 0x20130245: // PCTV Systems PCTV 73ESE
1146  case 0x2013024F: // PCTV Systems nanoStick T2 290e
1147  MaxSnr = 255; break;
1148  }
1149  int a = int(constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
1150  int b = 100 - (Unc * 10 + (Ber / 256) * 5);
1151  if (b < 0)
1152  b = 0;
1153  int q = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
1154  if (q > 100)
1155  q = 100;
1156 #ifdef DEBUG_SIGNALQUALITY
1157  fprintf(stderr, "FE %d/%d: API3 %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
1158 #endif
1159  return q;
1160  }
1161  return -1;
1162 }
1163 
1164 static unsigned int FrequencyToHz(unsigned int f)
1165 {
1166  while (f && f < 1000000)
1167  f *= 1000;
1168  return f;
1169 }
1170 
1172 {
1173  if (!positioner) {
1176  }
1177  return positioner;
1178 }
1179 
1180 void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
1181 {
1182  if (!lnbPowerTurnedOn) {
1183  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
1184  lnbPowerTurnedOn = true;
1185  }
1186  static cMutex Mutex;
1187  if (Diseqc->IsScr())
1188  Mutex.Lock();
1189  struct dvb_diseqc_master_cmd cmd;
1190  const char *CurrentAction = NULL;
1191  cPositioner *Positioner = NULL;
1192  bool Break = false;
1193  for (int i = 0; !Break; i++) {
1194  cmd.msg_len = sizeof(cmd.msg);
1195  cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
1196  if (da == cDiseqc::daNone) {
1197  diseqcOffset = 0;
1198  break;
1199  }
1200  bool d = i >= diseqcOffset;
1201  switch (da) {
1202  case cDiseqc::daToneOff: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break;
1203  case cDiseqc::daToneOn: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break;
1204  case cDiseqc::daVoltage13: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break;
1205  case cDiseqc::daVoltage18: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break;
1206  case cDiseqc::daMiniA: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break;
1207  case cDiseqc::daMiniB: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break;
1208  case cDiseqc::daCodes: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break;
1209  case cDiseqc::daPositionN: if ((Positioner = GetPositioner()) != NULL) {
1210  if (d) {
1212  Break = Positioner->IsMoving();
1213  }
1214  }
1215  break;
1216  case cDiseqc::daPositionA: if ((Positioner = GetPositioner()) != NULL) {
1217  if (d) {
1219  Break = Positioner->IsMoving();
1220  }
1221  }
1222  break;
1223  case cDiseqc::daScr:
1224  case cDiseqc::daWait: break;
1225  default: esyslog("ERROR: unknown diseqc command %d", da);
1226  }
1227  if (Break)
1228  diseqcOffset = i + 1;
1229  }
1231  if (scr && !Break)
1232  ResetToneAndVoltage(); // makes sure we don't block the bus!
1233  if (Diseqc->IsScr())
1234  Mutex.Unlock();
1235 }
1236 
1238 {
1239  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13));
1240  CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
1241 }
1242 
1243 static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
1244 {
1245  int ds = SYS_UNDEFINED;
1246  if (Channel->IsAtsc())
1247  ds = SYS_ATSC;
1248  else if (Channel->IsCable())
1249  ds = SYS_DVBC_ANNEX_AC;
1250  else if (Channel->IsSat())
1251  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBS : SYS_DVBS2;
1252  else if (Channel->IsTerr())
1253  ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBT : SYS_DVBT2;
1254  else
1255  esyslog("ERROR: can't determine frontend type for channel %d (%s)", Channel->Number(), Channel->Name());
1256  return ds;
1257 }
1258 
1260 {
1261  dtv_property Props[MAXFRONTENDCMDS];
1262  memset(&Props, 0, sizeof(Props));
1263  dtv_properties CmdSeq;
1264  memset(&CmdSeq, 0, sizeof(CmdSeq));
1265  CmdSeq.props = Props;
1266  SETCMD(DTV_CLEAR, 0);
1267  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1268  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
1269  return false;
1270  }
1271  CmdSeq.num = 0;
1272 
1274 
1275  // Determine the required frontend type:
1277  if (frontendType == SYS_UNDEFINED)
1278  return false;
1279 
1280  SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
1281  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
1282  int frequency = channel.Frequency();
1283  if (Setup.DiSEqC) {
1284  if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
1285  frequency -= diseqc->Lof();
1286  if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
1287  if (IsBondedMaster()) {
1288  ExecuteDiseqc(diseqc, &frequency);
1289  if (frequency == 0)
1290  return false;
1291  }
1292  else
1294  lastDiseqc = diseqc;
1296  }
1297  }
1298  else {
1299  esyslog("ERROR: no DiSEqC parameters found for channel %d (%s)", channel.Number(), channel.Name());
1300  return false;
1301  }
1302  }
1303  else {
1304  int tone = SEC_TONE_OFF;
1305  if (frequency < Setup.LnbSLOF) {
1306  frequency -= Setup.LnbFrequLo;
1307  tone = SEC_TONE_OFF;
1308  }
1309  else {
1310  frequency -= Setup.LnbFrequHi;
1311  tone = SEC_TONE_ON;
1312  }
1313  int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
1314  if (!IsBondedMaster()) {
1315  tone = SEC_TONE_OFF;
1316  volt = SEC_VOLTAGE_13;
1317  }
1318  CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
1319  CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
1320  }
1321  frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
1322 
1323  // DVB-S/DVB-S2 (common parts)
1324  SETCMD(DTV_FREQUENCY, frequency * 1000UL);
1325  SETCMD(DTV_MODULATION, dtp.Modulation());
1326  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1327  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1328  SETCMD(DTV_INVERSION, dtp.Inversion());
1329  if (frontendType == SYS_DVBS2) {
1330  // DVB-S2
1331  SETCMD(DTV_PILOT, dtp.Pilot());
1332  SETCMD(DTV_ROLLOFF, dtp.RollOff());
1333  if (DvbApiVersion >= 0x0508)
1334  SETCMD(DTV_STREAM_ID, dtp.StreamId());
1335  }
1336  else {
1337  // DVB-S
1338  SETCMD(DTV_ROLLOFF, ROLLOFF_35); // DVB-S always has a ROLLOFF of 0.35
1339  }
1340 
1343  }
1344  else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) {
1345  // DVB-C
1346  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1347  SETCMD(DTV_INVERSION, dtp.Inversion());
1348  SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL);
1349  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1350  SETCMD(DTV_MODULATION, dtp.Modulation());
1351 
1354  }
1355  else if (frontendType == SYS_DVBT || frontendType == SYS_DVBT2) {
1356  // DVB-T/DVB-T2 (common parts)
1357  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1358  SETCMD(DTV_INVERSION, dtp.Inversion());
1359  SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth());
1360  SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH());
1361  SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL());
1362  SETCMD(DTV_MODULATION, dtp.Modulation());
1363  SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission());
1364  SETCMD(DTV_GUARD_INTERVAL, dtp.Guard());
1365  SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
1366  if (frontendType == SYS_DVBT2) {
1367  // DVB-T2
1368  SETCMD(DTV_INNER_FEC, dtp.CoderateH());
1369  if (DvbApiVersion >= 0x0508) {
1370  SETCMD(DTV_STREAM_ID, dtp.StreamId());
1371  }
1372  else if (DvbApiVersion >= 0x0503)
1373  SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId());
1374  }
1377  }
1378  else if (frontendType == SYS_ATSC) {
1379  // ATSC
1380  SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
1381  SETCMD(DTV_INVERSION, dtp.Inversion());
1382  SETCMD(DTV_MODULATION, dtp.Modulation());
1383 
1386  }
1387  else {
1388  esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
1389  return false;
1390  }
1391  SETCMD(DTV_TUNE, 0);
1392  if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
1393  esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
1394  return false;
1395  }
1396  return true;
1397 }
1398 
1400 {
1401  cTimeMs Timer;
1402  bool LostLock = false;
1403  fe_status_t Status = (fe_status_t)0;
1404  while (Running()) {
1405  fe_status_t NewStatus;
1406  if (GetFrontendStatus(NewStatus))
1407  Status = NewStatus;
1408  cMutexLock MutexLock(&mutex);
1409  int WaitTime = 1000;
1410  switch (tunerStatus) {
1411  case tsIdle:
1412  break; // we want the TimedWait() below!
1413  case tsSet:
1415  continue;
1416  case tsPositioning:
1417  if (positioner) {
1418  if (positioner->IsMoving())
1419  break; // we want the TimedWait() below!
1420  else if (diseqcOffset) {
1421  lastDiseqc = NULL;
1422  tunerStatus = tsSet; // have it process the rest of the DiSEqC sequence
1423  continue;
1424  }
1425  }
1426  tunerStatus = tsTuned;
1427  Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT : 0));
1428  if (positioner)
1429  continue;
1430  // otherwise run directly into tsTuned...
1431  case tsTuned:
1432  if (Timer.TimedOut()) {
1433  tunerStatus = tsSet;
1434  lastDiseqc = NULL;
1435  lastSource = 0;
1436  if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
1437  isyslog("frontend %d/%d timed out while tuning to channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1438  lastTimeoutReport = time(NULL);
1439  }
1440  continue;
1441  }
1442  WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
1443  // run into tsLocked...
1444  case tsLocked:
1445  if (Status & FE_REINIT) {
1446  tunerStatus = tsSet;
1447  lastDiseqc = NULL;
1448  lastSource = 0;
1449  isyslog("frontend %d/%d was reinitialized", adapter, frontend);
1450  lastTimeoutReport = 0;
1451  continue;
1452  }
1453  else if (Status & FE_HAS_LOCK) {
1454  if (LostLock) {
1455  isyslog("frontend %d/%d regained lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1456  LostLock = false;
1457  }
1459  locked.Broadcast();
1460  lastTimeoutReport = 0;
1461  }
1462  else if (tunerStatus == tsLocked) {
1463  LostLock = true;
1464  isyslog("frontend %d/%d lost lock on channel %d (%s), tp %d", adapter, frontend, channel.Number(), channel.Name(), channel.Transponder());
1465  tunerStatus = tsTuned;
1466  Timer.Set(lockTimeout);
1467  lastTimeoutReport = 0;
1468  continue;
1469  }
1470  break;
1471  default: esyslog("ERROR: unknown tuner status %d", tunerStatus);
1472  }
1473  newSet.TimedWait(mutex, WaitTime);
1474  }
1475 }
1476 
1477 // --- cDvbSourceParam -------------------------------------------------------
1478 
1480 private:
1481  int param;
1482  int srate;
1484 public:
1485  cDvbSourceParam(char Source, const char *Description);
1486  virtual void SetData(cChannel *Channel);
1487  virtual void GetData(cChannel *Channel);
1488  virtual cOsdItem *GetOsdItem(void);
1489  };
1490 
1491 cDvbSourceParam::cDvbSourceParam(char Source, const char *Description)
1492 :cSourceParam(Source, Description)
1493 {
1494  param = 0;
1495  srate = 0;
1496 }
1497 
1499 {
1500  srate = Channel->Srate();
1501  dtp.Parse(Channel->Parameters());
1502  param = 0;
1503 }
1504 
1506 {
1507  Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), srate, dtp.ToString(Source()), true);
1508 }
1509 
1511 {
1512  char type = Source();
1513  const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr;
1514 #undef ST
1515 #define ST(s) if (strchr(s, type))
1516  switch (param++) {
1517  case 0: ST(" S ") return new cMenuEditChrItem( tr("Polarization"), &dtp.polarization, "HVLR"); else return GetOsdItem();
1518  case 1: ST(" ST") return new cMenuEditMapItem( tr("System"), &dtp.system, SystemValues); else return GetOsdItem();
1519  case 2: ST(" CS ") return new cMenuEditIntItem( tr("Srate"), &srate); else return GetOsdItem();
1520  case 3: ST("ACST") return new cMenuEditMapItem( tr("Inversion"), &dtp.inversion, InversionValues); else return GetOsdItem();
1521  case 4: ST(" CST") return new cMenuEditMapItem( tr("CoderateH"), &dtp.coderateH, CoderateValues); else return GetOsdItem();
1522  case 5: ST(" T") return new cMenuEditMapItem( tr("CoderateL"), &dtp.coderateL, CoderateValues); else return GetOsdItem();
1523  case 6: ST("ACST") return new cMenuEditMapItem( tr("Modulation"), &dtp.modulation, ModulationValues); else return GetOsdItem();
1524  case 7: ST(" T") return new cMenuEditMapItem( tr("Bandwidth"), &dtp.bandwidth, BandwidthValues); else return GetOsdItem();
1525  case 8: ST(" T") return new cMenuEditMapItem( tr("Transmission"), &dtp.transmission, TransmissionValues); else return GetOsdItem();
1526  case 9: ST(" T") return new cMenuEditMapItem( tr("Guard"), &dtp.guard, GuardValues); else return GetOsdItem();
1527  case 10: ST(" T") return new cMenuEditMapItem( tr("Hierarchy"), &dtp.hierarchy, HierarchyValues); else return GetOsdItem();
1528  case 11: ST(" S ") return new cMenuEditMapItem( tr("Rolloff"), &dtp.rollOff, RollOffValues); else return GetOsdItem();
1529  case 12: ST(" ST") return new cMenuEditIntItem( tr("StreamId"), &dtp.streamId, 0, 255); else return GetOsdItem();
1530  case 13: ST(" S ") return new cMenuEditMapItem( tr("Pilot"), &dtp.pilot, PilotValues); else return GetOsdItem();
1531  case 14: ST(" T") return new cMenuEditIntItem( tr("T2SystemId"), &dtp.t2systemId, 0, 65535); else return GetOsdItem();
1532  case 15: ST(" T") return new cMenuEditIntItem( tr("SISO/MISO"), &dtp.sisoMiso, 0, 1); else return GetOsdItem();
1533  default: return NULL;
1534  }
1535  return NULL;
1536 }
1537 
1538 // --- cDvbDevice ------------------------------------------------------------
1539 
1540 bool cDvbDevice::useDvbDevices = true;
1543 
1544 const char *DeliverySystemNames[] = {
1545  "",
1546  "DVB-C",
1547  "DVB-C",
1548  "DVB-T",
1549  "DSS",
1550  "DVB-S",
1551  "DVB-S2",
1552  "DVB-H",
1553  "ISDBT",
1554  "ISDBS",
1555  "ISDBC",
1556  "ATSC",
1557  "ATSCMH",
1558  "DTMB",
1559  "CMMB",
1560  "DAB",
1561  "DVB-T2",
1562  "TURBO",
1563  "DVB-C",
1564  "DVB-C2",
1565  NULL
1566  };
1567 
1568 static const int DeliverySystemNamesMax = sizeof(DeliverySystemNames) / sizeof(DeliverySystemNames[0]) - 2; // -1 to get the maximum allowed index & -1 for the NULL => -2
1569 
1570 static const char *GetDeliverySystemName(int Index)
1571 {
1572  if (Index > DeliverySystemNamesMax)
1573  Index = 0;
1574  return DeliverySystemNames[Index];
1575 };
1576 
1577 cDvbDevice::cDvbDevice(int Adapter, int Frontend)
1578 {
1579  adapter = Adapter;
1580  frontend = Frontend;
1581  ciAdapter = NULL;
1582  dvbTuner = NULL;
1583  numDeliverySystems = 0;
1584  numModulations = 0;
1585  bondedDevice = NULL;
1587  tsBuffer = NULL;
1588 
1589  // Devices that are present on all card types:
1590 
1591  int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
1592 
1593  // Common Interface:
1594 
1595  fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
1596  if (fd_ca >= 0)
1598  checkTsBuffer = false;
1599 
1600  // The DVR device (will be opened and closed as needed):
1601 
1602  fd_dvr = -1;
1603 
1604  // We only check the devices that must be present - the others will be checked before accessing them://XXX
1605 
1606  if (fd_frontend >= 0) {
1607  if (QueryDeliverySystems(fd_frontend))
1608  dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend);
1609  }
1610  else
1611  esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
1612 
1614 }
1615 
1617 {
1619  delete dvbTuner;
1620  delete ciAdapter;
1621  UnBond();
1622  // We're not explicitly closing any device files here, since this sometimes
1623  // caused segfaults. Besides, the program is about to terminate anyway...
1624 }
1625 
1626 cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
1627 {
1628  return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE, DEV_DVB_ADAPTER, Adapter, Name, Frontend);
1629 }
1630 
1631 int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
1632 {
1633  cString FileName = DvbName(Name, Adapter, Frontend);
1634  int fd = open(FileName, Mode);
1635  if (fd < 0 && ReportError)
1636  LOG_ERROR_STR(*FileName);
1637  return fd;
1638 }
1639 
1640 bool cDvbDevice::Exists(int Adapter, int Frontend)
1641 {
1643  if (access(FileName, F_OK) == 0) {
1644  int f = open(FileName, O_RDONLY);
1645  if (f >= 0) {
1646  close(f);
1647  return true;
1648  }
1649  else if (errno != ENODEV && errno != EINVAL)
1650  LOG_ERROR_STR(*FileName);
1651  }
1652  else if (errno != ENOENT)
1653  LOG_ERROR_STR(*FileName);
1654  return false;
1655 }
1656 
1657 bool cDvbDevice::Probe(int Adapter, int Frontend)
1658 {
1660  dsyslog("probing %s", *FileName);
1661  for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
1662  if (dp->Probe(Adapter, Frontend))
1663  return true; // a plugin has created the actual device
1664  }
1665  dsyslog("creating cDvbDevice");
1666  new cDvbDevice(Adapter, Frontend); // it's a "budget" device
1667  return true;
1668 }
1669 
1671 {
1672  if (dvbTuner) {
1673  if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1675  if (numDeliverySystems)
1676  return GetDeliverySystemName(deliverySystems[0]); // to have some reasonable default
1677  }
1678  return "";
1679 }
1680 
1682 {
1683  return frontendInfo.name;
1684 }
1685 
1687 {
1688  new cDvbSourceParam('A', "ATSC");
1689  new cDvbSourceParam('C', "DVB-C");
1690  new cDvbSourceParam('S', "DVB-S");
1691  new cDvbSourceParam('T', "DVB-T");
1692  cStringList Nodes;
1693  cReadDir DvbDir(DEV_DVB_BASE);
1694  if (DvbDir.Ok()) {
1695  struct dirent *a;
1696  while ((a = DvbDir.Next()) != NULL) {
1697  if (strstr(a->d_name, DEV_DVB_ADAPTER) == a->d_name) {
1698  int Adapter = strtol(a->d_name + strlen(DEV_DVB_ADAPTER), NULL, 10);
1699  cReadDir AdapterDir(AddDirectory(DEV_DVB_BASE, a->d_name));
1700  if (AdapterDir.Ok()) {
1701  struct dirent *f;
1702  while ((f = AdapterDir.Next()) != NULL) {
1703  if (strstr(f->d_name, DEV_DVB_FRONTEND) == f->d_name) {
1704  int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND), NULL, 10);
1705  Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
1706  }
1707  }
1708  }
1709  }
1710  }
1711  }
1712  int Found = 0;
1713  int Used = 0;
1714  if (Nodes.Size() > 0) {
1715  Nodes.Sort();
1716  for (int i = 0; i < Nodes.Size(); i++) {
1717  int Adapter;
1718  int Frontend;
1719  if (2 == sscanf(Nodes[i], "%d %d", &Adapter, &Frontend)) {
1720  if (Exists(Adapter, Frontend)) {
1721  if (Found < MAXDEVICES) {
1722  Found++;
1724  if (Probe(Adapter, Frontend))
1725  Used++;
1726  }
1727  else
1728  NextCardIndex(1); // skips this one
1729  }
1730  }
1731  }
1732  }
1733  }
1734  if (Found > 0) {
1735  isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "");
1736  if (Used != Found)
1737  isyslog("using only %d DVB device%s", Used, Used != 1 ? "s" : "");
1738  }
1739  else
1740  isyslog("no DVB device found");
1741  return Found > 0;
1742 }
1743 
1745 {
1746  numDeliverySystems = 0;
1747  if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) {
1748  LOG_ERROR;
1749  return false;
1750  }
1751  dtv_property Props[1];
1752  dtv_properties CmdSeq;
1753  // Determine the version of the running DVB API:
1754  if (!DvbApiVersion) {
1755  memset(&Props, 0, sizeof(Props));
1756  memset(&CmdSeq, 0, sizeof(CmdSeq));
1757  CmdSeq.props = Props;
1758  SETCMD(DTV_API_VERSION, 0);
1759  if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) != 0) {
1760  LOG_ERROR;
1761  return false;
1762  }
1763  DvbApiVersion = Props[0].u.data;
1764  isyslog("DVB API version is 0x%04X (VDR was built with 0x%04X)", DvbApiVersion, DVBAPIVERSION);
1765  }
1766  // Determine the types of delivery systems this device provides:
1767  bool LegacyMode = true;
1768  if (DvbApiVersion >= 0x0505) {
1769  memset(&Props, 0, sizeof(Props));
1770  memset(&CmdSeq, 0, sizeof(CmdSeq));
1771  CmdSeq.props = Props;
1772  SETCMD(DTV_ENUM_DELSYS, 0);
1773  int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq);
1774  if (Result == 0) {
1775  for (uint i = 0; i < Props[0].u.buffer.len; i++) {
1777  esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend);
1778  break;
1779  }
1780  deliverySystems[numDeliverySystems++] = Props[0].u.buffer.data[i];
1781  }
1782  LegacyMode = false;
1783  }
1784  else {
1785  esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend);
1786  }
1787  }
1788  if (LegacyMode) {
1789  // Legacy mode (DVB-API < 5.5):
1790  switch (frontendInfo.type) {
1791  case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1793  deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1794  break;
1795  case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1798  break;
1799  case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC; break;
1800  case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break;
1801  default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
1802  }
1803  }
1804  if (numDeliverySystems > 0) {
1805  cString ds("");
1806  for (int i = 0; i < numDeliverySystems; i++)
1807  ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", GetDeliverySystemName(deliverySystems[i]));
1808  cString ms("");
1809  if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
1810  if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
1811  if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); }
1812  if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); }
1813  if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); }
1814  if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); }
1815  if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); }
1816  if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); }
1817  if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); }
1818  if (!**ms)
1819  ms = "unknown modulations";
1820  isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name);
1821  return true;
1822  }
1823  else
1824  esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend);
1825  return false;
1826 }
1827 
1828 bool cDvbDevice::BondDevices(const char *Bondings)
1829 {
1830  UnBondDevices();
1831  if (Bondings) {
1832  cSatCableNumbers SatCableNumbers(MAXDEVICES, Bondings);
1833  for (int i = 0; i < cDevice::NumDevices(); i++) {
1834  int d = SatCableNumbers.FirstDeviceIndex(i);
1835  if (d >= 0) {
1836  int ErrorDevice = 0;
1837  if (cDevice *Device1 = cDevice::GetDevice(i)) {
1838  if (cDevice *Device2 = cDevice::GetDevice(d)) {
1839  if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1840  if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1841  if (!DvbDevice1->Bond(DvbDevice2))
1842  return false; // Bond() has already logged the error
1843  }
1844  else
1845  ErrorDevice = d + 1;
1846  }
1847  else
1848  ErrorDevice = i + 1;
1849  if (ErrorDevice) {
1850  esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings);
1851  return false;
1852  }
1853  }
1854  else
1855  ErrorDevice = d + 1;
1856  }
1857  else
1858  ErrorDevice = i + 1;
1859  if (ErrorDevice) {
1860  esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings);
1861  return false;
1862  }
1863  }
1864  }
1865  }
1866  return true;
1867 }
1868 
1870 {
1871  for (int i = 0; i < cDevice::NumDevices(); i++) {
1872  if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i)))
1873  d->UnBond();
1874  }
1875 }
1876 
1878 {
1879  cMutexLock MutexLock(&bondMutex);
1880  if (!bondedDevice) {
1881  if (Device != this) {
1882  if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) {
1883  if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
1884  bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
1885  Device->bondedDevice = this;
1886  dsyslog("device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1887  return true;
1888  }
1889  }
1890  else
1891  esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->CardIndex() + 1);
1892  }
1893  else
1894  esyslog("ERROR: can't bond device %d with itself", CardIndex() + 1);
1895  }
1896  else
1897  esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->CardIndex() + 1);
1898  return false;
1899 }
1900 
1902 {
1903  cMutexLock MutexLock(&bondMutex);
1904  if (cDvbDevice *d = bondedDevice) {
1905  if (dvbTuner)
1906  dvbTuner->UnBond();
1907  dsyslog("device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1);
1908  while (d->bondedDevice != this)
1909  d = d->bondedDevice;
1910  if (d == bondedDevice)
1911  d->bondedDevice = NULL;
1912  else
1913  d->bondedDevice = bondedDevice;
1914  bondedDevice = NULL;
1915  }
1916 }
1917 
1918 bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
1919 {
1920  cMutexLock MutexLock(&bondMutex);
1921  if (bondedDevice || Positioner())
1922  return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1923  return true;
1924 }
1925 
1927 {
1928  return ciAdapter;
1929 }
1930 
1931 bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
1932 {
1933  if (Handle->pid) {
1934  dmx_pes_filter_params pesFilterParams;
1935  memset(&pesFilterParams, 0, sizeof(pesFilterParams));
1936  if (On) {
1937  if (Handle->handle < 0) {
1938  Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
1939  if (Handle->handle < 0) {
1940  LOG_ERROR;
1941  return false;
1942  }
1943  }
1944  pesFilterParams.pid = Handle->pid;
1945  pesFilterParams.input = DMX_IN_FRONTEND;
1946  pesFilterParams.output = DMX_OUT_TS_TAP;
1947  pesFilterParams.pes_type= DMX_PES_OTHER;
1948  pesFilterParams.flags = DMX_IMMEDIATE_START;
1949  if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
1950  LOG_ERROR;
1951  return false;
1952  }
1953  }
1954  else if (!Handle->used) {
1955  CHECK(ioctl(Handle->handle, DMX_STOP));
1956  if (Type <= ptTeletext) {
1957  pesFilterParams.pid = 0x1FFF;
1958  pesFilterParams.input = DMX_IN_FRONTEND;
1959  pesFilterParams.output = DMX_OUT_DECODER;
1960  pesFilterParams.pes_type= DMX_PES_OTHER;
1961  pesFilterParams.flags = DMX_IMMEDIATE_START;
1962  CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
1963  }
1964  close(Handle->handle);
1965  Handle->handle = -1;
1966  }
1967  }
1968  return true;
1969 }
1970 
1971 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
1972 {
1974  int f = open(FileName, O_RDWR | O_NONBLOCK);
1975  if (f >= 0) {
1976  dmx_sct_filter_params sctFilterParams;
1977  memset(&sctFilterParams, 0, sizeof(sctFilterParams));
1978  sctFilterParams.pid = Pid;
1979  sctFilterParams.timeout = 0;
1980  sctFilterParams.flags = DMX_IMMEDIATE_START;
1981  sctFilterParams.filter.filter[0] = Tid;
1982  sctFilterParams.filter.mask[0] = Mask;
1983  if (ioctl(f, DMX_SET_FILTER, &sctFilterParams) >= 0)
1984  return f;
1985  else {
1986  esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask);
1987  close(f);
1988  }
1989  }
1990  else
1991  esyslog("ERROR: can't open filter handle on '%s'", *FileName);
1992  return -1;
1993 }
1994 
1995 void cDvbDevice::CloseFilter(int Handle)
1996 {
1997  close(Handle);
1998 }
1999 
2000 bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
2001 {
2002  for (int i = 0; i < numDeliverySystems; i++) {
2003  if (deliverySystems[i] == DeliverySystem)
2004  return true;
2005  }
2006  return false;
2007 }
2008 
2009 bool cDvbDevice::ProvidesSource(int Source) const
2010 {
2011  int type = Source & cSource::st_Mask;
2012  return type == cSource::stNone
2013  || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
2014  || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
2015  || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
2017 }
2018 
2019 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
2020 {
2021  if (!ProvidesSource(Channel->Source()))
2022  return false; // doesn't provide source
2023  cDvbTransponderParameters dtp(Channel->Parameters());
2024  if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) ||
2025  dtp.StreamId() != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM) ||
2026  dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
2027  dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
2028  dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
2029  dtp.Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
2030  dtp.Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
2031  dtp.Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
2032  dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
2033  dtp.Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
2034  dtp.Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
2035  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
2036  return false; // requires modulation system which frontend doesn't provide
2037  if (!cSource::IsSat(Channel->Source()) ||
2038  (!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)))
2039  return DeviceHooksProvidesTransponder(Channel);
2040  return false;
2041 }
2042 
2043 bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
2044 {
2045  bool result = false;
2046  bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
2047  bool needsDetachReceivers = false;
2049 
2050  if (dvbTuner && ProvidesTransponder(Channel)) {
2051  result = hasPriority;
2052  if (Priority > IDLEPRIORITY) {
2053  if (Receiving()) {
2054  if (dvbTuner->IsTunedTo(Channel)) {
2055  if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0)) || Channel->Dpid(0) && !HasPid(Channel->Dpid(0))) {
2056  if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
2057  if (CamSlot()->CanDecrypt(Channel))
2058  result = true;
2059  else
2060  needsDetachReceivers = true;
2061  }
2062  else
2063  result = true;
2064  }
2065  else
2066  result = true;
2067  }
2068  else
2069  needsDetachReceivers = Receiving();
2070  }
2071  if (result) {
2072  cMutexLock MutexLock(&bondMutex);
2073  if (!BondingOk(Channel)) {
2074  // This device is bonded, so we need to check the priorities of the others:
2075  for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
2076  if (d->Priority() >= Priority) {
2077  result = false;
2078  break;
2079  }
2080  needsDetachReceivers |= d->Receiving();
2081  }
2083  needsDetachReceivers |= Receiving();
2084  }
2085  }
2086  }
2087  }
2088  if (NeedsDetachReceivers)
2089  *NeedsDetachReceivers = needsDetachReceivers;
2090  return result;
2091 }
2092 
2093 bool cDvbDevice::ProvidesEIT(void) const
2094 {
2095  return dvbTuner != NULL;
2096 }
2097 
2099 {
2101 }
2102 
2104 {
2105  return dvbTuner ? dvbTuner->Positioner() : NULL;
2106 }
2107 
2108 bool cDvbDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
2109 {
2110  return dvbTuner ? dvbTuner->GetSignalStats(Valid, Strength, Cnr, BerPre, BerPost, Per, Status) : false;
2111 }
2112 
2114 {
2115  return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
2116 }
2117 
2119 {
2120  return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
2121 }
2122 
2124 {
2125  return dvbTuner ? dvbTuner->GetTransponder() : NULL;
2126 }
2127 
2128 bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) const
2129 {
2130  return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
2131 }
2132 
2133 bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
2134 {
2135  return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
2136 }
2137 
2138 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
2139 {
2140  if (dvbTuner)
2141  dvbTuner->SetChannel(Channel);
2142  return true;
2143 }
2144 
2145 bool cDvbDevice::HasLock(int TimeoutMs) const
2146 {
2147  return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
2148 }
2149 
2151 {
2153 }
2154 
2156 {
2157  CloseDvr();
2158  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
2159  if (fd_dvr >= 0)
2160  tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5), CardIndex() + 1);
2161  return fd_dvr >= 0;
2162 }
2163 
2165 {
2166  if (fd_dvr >= 0) {
2167  delete tsBuffer;
2168  tsBuffer = NULL;
2169  close(fd_dvr);
2170  fd_dvr = -1;
2171  }
2172 }
2173 
2175 {
2176  if (tsBuffer) {
2177  if (cCamSlot *cs = CamSlot()) {
2178  if (cs->WantsTsData()) {
2179  int Available;
2180  Data = tsBuffer->Get(&Available, checkTsBuffer);
2181  if (!Data)
2182  Available = 0;
2183  Data = cs->Decrypt(Data, Available);
2184  tsBuffer->Skip(Available);
2185  checkTsBuffer = Data != NULL;
2186  return true;
2187  }
2188  }
2189  Data = tsBuffer->Get();
2190  return true;
2191  }
2192  return false;
2193 }
2194 
2196 {
2197  cMutexLock MutexLock(&bondMutex);
2198  cDvbDevice *d = this;
2199  do {
2200  d->cDevice::DetachAllReceivers();
2201  d = d->bondedDevice;
2202  } while (d && d != this && needsDetachBondedReceivers);
2204 }
2205 
2206 // --- cDvbDeviceProbe -------------------------------------------------------
2207 
2209 
2211 {
2212  DvbDeviceProbes.Add(this);
2213 }
2214 
2216 {
2217  DvbDeviceProbes.Del(this, false);
2218 }
2219 
2220 uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
2221 {
2222  uint32_t SubsystemId = 0;
2223  cString FileName = cString::sprintf("/dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
2224  struct stat st;
2225  if (stat(FileName, &st) == 0) {
2226  cReadDir d("/sys/class/dvb");
2227  if (d.Ok()) {
2228  struct dirent *e;
2229  while ((e = d.Next()) != NULL) {
2230  if (strstr(e->d_name, "frontend")) {
2231  FileName = cString::sprintf("/sys/class/dvb/%s/dev", e->d_name);
2232  if (FILE *f = fopen(FileName, "r")) {
2233  cReadLine ReadLine;
2234  char *s = ReadLine.Read(f);
2235  fclose(f);
2236  unsigned Major;
2237  unsigned Minor;
2238  if (s && 2 == sscanf(s, "%u:%u", &Major, &Minor)) {
2239  if (((Major << 8) | Minor) == st.st_rdev) {
2240  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
2241  if ((f = fopen(FileName, "r")) != NULL) {
2242  if (char *s = ReadLine.Read(f))
2243  SubsystemId = strtoul(s, NULL, 0) << 16;
2244  fclose(f);
2245  }
2246  else {
2247  FileName = cString::sprintf("/sys/class/dvb/%s/device/idVendor", e->d_name);
2248  if ((f = fopen(FileName, "r")) != NULL) {
2249  if (char *s = ReadLine.Read(f))
2250  SubsystemId = strtoul(s, NULL, 16) << 16;
2251  fclose(f);
2252  }
2253  }
2254  FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_device", e->d_name);
2255  if ((f = fopen(FileName, "r")) != NULL) {
2256  if (char *s = ReadLine.Read(f))
2257  SubsystemId |= strtoul(s, NULL, 0);
2258  fclose(f);
2259  }
2260  else {
2261  FileName = cString::sprintf("/sys/class/dvb/%s/device/idProduct", e->d_name);
2262  if ((f = fopen(FileName, "r")) != NULL) {
2263  if (char *s = ReadLine.Read(f))
2264  SubsystemId |= strtoul(s, NULL, 16);
2265  fclose(f);
2266  }
2267  }
2268  break;
2269  }
2270  }
2271  }
2272  }
2273  }
2274  }
2275  }
2276  return SubsystemId;
2277 }
static unsigned int FrequencyToHz(unsigned int f)
Definition: dvbdevice.c:1164
#define SETCMD(c, d)
Definition: dvbdevice.c:569
#define DVB_SYSTEM_1
Definition: dvbdevice.c:96
struct dirent * Next(void)
Definition: tools.c:1540
int lastSource
Definition: dvbdevice.c:318
#define DTV_STAT_VALID_PER
Definition: device.h:107
virtual ~cDvbDeviceProbe()
Definition: dvbdevice.c:2215
cDiseqcs Diseqcs
Definition: diseqc.c:439
static bool UseDevice(int n)
Tells whether the device with the given card index shall be used in this instance of VDR.
Definition: device.h:139
const char * DeliverySystemNames[]
Definition: dvbdevice.c:1544
virtual ~cDvbTuner()
Definition: dvbdevice.c:386
cDvbTransponderParameters(const char *Parameters=NULL)
Definition: dvbdevice.c:202
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
unsigned char uchar
Definition: tools.h:31
virtual ~cDvbDevice()
Definition: dvbdevice.c:1616
void Lock(void)
Definition: thread.c:222
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: dvbdevice.c:2009
#define DEV_DVB_BASE
Definition: dvbdevice.h:73
static bool Exists(int Adapter, int Frontend)
Checks whether the given adapter/frontend exists.
Definition: dvbdevice.c:1640
#define DTV_STAT_VALID_NONE
The cDevice class is the base from which actual devices can be derived.
Definition: device.h:102
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:780
uint32_t lastUncValue
Definition: dvbdevice.c:312
cPositioner * positioner
Definition: dvbdevice.c:319
void ResetToneAndVoltage(void)
Definition: dvbdevice.c:1237
#define SCR_RANDOM_TIMEOUT
Definition: dvbdevice.c:35
#define dsyslog(a...)
Definition: tools.h:37
#define DTV_STAT_HAS_VITERBI
Definition: device.h:113
cString AddDirectory(const char *DirName, const char *FileName)
Definition: tools.c:384
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:469
bool IsAtsc(void) const
Definition: channels.h:183
#define CA_ENCRYPTED_MIN
Definition: channels.h:44
int SignalToSQI(const cChannel *Channel, int Signal, int Ber, int FeModulation, int FeCoderateH, int FeFec)
Definition: dvbdevice.c:785
void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
Definition: dvbdevice.c:1180
void Set(int Ms=0)
Definition: tools.c:774
const char * ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map=NULL)
Definition: dvbdevice.c:236
int Modulation(void) const
Definition: dvbdevice.h:134
int Dpid(int i) const
Definition: channels.h:159
static bool Initialize(void)
Initializes the DVB devices.
Definition: dvbdevice.c:1686
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition: thread.c:267
int Srate(void) const
Definition: channels.h:151
#define REF_S2(q1, q2, q3, q4)
Definition: dvbdevice.c:703
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:2174
#define LOG_ERROR
Definition: tools.h:39
cDvbTuner * dvbTuner
Definition: dvbdevice.h:238
#define DVBT_TUNE_TIMEOUT
Definition: dvbdevice.c:30
int UserIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:151
int fd_dvr
Definition: dvbdevice.h:189
int fd_frontend
Definition: dvbdevice.c:306
void UnBond(void)
Removes this device from any bonding it might have with other devices.
Definition: dvbdevice.c:1901
#define DTV_STAT_HAS_SYNC
Definition: device.h:114
cTSBuffer * tsBuffer
< Controls how the DVB device handles Transfer Mode when replaying Dolby Digital audio.
Definition: dvbdevice.h:289
#define DVBC_TUNE_TIMEOUT
Definition: dvbdevice.c:28
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:1918
bool IsPrimaryDevice(void) const
Definition: device.h:213
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition: dvbdevice.c:2113
virtual cOsdItem * GetOsdItem(void)
Returns all the OSD items necessary for editing the source specific parameters of the channel that wa...
Definition: dvbdevice.c:1510
cString ToString(char Type) const
Definition: dvbdevice.c:212
static const int DeliverySystemNamesMax
Definition: dvbdevice.c:1568
#define DVBS_LOCK_TIMEOUT
Definition: dvbdevice.c:27
virtual void GotoPosition(uint Number, int Longitude)
Move the dish to the satellite position stored under the given Number.
Definition: positioner.c:100
static const char * GetDeliverySystemName(int Index)
Definition: dvbdevice.c:1570
int GetSignalStrength(void) const
Definition: dvbdevice.c:927
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1127
#define DVBC_LOCK_TIMEOUT
Definition: dvbdevice.c:29
const tDvbParameterMap SystemValuesSat[]
Definition: dvbdevice.c:99
virtual void Append(T Data)
Definition: tools.h:737
void SetFrontend(int Frontend)
This function is called whenever the positioner is connected to a DVB frontend.
Definition: positioner.h:89
int Source(void) const
Definition: channels.h:150
#define DVBT_LOCK_TIMEOUT
Definition: dvbdevice.c:31
cDvbDeviceProbe(void)
Definition: dvbdevice.c:2210
static uint32_t GetSubsystemId(int Adapter, int Frontend)
Definition: dvbdevice.c:2220
const tDvbParameterMap InversionValues[]
Definition: dvbdevice.c:46
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition: dvbdevice.c:1681
#define MAXDEVICES
Definition: device.h:29
#define esyslog(a...)
Definition: tools.h:35
uint32_t lastUncDelta
Definition: dvbdevice.c:313
#define REF_C1(q1, q2, q3, q4, q5)
Definition: dvbdevice.c:706
bool Parse(const char *s)
Definition: dvbdevice.c:252
char Source(void) const
Definition: sourceparams.h:31
int frontend
Definition: dvbdevice.c:307
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:223
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition: dvbdevice.c:2138
#define LOG_ERROR_STR(s)
Definition: tools.h:40
Definition: tools.h:594
int frontendType
Definition: dvbdevice.c:304
int Position(void) const
Indicates which positioning mode to use in order to move the dish to a given satellite position.
Definition: diseqc.h:126
const cPositioner * Positioner(void) const
Definition: dvbdevice.c:351
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:127
#define DTV_STAT_HAS_CARRIER
Definition: device.h:112
#define DEV_DVB_ADAPTER
Definition: dvbdevice.h:74
#define TUNER_POLL_TIMEOUT
Definition: dvbdevice.c:298
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition: device.c:642
bool IsScr(void) const
Returns true if this DiSEqC sequence uses Satellite Channel Routing.
Definition: diseqc.h:132
int Adapter(void) const
Definition: dvbdevice.h:198
#define DTV_STAT_VALID_BERPOST
Definition: device.h:106
T min(T a, T b)
Definition: tools.h:59
int Ca(int Index=0) const
Definition: channels.h:171
cDvbTuner * GetBondedMaster(void)
Definition: dvbdevice.c:466
bool Poll(int TimeoutMs=0)
Definition: tools.c:1517
#define REF_T2(q1, q2, q3, q4)
Definition: dvbdevice.c:705
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: dvbdevice.c:2098
uint32_t subsystemId
Definition: dvbdevice.c:308
virtual bool IsMoving(void) const
Returns true if the dish is currently moving as a result of a call to GotoPosition() or GotoAngle().
Definition: positioner.c:127
int MapToDriver(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:192
int adapter
Definition: dvbdevice.c:307
char * Read(FILE *f)
Definition: tools.c:1459
bool QueryDeliverySystems(int fd_frontend)
Definition: dvbdevice.c:1744
cPositioner * GetPositioner(void)
Definition: dvbdevice.c:1171
Definition: diseqc.h:62
bool needsDetachBondedReceivers
Definition: dvbdevice.h:193
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition: device.c:148
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition: device.c:710
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
Definition: channels.c:176
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition: device.c:1650
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition: positioner.c:133
int frontend
Definition: dvbdevice.h:183
int LnbFrequLo
Definition: config.h:272
int System(void) const
Definition: dvbdevice.h:135
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition: positioner.h:31
cMutex mutex
Definition: dvbdevice.c:323
static int DvbApiVersion
Definition: dvbdevice.c:24
virtual void GotoAngle(int Longitude)
Move the dish to the given angular position.
Definition: positioner.c:107
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition: dvbdevice.c:2103
cCondVar newSet
Definition: dvbdevice.c:325
bool GetSignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Definition: dvbdevice.c:577
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:146
int StrengthToSSI(const cChannel *Channel, int Strength, int FeModulation, int FeCoderateH, int FeFec)
Definition: dvbdevice.c:708
const tDvbParameterMap HierarchyValues[]
Definition: dvbdevice.c:134
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition: dvbdevice.c:1670
#define IDLEPRIORITY
Definition: config.h:47
cCiAdapter * ciAdapter
Definition: dvbdevice.h:233
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition: device.c:651
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:2093
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition: dvbdevice.c:1828
#define trNOOP(s)
Definition: i18n.h:88
#define CHECK(s)
Definition: tools.h:51
cChannel channel
Definition: dvbdevice.c:315
#define DTV_STAT_VALID_STATUS
Definition: device.h:108
static bool Probe(int Adapter, int Frontend)
Probes for existing DVB devices.
Definition: dvbdevice.c:1657
bool bondedMaster
Definition: dvbdevice.c:327
T constrain(T v, T l, T h)
Definition: tools.h:68
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
Definition: dvbdevice.c:1931
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition: device.c:662
int numModulations
Definition: dvbdevice.h:188
int FrontendType(void) const
Definition: dvbdevice.c:342
const cScr * scr
Definition: dvbdevice.c:320
#define MAXDELIVERYSYSTEMS
Definition: dvbdevice.h:70
static cMutex bondMutex
Definition: dvbdevice.c:302
virtual void SetData(cChannel *Channel)
Sets all source specific parameters to those of the given Channel.
Definition: dvbdevice.c:1498
void Broadcast(void)
Definition: thread.c:150
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:2133
int Size(void) const
Definition: tools.h:717
cDvbDevice * bondedDevice
Definition: dvbdevice.h:192
cDvbSourceParam(char Source, const char *Description)
Definition: dvbdevice.c:1491
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Returns statistics about the currently received signal (if available).
Definition: dvbdevice.c:2108
time_t lastUncChange
Definition: dvbdevice.c:314
int LnbSLOF
Definition: config.h:271
int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
Definition: dvbdevice.c:173
bool GetFrontendStatus(fe_status_t &Status) const
Definition: dvbdevice.c:552
bool IsCable(void) const
Definition: channels.h:184
#define DVBAPIVERSION
Definition: dvbdevice.h:17
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:2043
static cDvbCiAdapter * CreateCiAdapter(cDevice *Device, int Fd)
Definition: dvbci.c:102
#define DTV_STAT_HAS_LOCK
Definition: device.h:115
bool BondingOk(const cChannel *Channel, bool ConsiderOccupied=false) const
Definition: dvbdevice.c:450
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: dvbdevice.c:2128
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, int *Frequency) const
Parses the DiSEqC commands and returns the appropriate action code with every call.
Definition: diseqc.c:402
cList< cDvbDeviceProbe > DvbDeviceProbes
Definition: dvbdevice.c:2208
static cMutex bondMutex
Definition: dvbdevice.h:191
void ClearEventQueue(void) const
Definition: dvbdevice.c:542
int dB1000toPercent(int dB1000, int Low, int High)
Definition: dvbdevice.c:687
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition: thread.c:304
virtual void CloseDvr(void)
Shuts down the DVR.
Definition: dvbdevice.c:2164
#define DEV_DVB_FRONTEND
Definition: dvbdevice.h:76
#define DVBS_TUNE_TIMEOUT
Definition: dvbdevice.c:26
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
Definition: dvbdevice.c:1995
static bool IsSat(int Code)
Definition: sources.h:57
bool Ok(void)
Definition: tools.h:418
#define DEV_DVB_CA
Definition: dvbdevice.h:81
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:2019
cSetup Setup
Definition: config.c:372
int DriverIndex(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:162
int adapter
Definition: dvbdevice.h:183
#define MAXFRONTENDCMDS
Definition: dvbdevice.c:568
cString GetBondingParams(const cChannel *Channel=NULL) const
Definition: dvbdevice.c:433
void UnBond(void)
Definition: dvbdevice.c:417
Definition: ci.h:232
#define ATSC_LOCK_TIMEOUT
Definition: dvbdevice.c:33
#define REF_T1(q1, q2, q3)
Definition: dvbdevice.c:704
const tDvbParameterMap ModulationValues[]
Definition: dvbdevice.c:79
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:101
#define DTV_STAT_VALID_STRENGTH
Definition: device.h:103
int deliverySystems[MAXDELIVERYSYSTEMS]
Definition: dvbdevice.h:186
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition: dvbdevice.c:2123
bool lnbPowerTurnedOn
Definition: dvbdevice.c:321
Definition: thread.h:67
virtual bool ProvidesDeliverySystem(int DeliverySystem) const
Definition: dvbdevice.c:2000
int Apid(int i) const
Definition: channels.h:158
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition: thread.c:132
bool Locked(int TimeoutMs=0)
Definition: dvbdevice.c:530
#define DVB_SYSTEM_2
Definition: dvbdevice.c:97
uint32_t SubsystemId(void) const
Definition: dvbdevice.c:347
void Skip(int Count)
If after a call to Get() more or less than TS_SIZE of the available data has been processed,...
Definition: device.c:1923
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:2155
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:214
int LnbFrequHi
Definition: config.h:273
#define DEV_DVB_DVR
Definition: dvbdevice.h:77
int PrintParameter(char *p, char Name, int Value) const
Definition: dvbdevice.c:207
int diseqcOffset
Definition: dvbdevice.c:317
bool Bond(cDvbTuner *Tuner)
Definition: dvbdevice.c:401
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition: dvbdevice.c:2195
static void UnBondDevices(void)
Unbonds all devices.
Definition: dvbdevice.c:1869
#define DTV_ENUM_DELSYS
Definition: dvbdevice.h:57
const char * MapToUserString(int Value, const tDvbParameterMap *Map)
Definition: dvbdevice.c:184
const char * Name(void) const
Definition: channels.c:107
static bool useDvbDevices
Definition: dvbdevice.h:177
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition: dvbdevice.c:1926
const tDvbParameterMap PilotValues[]
Definition: dvbdevice.c:39
int Vpid(void) const
Definition: channels.h:152
dvb_frontend_info frontendInfo
Definition: dvbdevice.h:185
#define MEGABYTE(n)
Definition: tools.h:45
eTunerStatus tunerStatus
Definition: dvbdevice.c:322
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition: dvbdevice.c:2145
const cDiseqc * lastDiseqc
Definition: dvbdevice.c:316
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition: device.c:1893
static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
Definition: dvbdevice.c:1243
cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
Definition: dvbdevice.c:359
const tDvbParameterMap RollOffValues[]
Definition: dvbdevice.c:143
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:146
int Frontend(void) const
Definition: dvbdevice.h:199
static int setTransferModeForDolbyDigital
Definition: dvbdevice.h:277
int GetSignalQuality(void) const
Definition: dvbdevice.c:992
int Frequency(void) const
Returns the actual frequency, as given in 'channels.conf'.
Definition: channels.h:147
const cDiseqc * Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
Selects a DiSEqC entry suitable for the given Device and tuning parameters.
Definition: diseqc.c:447
Definition: diseqc.h:34
const tDvbParameterMap CoderateValues[]
Definition: dvbdevice.c:63
bool IsBondedMaster(void) const
Definition: dvbdevice.c:331
#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:1877
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition: device.c:531
#define DEV_DVB_DEMUX
Definition: dvbdevice.h:78
#define DTV_STAT_HAS_SIGNAL
Definition: device.h:111
#define DTV_STAT_VALID_BERPRE
Definition: device.h:105
bool checkTsBuffer
Definition: dvbdevice.h:190
bool IsTunedTo(const cChannel *Channel) const
Definition: dvbdevice.c:487
#define ST(s)
#define isyslog(a...)
Definition: tools.h:36
eDiseqcActions
Definition: diseqc.h:64
virtual bool CanDecrypt(const cChannel *Channel, cMtdMapper *MtdMapper=NULL)
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:2662
Definition: thread.h:79
#define REF_S1(q1)
Definition: dvbdevice.c:702
bool SetFrontend(void)
Definition: dvbdevice.c:1259
void Sort(bool IgnoreCase=false)
Definition: tools.h:806
#define DTV_STREAM_ID
Definition: dvbdevice.h:64
The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API.
Definition: dvbdevice.h:167
void SetChannel(const cChannel *Channel)
Definition: dvbdevice.c:497
Definition: tools.h:369
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise).
Definition: sources.h:35
#define LOCK_THRESHOLD
Definition: dvbdevice.c:990
#define DTV_STAT_HAS_NONE
Definition: device.h:110
#define DTV_DVBT2_PLP_ID_LEGACY
Definition: dvbdevice.h:65
const tDvbParameterMap SystemValuesTerr[]
Definition: dvbdevice.c:105
#define DTV_STAT_VALID_CNR
Definition: device.h:104
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:1399
const tDvbParameterMap BandwidthValues[]
Definition: dvbdevice.c:53
int lockTimeout
Definition: dvbdevice.c:310
bool IsTerr(void) const
Definition: channels.h:186
int tuneTimeout
Definition: dvbdevice.c:309
#define BER_ERROR_FREE
Definition: dvbdevice.c:783
const char * Parameters(void) const
Definition: channels.h:180
cCondVar locked
Definition: dvbdevice.c:324
Definition: tools.h:393
Derived cDevice classes that can receive channels will have to provide Transport Stream (TS) packets ...
Definition: device.h:861
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
Definition: dvbdevice.c:1971
time_t lastTimeoutReport
Definition: dvbdevice.c:311
cDvbDevice(int Adapter, int Frontend)
Definition: dvbdevice.c:1577
int numDeliverySystems
Definition: dvbdevice.h:187
const cChannel * GetTransponder(void) const
Definition: dvbdevice.c:346
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:354
bool SetFrontendType(const cChannel *Channel)
#define ATSC_TUNE_TIMEOUT
Definition: dvbdevice.c:32
const char * userString
Definition: dvbdevice.h:86
cDvbTransponderParameters dtp
Definition: dvbdevice.c:1483
static cString DvbName(const char *Name, int Adapter, int Frontend)
Definition: dvbdevice.c:1626
int Priority(void) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition: device.c:1632
Definition: tools.h:176
int Number(void) const
Definition: channels.h:177
static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError=false)
Definition: dvbdevice.c:1631
bool IsSat(void) const
Definition: channels.h:185
cDvbTuner * bondedTuner
Definition: dvbdevice.c:326
const cDvbDevice * device
Definition: dvbdevice.c:305
const tDvbParameterMap GuardValues[]
Definition: dvbdevice.c:122
virtual void GetData(cChannel *Channel)
Copies all source specific parameters to the given Channel.
Definition: dvbdevice.c:1505
const tDvbParameterMap TransmissionValues[]
Definition: dvbdevice.c:111
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition: dvbdevice.c:2118
static void SetTransferModeForDolbyDigital(int Mode)
Definition: dvbdevice.c:2150
void Unlock(void)
Definition: thread.c:228
bool TimedOut(void) const
Definition: tools.c:779
int DiSEqC
Definition: config.h:274