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