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