MythTV  master
dvbchannel.cpp
Go to the documentation of this file.
1 /*
2  * Class DVBChannel
3  *
4  * Copyright (C) Kenneth Aafloy 2003
5  *
6  * Description:
7  * Has the responsibility of opening the Frontend device and
8  * setting the options to tune a channel. It also keeps other
9  * channel options used by the dvb hierarcy.
10  *
11  * Author(s):
12  * Taylor Jacob (rtjacob at earthlink.net)
13  * - Changed tuning and DB structure
14  * Kenneth Aafloy (ke-aa at frisurf.no)
15  * - Rewritten for faster tuning.
16  * Ben Bucksch
17  * - Wrote the original implementation
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32  */
33 
34 // POSIX headers
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <sys/poll.h>
38 #include <sys/select.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 
42 // MythTV headers
43 #include "mythconfig.h"
44 #include "mythdb.h"
45 #include "cardutil.h"
46 #include "channelutil.h"
47 #include "dvbtypes.h"
48 #include "dvbchannel.h"
49 #include "dvbcam.h"
50 #include "tv_rec.h"
51 
52 static void drain_dvb_events(int fd);
53 static bool wait_for_backend(int fd, int timeout_ms);
54 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
55  DTVTunerType, const DTVMultiplex&, int intermediate_freq, bool can_fec_auto);
57  DTVTunerType, const dvb_frontend_parameters&);
58 
59 int64_t concurrent_tunings_delay = 1000;
60 QDateTime DVBChannel::last_tuning = QDateTime::currentDateTime();
61 
62 #define LOC QString("DVBChan[%1](%2): ").arg(m_inputid).arg(GetDevice())
63 
69 DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent)
70  : DTVChannel(parent),
71  // Helper classes
72  diseqc_tree(nullptr), dvbcam(nullptr),
73  // Device info
74  capabilities(0), ext_modulations(0),
75  frequency_minimum(0), frequency_maximum(0),
76  symbol_rate_minimum(0), symbol_rate_maximum(0),
77  // Tuning
78  tune_lock(), hw_lock(QMutex::Recursive),
79  last_lnb_dev_id(~0x0),
80  tuning_delay(0), sigmon_delay(25),
81  first_tune(true),
82  // Misc
83  fd_frontend(-1), device(aDevice),
84  has_crc_bug(false)
85 {
86  master_map_lock.lockForWrite();
88  if (m_pParent)
89  key += QString(":%1")
91  master_map[key].push_back(this); // == RegisterForMaster
92  DVBChannel *master = static_cast<DVBChannel*>(master_map[key].front());
93  if (master == this)
94  {
95  dvbcam = new DVBCam(device);
97  }
98  else
99  {
100  dvbcam = master->dvbcam;
101  has_crc_bug = master->has_crc_bug;
102  }
103  master_map_lock.unlock();
104 
106 }
107 
109 {
110  // set a new master if there are other instances and we're the master
111  // whether we are the master or not remove us from the map..
112  master_map_lock.lockForWrite();
114  if (m_pParent)
115  key += QString(":%1")
117  DVBChannel *master = static_cast<DVBChannel*>(master_map[key].front());
118  if (master == this)
119  {
120  master_map[key].pop_front();
121  DVBChannel *new_master = nullptr;
122  if (!master_map[key].empty())
123  new_master = dynamic_cast<DVBChannel*>(master_map[key].front());
124  if (new_master)
125  {
126  QMutexLocker master_locker(&(master->hw_lock));
127  QMutexLocker new_master_locker(&(new_master->hw_lock));
128  new_master->is_open = master->is_open;
129  }
130  }
131  else
132  {
133  master_map[key].removeAll(this);
134  }
135  master_map_lock.unlock();
136 
137  Close();
138 
139  // if we're the last one out delete dvbcam
140  master_map_lock.lockForRead();
141  MasterMap::iterator mit = master_map.find(key);
142  if ((*mit).empty())
143  delete dvbcam;
144  dvbcam = nullptr;
145  master_map_lock.unlock();
146 
147  // diseqc_tree is managed elsewhere
148 }
149 
151 {
152  LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel");
153 
154  QMutexLocker locker(&hw_lock);
155 
156  IsOpenMap::iterator it = is_open.find(who);
157  if (it == is_open.end())
158  return; // this caller didn't have it open in the first place..
159 
160  is_open.erase(it);
161 
162  DVBChannel *master = GetMasterLock();
163  if (master != nullptr && master != this)
164  {
165  if (dvbcam->IsRunning())
166  dvbcam->SetPMT(this, nullptr);
167  master->Close(this);
168  fd_frontend = -1;
169  ReturnMasterLock(master);
170  return;
171  }
172  ReturnMasterLock(master); // if we're the master we don't need this lock..
173 
174  if (!is_open.empty())
175  return; // not all callers have closed the DVB channel yet..
176 
177  if (diseqc_tree)
178  diseqc_tree->Close();
179 
180  if (fd_frontend >= 0)
181  {
183  fd_frontend = -1;
184 
185  dvbcam->Stop();
186  }
187 }
188 
190 {
191  LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel");
192 
193  if (!m_inputid)
194  {
195  if (!InitializeInput())
196  return false;
197  }
198 
199  QMutexLocker locker(&hw_lock);
200 
201  if (fd_frontend >= 0)
202  {
203  is_open[who] = true;
204  return true;
205  }
206 
207  DVBChannel *master = GetMasterLock();
208  if (master != this)
209  {
210  if (!master->Open(who))
211  {
212  ReturnMasterLock(master);
213  return false;
214  }
215 
216  fd_frontend = master->fd_frontend;
217  frontend_name = master->frontend_name;
218  tunerType = master->tunerType;
219  capabilities = master->capabilities;
225 
226  is_open[who] = true;
227 
228  if (!InitializeInput())
229  {
230  Close();
231  ReturnMasterLock(master);
232  return false;
233  }
234 
235  ReturnMasterLock(master);
236  return true;
237  }
238  ReturnMasterLock(master); // if we're the master we don't need this lock..
239 
240  QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
241  QByteArray devn = devname.toLatin1();
242 
243  for (int tries = 1; ; ++tries)
244  {
245  fd_frontend = open(devn.constData(), O_RDWR | O_NONBLOCK);
246  if (fd_frontend >= 0)
247  break;
248  LOG(VB_GENERAL, LOG_WARNING, LOC +
249  "Opening DVB frontend device failed." + ENO);
250  if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
251  {
252  LOG(VB_GENERAL, LOG_ERR, LOC +
253  QString("Failed to open DVB frontend device due to "
254  "fatal error or too many attempts."));
255  return false;
256  }
257  usleep(50000);
258  }
259 
260  dvb_frontend_info info;
261  memset(&info, 0, sizeof(info));
262  if (ioctl(fd_frontend, FE_GET_INFO, &info) < 0)
263  {
264  LOG(VB_GENERAL, LOG_ERR, LOC +
265  "Failed to get frontend information." + ENO);
266 
268  fd_frontend = -1;
269  return false;
270  }
271 
272  frontend_name = info.name;
273  tunerType = info.type;
274 #if HAVE_FE_CAN_2G_MODULATION
275  if (info.caps & FE_CAN_2G_MODULATION)
276  {
281  }
282 #endif // HAVE_FE_CAN_2G_MODULATION
283  capabilities = info.caps;
284  frequency_minimum = info.frequency_min;
285  frequency_maximum = info.frequency_max;
286  symbol_rate_minimum = info.symbol_rate_min;
287  symbol_rate_maximum = info.symbol_rate_max;
288 
289 #if DVB_API_VERSION >=5
290  unsigned int i;
291  struct dtv_property prop;
292  struct dtv_properties cmd;
293 
294  memset(&prop, 0, sizeof(prop));
295  prop.cmd = DTV_API_VERSION;
296  cmd.num = 1;
297  cmd.props = &prop;
298  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
299  {
300  LOG(VB_RECORD, LOG_INFO, LOC +
301  QString("dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
302  }
303 
304  memset(&prop, 0, sizeof(prop));
305  prop.cmd = DTV_ENUM_DELSYS;
306  cmd.num = 1;
307  cmd.props = &prop;
308 
309  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
310  {
311  LOG(VB_RECORD, LOG_DEBUG, LOC +
312  QString("num props %1").arg(prop.u.buffer.len));
313  for (i = 0; i < prop.u.buffer.len; i++)
314  {
315  LOG(VB_RECORD, LOG_INFO, LOC +
316  QString("delsys %1: %2 %3")
317  .arg(i).arg(prop.u.buffer.data[i])
318  .arg(DTVModulationSystem::toString(prop.u.buffer.data[i])));
319  switch (prop.u.buffer.data[i])
320  {
321  // TODO: not supported. you can have DVBC and DVBT on the same card
322  // The following are backwards compatible so its ok
323  case SYS_DVBS2:
325  break;
326  case SYS_DVBT2:
328  break;
329  default:
330  break;
331  }
332  }
333  }
334 #endif
335 
336  LOG(VB_RECORD, LOG_INFO, LOC +
337  QString("Using DVB card %1, with frontend '%2'.")
338  .arg(device).arg(frontend_name));
339 
340  // Turn on the power to the LNB
342  {
343 
345  if (diseqc_tree)
346  {
347  bool is_SCR = false;
348 
350  if (scr)
351  {
352  is_SCR = true;
353  LOG(VB_CHANNEL, LOG_INFO, LOC + "Requested DVB channel is on SCR system");
354  }
355  else
356  LOG(VB_CHANNEL, LOG_INFO, LOC + "Requested DVB channel is on non-SCR system");
357 
358  diseqc_tree->Open(fd_frontend, is_SCR);
359  }
360  }
361 
362  first_tune = true;
363 
364  if (!InitializeInput())
365  {
366  Close();
367  return false;
368  }
369 
370  if (fd_frontend >= 0)
371  is_open[who] = true;
372 
373  return (fd_frontend >= 0);
374 }
375 
376 bool DVBChannel::IsOpen(void) const
377 {
378  //Have to acquire the hw lock to prevent is_open being modified whilst we're searching it
379  QMutexLocker locker(&hw_lock);
380  IsOpenMap::const_iterator it = is_open.find(this);
381  return it != is_open.end();
382 }
383 
384 bool DVBChannel::Init(QString &startchannel, bool setchan)
385 {
386  if (setchan && !IsOpen())
387  Open(this);
388 
389  return ChannelBase::Init(startchannel, setchan);
390 }
391 
395 void DVBChannel::CheckFrequency(uint64_t frequency) const
396 {
399  (frequency < frequency_minimum || frequency > frequency_maximum))
400  {
401  LOG(VB_GENERAL, LOG_WARNING, LOC +
402  QString("Your frequency setting (%1) is out of range. "
403  "(min/max:%2/%3)")
404  .arg(frequency).arg(frequency_minimum).arg(frequency_maximum));
405  }
406 }
407 
409 {
410  if ((tuning.inversion == DTVInversion::kInversionAuto) &&
411  !(capabilities & FE_CAN_INVERSION_AUTO))
412  {
413  LOG(VB_GENERAL, LOG_WARNING, LOC +
414  "'Auto' inversion parameter unsupported by this driver, "
415  "falling back to 'off'.");
417  }
418 
419  // DVB-S needs a fully initialized diseqc tree and is checked later in Tune
420  if (!diseqc_tree)
421  {
422  const DVBChannel *master = GetMasterLock();
423  if (master == nullptr || !master->diseqc_tree)
424  CheckFrequency(tuning.frequency);
425  ReturnMasterLock(master);
426  }
427 
428  if (tunerType.IsFECVariable() &&
431  (tuning.symbolrate < symbol_rate_minimum ||
433  {
434  LOG(VB_GENERAL, LOG_WARNING, LOC +
435  QString("Symbol Rate setting (%1) is out of range (min/max:%2/%3)")
436  .arg(tuning.symbolrate)
438  }
439 
440  if (tunerType.IsFECVariable() && !CheckCodeRate(tuning.fec))
441  {
442  LOG(VB_GENERAL, LOG_WARNING, LOC +
443  "Selected fec_inner parameter unsupported by this driver.");
444  }
445 
447  {
448  LOG(VB_GENERAL, LOG_WARNING, LOC +
449  "Selected modulation parameter unsupported by this driver.");
450  }
451 
454  {
455  LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
456  return;
457  }
458 
459  // Check OFDM Tuning params
460 
461  if (!CheckCodeRate(tuning.hp_code_rate))
462  {
463  LOG(VB_GENERAL, LOG_WARNING, LOC +
464  "Selected code_rate_hp parameter unsupported by this driver.");
465  }
466 
467  if (!CheckCodeRate(tuning.lp_code_rate))
468  {
469  LOG(VB_GENERAL, LOG_WARNING, LOC +
470  "Selected code_rate_lp parameter unsupported by this driver.");
471  }
472 
473  if ((tuning.bandwidth == DTVBandwidth::kBandwidthAuto) &&
474  !(capabilities & FE_CAN_BANDWIDTH_AUTO))
475  {
476  LOG(VB_GENERAL, LOG_WARNING, LOC +
477  "'Auto' bandwidth parameter unsupported by this driver.");
478  }
479 
481  !(capabilities & FE_CAN_TRANSMISSION_MODE_AUTO))
482  {
483  LOG(VB_GENERAL, LOG_WARNING, LOC +
484  "'Auto' transmission_mode parameter unsupported by this driver.");
485  }
486 
488  !(capabilities & FE_CAN_GUARD_INTERVAL_AUTO))
489  {
490  LOG(VB_GENERAL, LOG_WARNING, LOC +
491  "'Auto' guard_interval parameter unsupported by this driver.");
492  }
493 
494  if ((tuning.hierarchy == DTVHierarchy::kHierarchyAuto) &&
495  !(capabilities & FE_CAN_HIERARCHY_AUTO))
496  {
497  LOG(VB_GENERAL, LOG_WARNING, LOC +
498  "'Auto' hierarchy parameter unsupported by this driver. ");
499  }
500 
501  if (!CheckModulation(tuning.modulation))
502  {
503  LOG(VB_GENERAL, LOG_WARNING, LOC +
504  "Selected modulation parameter unsupported by this driver.");
505  }
506 
507  LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
508 }
509 
514 {
515  const uint64_t caps = capabilities;
516  return
517  ((DTVCodeRate::kFECNone == rate)) ||
518  ((DTVCodeRate::kFEC_1_2 == rate) && (caps & FE_CAN_FEC_1_2)) ||
519  ((DTVCodeRate::kFEC_2_3 == rate) && (caps & FE_CAN_FEC_2_3)) ||
520  ((DTVCodeRate::kFEC_3_4 == rate) && (caps & FE_CAN_FEC_3_4)) ||
521  ((DTVCodeRate::kFEC_4_5 == rate) && (caps & FE_CAN_FEC_4_5)) ||
522  ((DTVCodeRate::kFEC_5_6 == rate) && (caps & FE_CAN_FEC_5_6)) ||
523  ((DTVCodeRate::kFEC_6_7 == rate) && (caps & FE_CAN_FEC_6_7)) ||
524  ((DTVCodeRate::kFEC_7_8 == rate) && (caps & FE_CAN_FEC_7_8)) ||
525  ((DTVCodeRate::kFEC_8_9 == rate) && (caps & FE_CAN_FEC_8_9)) ||
526  ((DTVCodeRate::kFECAuto == rate) && (caps & FE_CAN_FEC_AUTO));
527 }
528 
533 {
534  const DTVModulation m = modulation;
535  const uint64_t c = capabilities;
536 
537  return
538  ((DTVModulation::kModulationQPSK == m) && (c & FE_CAN_QPSK)) ||
539 #if HAVE_FE_CAN_2G_MODULATION
540  ((DTVModulation::kModulation8PSK == m) && (c & FE_CAN_2G_MODULATION)) ||
541  ((DTVModulation::kModulation16APSK == m) && (c & FE_CAN_2G_MODULATION)) ||
542  ((DTVModulation::kModulation32APSK == m) && (c & FE_CAN_2G_MODULATION)) ||
543 #endif //HAVE_FE_CAN_2G_MODULATION
544  ((DTVModulation::kModulationQAM16 == m) && (c & FE_CAN_QAM_16)) ||
545  ((DTVModulation::kModulationQAM32 == m) && (c & FE_CAN_QAM_32)) ||
546  ((DTVModulation::kModulationQAM64 == m) && (c & FE_CAN_QAM_64)) ||
547  ((DTVModulation::kModulationQAM128 == m) && (c & FE_CAN_QAM_128)) ||
548  ((DTVModulation::kModulationQAM256 == m) && (c & FE_CAN_QAM_256)) ||
549  ((DTVModulation::kModulationQAMAuto == m) && (c & FE_CAN_QAM_AUTO)) ||
550  ((DTVModulation::kModulation8VSB == m) && (c & FE_CAN_8VSB)) ||
551  ((DTVModulation::kModulation16VSB == m) && (c & FE_CAN_16VSB));
552 }
553 
558 {
559  if (!dvbcam->IsRunning())
560  dvbcam->Start();
561  if (pmt && dvbcam->IsRunning())
562  dvbcam->SetPMT(this, pmt);
563 }
564 
569 void DVBChannel::SetTimeOffset(double offset)
570 {
571  if (dvbcam->IsRunning())
572  dvbcam->SetTimeOffset(offset);
573 }
574 
575 
576 bool DVBChannel::Tune(const DTVMultiplex &tuning)
577 {
578  if (!m_inputid)
579  {
580  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Tune(): Invalid input."));
581  return false;
582  }
583  return Tune(tuning, false, false);
584 }
585 
586 #if DVB_API_VERSION >= 5
587 static struct dtv_properties *dtvmultiplex_to_dtvproperties(
588  DTVTunerType tuner_type, const DTVMultiplex &tuning, int intermediate_freq,
589  bool can_fec_auto, bool do_tune = true)
590 {
591  uint c = 0;
592  struct dtv_properties *cmdseq;
593 
594  if (tuner_type != DTVTunerType::kTunerTypeDVBT &&
595  tuner_type != DTVTunerType::kTunerTypeDVBC &&
596  tuner_type != DTVTunerType::kTunerTypeDVBS1 &&
597  tuner_type != DTVTunerType::kTunerTypeDVBS2 &&
598  tuner_type != DTVTunerType::kTunerTypeDVBT2)
599  {
600  LOG(VB_GENERAL, LOG_ERR, "DVBChan: Unsupported tuner type " +
601  tuner_type.toString());
602  return nullptr;
603  }
604 
605  LOG(VB_CHANNEL, LOG_DEBUG, "DVBChan: modsys " + tuning.mod_sys.toString());
606 
607  cmdseq = (struct dtv_properties*) calloc(1, sizeof(*cmdseq));
608  if (!cmdseq)
609  return nullptr;
610 
611  cmdseq->props = (struct dtv_property*) calloc(20, sizeof(*(cmdseq->props)));
612  if (!(cmdseq->props))
613  {
614  free(cmdseq);
615  return nullptr;
616  }
617 
618  // The cx24116 DVB-S2 demod anounce FE_CAN_FEC_AUTO but has apparently
619  // trouble with FEC_AUTO on DVB-S2 transponders
621  can_fec_auto = false;
622 
623  if (tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
624  tuner_type == DTVTunerType::kTunerTypeDVBT ||
625  tuner_type == DTVTunerType::kTunerTypeDVBT2)
626  {
627  cmdseq->props[c].cmd = DTV_DELIVERY_SYSTEM;
628  cmdseq->props[c++].u.data = tuning.mod_sys;
629  }
630 
631  cmdseq->props[c].cmd = DTV_FREQUENCY;
632  cmdseq->props[c++].u.data = intermediate_freq ? intermediate_freq : tuning.frequency;
633  cmdseq->props[c].cmd = DTV_MODULATION;
634  cmdseq->props[c++].u.data = tuning.modulation;
635  cmdseq->props[c].cmd = DTV_INVERSION;
636  cmdseq->props[c++].u.data = tuning.inversion;
637 
638  if (tuner_type == DTVTunerType::kTunerTypeDVBS1 ||
639  tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
640  tuner_type == DTVTunerType::kTunerTypeDVBC)
641  {
642  cmdseq->props[c].cmd = DTV_SYMBOL_RATE;
643  cmdseq->props[c++].u.data = tuning.symbolrate;
644  }
645 
646  if (tuner_type.IsFECVariable())
647  {
648  cmdseq->props[c].cmd = DTV_INNER_FEC;
649  cmdseq->props[c++].u.data = can_fec_auto ? FEC_AUTO
650  : (fe_code_rate_t) (int) tuning.fec;
651  }
652 
653  if (tuner_type == DTVTunerType::kTunerTypeDVBT ||
654  tuner_type == DTVTunerType::kTunerTypeDVBT2)
655  {
656  cmdseq->props[c].cmd = DTV_BANDWIDTH_HZ;
657  cmdseq->props[c++].u.data = (8-tuning.bandwidth) * 1000000;
658  cmdseq->props[c].cmd = DTV_CODE_RATE_HP;
659  cmdseq->props[c++].u.data = tuning.hp_code_rate;
660  cmdseq->props[c].cmd = DTV_CODE_RATE_LP;
661  cmdseq->props[c++].u.data = tuning.lp_code_rate;
662  cmdseq->props[c].cmd = DTV_TRANSMISSION_MODE;
663  cmdseq->props[c++].u.data = tuning.trans_mode;
664  cmdseq->props[c].cmd = DTV_GUARD_INTERVAL;
665  cmdseq->props[c++].u.data = tuning.guard_interval;
666  cmdseq->props[c].cmd = DTV_HIERARCHY;
667  cmdseq->props[c++].u.data = tuning.hierarchy;
668  }
669 
671  {
672  cmdseq->props[c].cmd = DTV_PILOT;
673  cmdseq->props[c++].u.data = PILOT_AUTO;
674  cmdseq->props[c].cmd = DTV_ROLLOFF;
675  cmdseq->props[c++].u.data = tuning.rolloff;
676  }
678  {
679  cmdseq->props[c].cmd = DTV_ROLLOFF;
680  cmdseq->props[c++].u.data = DTVRollOff::kRollOff_35;
681  }
682 
683  if (do_tune)
684  cmdseq->props[c++].cmd = DTV_TUNE;
685 
686  cmdseq->num = c;
687 
688  return cmdseq;
689 }
690 #endif
691 
692 
693 /*****************************************************************************
694  Tuning functions for each of the five types of cards.
695  *****************************************************************************/
696 
708 bool DVBChannel::Tune(const DTVMultiplex &tuning,
709  bool force_reset,
710  bool same_input)
711 {
712  QMutexLocker lock(&tune_lock);
713  QMutexLocker locker(&hw_lock);
714 
715  DVBChannel *master = GetMasterLock();
716  if (master != this)
717  {
718  LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel");
719  SetSIStandard(tuning.sistandard);
720  bool ok = master->Tune(tuning, force_reset, false);
721  ReturnMasterLock(master);
722  return ok;
723  }
724  ReturnMasterLock(master); // if we're the master we don't need this lock..
725 
726 
727  int intermediate_freq = 0;
728  bool can_fec_auto = false;
729  bool reset = (force_reset || first_tune);
730 
732  {
733  LOG(VB_GENERAL, LOG_ERR, LOC +
734  "DVB-S needs device tree for LNB handling");
735  return false;
736  }
737 
738  desired_tuning = tuning;
739 
740  if (fd_frontend < 0)
741  {
742  LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!");
743 
744  return false;
745  }
746 
747  // Remove any events in queue before tuning.
749 
750  LOG(VB_CHANNEL, LOG_INFO, LOC + "\nOld Params: " + prev_tuning.toString() +
751  "\nNew Params: " + tuning.toString());
752 
753  // DVB-S is in kHz, other DVB is in Hz
754  bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tunerType) ||
756  int freq_mult = (is_dvbs) ? 1 : 1000;
757  QString suffix = (is_dvbs) ? "kHz" : "Hz";
758 
759  if (reset || !prev_tuning.IsEqual(tunerType, tuning, 500 * freq_mult))
760  {
761  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2")
762  .arg(intermediate_freq ? intermediate_freq : tuning.frequency)
763  .arg(suffix));
764 
765  tune_delay_lock.lock();
766 
767  if (QDateTime::currentDateTime() < last_tuning)
768  {
769  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Next tuning after less than %1ms. Delaying by %1ms")
771  usleep(concurrent_tunings_delay * 1000);
772  }
773 
774  last_tuning = QDateTime::currentDateTime();
776 
777  tune_delay_lock.unlock();
778 
779  // send DVB-S setup
780  if (diseqc_tree)
781  {
782  // configure for new input
783  if (!same_input)
785 
786  // execute diseqc commands
787  if (!diseqc_tree->Execute(diseqc_settings, tuning))
788  {
789  LOG(VB_GENERAL, LOG_ERR, LOC +
790  "Tune(): Failed to setup DiSEqC devices");
791  return false;
792  }
793 
794  // retrieve actual intermediate frequency
796  if (!lnb)
797  {
798  LOG(VB_GENERAL, LOG_ERR, LOC +
799  "Tune(): No LNB for this configuration");
800  return false;
801  }
802 
803  if (lnb->GetDeviceID() != last_lnb_dev_id)
804  {
805  last_lnb_dev_id = lnb->GetDeviceID();
806  // make sure we tune to frequency, if the lnb has changed
807  first_tune = true;
808  }
809 
810  intermediate_freq = lnb->GetIntermediateFrequency(
811  diseqc_settings, tuning);
812 
813  // retrieve scr intermediate frequency
815  if (lnb && scr)
816  {
817  intermediate_freq = scr->GetIntermediateFrequency(intermediate_freq);
818  }
819 
820  // if card can auto-FEC, use it -- sometimes NITs are inaccurate
821  if (capabilities & FE_CAN_FEC_AUTO)
822  can_fec_auto = true;
823 
824  // Check DVB-S intermediate frequency here since it requires a fully
825  // initialized diseqc tree
826  CheckFrequency(intermediate_freq);
827  }
828 
829 #if DVB_API_VERSION >=5
832  {
833  struct dtv_property p_clear;
834  struct dtv_properties cmdseq_clear;
835 
836  p_clear.cmd = DTV_CLEAR;
837  cmdseq_clear.num = 1;
838  cmdseq_clear.props = &p_clear;
839 
840  if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0)
841  {
842  LOG(VB_GENERAL, LOG_ERR, LOC +
843  "Tune(): Clearing DTV properties cache failed." + ENO);
844  return false;
845  }
846 
847  struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties(
848  tunerType, tuning, intermediate_freq, can_fec_auto);
849 
850  if (!cmds) {
851  LOG(VB_GENERAL, LOG_ERR, LOC +
852  "Failed to convert DTVMultiplex to DTV_PROPERTY sequence");
853  return false;
854  }
855 
856  if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG))
857  {
858  for (uint i = 0; i < cmds->num; i++)
859  {
860  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
861  QString("prop %1: cmd = %2, data %3")
862  .arg(i).arg(cmds->props[i].cmd)
863  .arg(cmds->props[i].u.data));
864  }
865  }
866 
867  int res = ioctl(fd_frontend, FE_SET_PROPERTY, cmds);
868 
869  free(cmds->props);
870  free(cmds);
871 
872  if (res < 0)
873  {
874  LOG(VB_GENERAL, LOG_ERR, LOC +
875  "Tune(): Setting Frontend tuning parameters failed." + ENO);
876  return false;
877  }
878  }
879  else
880 #endif
881  {
882  struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams(
883  tunerType, tuning, intermediate_freq, can_fec_auto);
884 
885  if (ioctl(fd_frontend, FE_SET_FRONTEND, &params) < 0)
886  {
887  LOG(VB_GENERAL, LOG_ERR, LOC +
888  "Tune(): Setting Frontend tuning parameters failed." + ENO);
889  return false;
890  }
891  }
892 
893  // Extra delay to add for broken DVB drivers
894  if (tuning_delay)
895  usleep(tuning_delay * 1000);
896 
897  wait_for_backend(fd_frontend, 50 /* msec */);
898 
899  prev_tuning = tuning;
900  first_tune = false;
901  }
902 
903  SetSIStandard(tuning.sistandard);
904 
905  LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful.");
906 
907  return true;
908 }
909 
911 {
912  return Tune(desired_tuning, true, true);
913 }
914 
919 {
920  QMutexLocker locker(&hw_lock);
921 
922  if (fd_frontend < 0)
923  {
924  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
925 
926  return false;
927  }
928 
929  const DVBChannel *master = GetMasterLock();
930  if (master != this)
931  {
932  bool ok = master->IsTuningParamsProbeSupported();
933  ReturnMasterLock(master);
934  return ok;
935  }
936  ReturnMasterLock(master); // if we're the master we don't need this lock..
937 
938  if (diseqc_tree)
939  {
940  // TODO We need to implement the inverse of
941  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
942  // to accurately reflect the frequency before LNB transform.
943  return false;
944  }
945 
946  dvb_frontend_parameters params;
947 
948  int res = ioctl(fd_frontend, FE_GET_FRONTEND, &params);
949  if (res < 0)
950  {
951  LOG(VB_CHANNEL, LOG_ERR, LOC + "Getting device frontend failed." + ENO);
952  }
953 
954  return (res >= 0);
955 }
956 
965 {
966  QMutexLocker locker(&hw_lock);
967 
968  if (fd_frontend < 0)
969  {
970  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
971 
972  return false;
973  }
974 
975  const DVBChannel *master = GetMasterLock();
976  if (master != this)
977  {
978  bool ok = master->ProbeTuningParams(tuning);
979  ReturnMasterLock(master);
980  return ok;
981  }
982  ReturnMasterLock(master); // if we're the master we don't need this lock..
983 
984  if (diseqc_tree)
985  {
986  // TODO We need to implement the inverse of
987  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
988  // to accurately reflect the frequency before LNB transform.
989  return false;
990  }
991 
993  {
994  // TODO implement probing of tuning parameters with FE_GET_PROPERTY
995  return false;
996  }
997 
998  dvb_frontend_parameters params;
999  if (ioctl(fd_frontend, FE_GET_FRONTEND, &params) < 0)
1000  {
1001  LOG(VB_GENERAL, LOG_ERR, LOC +
1002  "Getting Frontend tuning parameters failed." + ENO);
1003 
1004  return false;
1005  }
1006 
1007  uint mplex = tuning.mplex;
1008  QString sistandard = tuning.sistandard;
1009 
1010  tuning = dvbparams_to_dtvmultiplex(tunerType, params);
1011 
1012  tuning.mplex = mplex;
1013  tuning.sistandard = sistandard;
1014 
1015  return true;
1016 }
1017 
1023 {
1024  int found = 0;
1025  int id = -1;
1026  MSqlQuery query(MSqlQuery::InitCon());
1027 
1028  query.prepare("SELECT chanid,visible "
1029  "FROM channel, capturecard "
1030  "WHERE capturecard.sourceid = channel.sourceid AND "
1031  " channel.channum = :CHANNUM AND "
1032  " capturecard.cardid = :INPUTID");
1033 
1034  query.bindValue(":CHANNUM", m_curchannelname);
1035  query.bindValue(":INPUTID", m_inputid);
1036 
1037  if (!query.exec() || !query.isActive())
1038  {
1039  MythDB::DBError("fetching chanid", query);
1040  return -1;
1041  }
1042 
1043  while (query.next())
1044  {
1045  found += query.value(1).toInt();
1046  if (id == -1 || found)
1047  id = query.value(0).toInt();
1048  }
1049 
1050  if (!found)
1051  {
1052  LOG(VB_GENERAL, LOG_INFO,
1053  QString("No visible channel ids for %1")
1054  .arg(m_curchannelname));
1055  }
1056 
1057  if (found > 1)
1058  {
1059  LOG(VB_GENERAL, LOG_WARNING,
1060  QString("Found multiple visible channel ids for %1")
1061  .arg(m_curchannelname));
1062  }
1063 
1064  return id;
1065 }
1066 
1068 {
1069  if (diseqc_tree)
1071 
1072  return nullptr;
1073 }
1074 
1075 // documented in dvbchannel.h
1076 bool DVBChannel::HasLock(bool *ok) const
1077 {
1078  const DVBChannel *master = GetMasterLock();
1079  if (master != this)
1080  {
1081  bool haslock = master->HasLock(ok);
1082  ReturnMasterLock(master);
1083  return haslock;
1084  }
1085  ReturnMasterLock(master); // if we're the master we don't need this lock..
1086 
1087  fe_status_t status;
1088  memset(&status, 0, sizeof(status));
1089 
1090  int ret = ioctl(fd_frontend, FE_READ_STATUS, &status);
1091  if (ret < 0)
1092  {
1093  LOG(VB_GENERAL, LOG_ERR, LOC +
1094  "Getting Frontend status failed." + ENO);
1095  }
1096 
1097  if (ok)
1098  *ok = (0 == ret);
1099 
1100  return status & FE_HAS_LOCK;
1101 }
1102 
1103 #if DVB_API_VERSION >=5
1104 // documented in dvbchannel.h
1105 double DVBChannel::GetSignalStrengthDVBv5(bool *ok) const
1106 {
1107  struct dtv_property prop;
1108  struct dtv_properties cmd;
1109 
1110  memset(&prop, 0, sizeof(prop));
1111  prop.cmd = DTV_STAT_SIGNAL_STRENGTH;
1112  cmd.num = 1;
1113  cmd.props = &prop;
1114  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
1115  LOG(VB_RECORD, LOG_DEBUG, LOC +
1116  QString("FE DTV signal strength ret=%1 res=%2 len=%3 scale=%4 val=%5")
1117  .arg(ret)
1118  .arg(cmd.props->result)
1119  .arg(cmd.props->u.st.len)
1120  .arg(cmd.props->u.st.stat[0].scale)
1121  .arg(cmd.props->u.st.stat[0].svalue)
1122  );
1123  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1124  if (ok)
1125  *ok = tmpOk;
1126  double value = 0;
1127  if (tmpOk)
1128  {
1129  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1130  {
1131  // -20dB is a great signal so make that 100%
1132  // svalue is in 0.001 dB
1133  value = cmd.props->u.st.stat[0].svalue + 100000.0;
1134  // convert 0.001 dB -100dB to 0dB to a 0-1 range
1135  value = value / 100000.0;
1136  if (value > 1.0)
1137  value = 1.0;
1138  else if (value < 0)
1139  value = 0.0;
1140  }
1141  else
1142  {
1143  // returned as 16 bit unsigned
1144  value = cmd.props->u.st.stat[0].svalue / 65535.0;
1145  }
1146  }
1147  else
1148  {
1149  LOG(VB_RECORD, LOG_ERR, LOC +
1150  "Getting V5 Frontend signal strength failed." + ENO);
1151  }
1152  return value;
1153 }
1154 #endif
1155 
1156 // documented in dvbchannel.h
1157 double DVBChannel::GetSignalStrength(bool *ok) const
1158 {
1159  const DVBChannel *master = GetMasterLock();
1160  if (master != this)
1161  {
1162  double val = master->GetSignalStrength(ok);
1163  ReturnMasterLock(master);
1164  return val;
1165  }
1166  ReturnMasterLock(master); // if we're the master we don't need this lock..
1167 
1168  // We use uint16_t for sig because this is correct for DVB API 4.0,
1169  // and works better than the correct int16_t for the 3.x API
1170  uint16_t sig = 0;
1171 
1172  int ret = ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig);
1173  if (ret < 0)
1174  {
1175 #if DVB_API_VERSION >=5
1176  if (errno == EOPNOTSUPP)
1177  {
1178  return GetSignalStrengthDVBv5(ok);
1179  }
1180 #endif
1181  LOG(VB_RECORD, LOG_ERR, LOC +
1182  "Getting Frontend signal strength failed." + ENO);
1183  }
1184 
1185  if (ok)
1186  *ok = (0 == ret);
1187 
1188  return sig * (1.0 / 65535.0);
1189 }
1190 
1191 #if DVB_API_VERSION >=5
1192 // documented in dvbchannel.h
1193 double DVBChannel::GetSNRDVBv5(bool *ok) const
1194 {
1195  struct dtv_property prop;
1196  struct dtv_properties cmd;
1197 
1198  memset(&prop, 0, sizeof(prop));
1199  prop.cmd = DTV_STAT_CNR;
1200  cmd.num = 1;
1201  cmd.props = &prop;
1202  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
1203  LOG(VB_RECORD, LOG_DEBUG, LOC +
1204  QString("FE DTV cnr ret=%1 res=%2 len=%3 scale=%4 val=%5")
1205  .arg(ret)
1206  .arg(cmd.props->result)
1207  .arg(cmd.props->u.st.len)
1208  .arg(cmd.props->u.st.stat[0].scale)
1209  .arg(cmd.props->u.st.stat[0].svalue)
1210  );
1211  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1212  if (ok)
1213  *ok = tmpOk;
1214  double value = 0;
1215  if (tmpOk)
1216  {
1217  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1218  {
1219  // svalue is in 0.001 dB
1220  value = cmd.props->u.st.stat[0].svalue;
1221  // let 50dB+ CNR be 100% quality and 0dB be 0%
1222  // convert 0.001 dB from 0-50000 to a 0-1 range
1223  value = value / 50000.0;
1224  if (value > 1.0)
1225  value = 1.0;
1226  else if (value < 0)
1227  value = 0.0;
1228  }
1229  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1230  {
1231  // returned as 16 bit unsigned
1232  value = cmd.props->u.st.stat[0].svalue / 65535.0;
1233  }
1234  }
1235  else
1236  {
1237  LOG(VB_GENERAL, LOG_ERR, LOC +
1238  "Getting V5 Frontend signal/noise ratio failed." + ENO);
1239  }
1240  return value;
1241 }
1242 #endif
1243 
1244 // documented in dvbchannel.h
1245 double DVBChannel::GetSNR(bool *ok) const
1246 {
1247  const DVBChannel *master = GetMasterLock();
1248  if (master != this)
1249  {
1250  double val = master->GetSNR(ok);
1251  ReturnMasterLock(master);
1252  return val;
1253  }
1254  ReturnMasterLock(master); // if we're the master we don't need this lock..
1255 
1256  // We use uint16_t for sig because this is correct for DVB API 4.0,
1257  // and works better than the correct int16_t for the 3.x API
1258 
1259  uint16_t snr = 0;
1260  int ret = ioctl(fd_frontend, FE_READ_SNR, &snr);
1261  if (ret < 0)
1262  {
1263 #if DVB_API_VERSION >=5
1264  if (errno == EOPNOTSUPP)
1265  {
1266  return GetSNRDVBv5(ok);
1267  }
1268 #endif
1269  LOG(VB_GENERAL, LOG_ERR, LOC +
1270  "Getting Frontend signal/noise ratio failed." + ENO);
1271  }
1272 
1273  if (ok)
1274  *ok = (0 == ret);
1275 
1276  return snr * (1.0 / 65535.0);
1277 }
1278 
1279 #if DVB_API_VERSION >=5
1280 // documented in dvbchannel.h
1281 double DVBChannel::GetBitErrorRateDVBv5(bool *ok) const
1282 {
1283  struct dtv_property prop[2];
1284  struct dtv_properties cmd;
1285 
1286  memset(&prop, 0, sizeof(prop));
1287  prop[0].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
1288  prop[1].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
1289  cmd.num = 2;
1290  cmd.props = prop;
1291  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
1292  bool tmpOk = (ret == 0) &&
1293  (cmd.props[0].u.st.len > 0) &&
1294  (cmd.props[1].u.st.len > 0);
1295  if (ok)
1296  *ok = tmpOk;
1297  double value = 0;
1298  if (tmpOk)
1299  {
1300  if ((cmd.props[0].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1301  (cmd.props[1].u.st.stat[1].scale == FE_SCALE_COUNTER) &&
1302  (cmd.props[1].u.st.stat[0].uvalue != 0))
1303  {
1304  value = static_cast<double>(
1305  static_cast<long double>(cmd.props[0].u.st.stat[0].uvalue) /
1306  cmd.props[1].u.st.stat[0].uvalue);
1307  }
1308  }
1309  else
1310  {
1311  LOG(VB_GENERAL, LOG_ERR, LOC +
1312  "Getting V5 Frontend signal error rate failed." + ENO);
1313  }
1314  return value;
1315 }
1316 #endif
1317 
1318 // documented in dvbchannel.h
1319 double DVBChannel::GetBitErrorRate(bool *ok) const
1320 {
1321  const DVBChannel *master = GetMasterLock();
1322  if (master != this)
1323  {
1324  double val = master->GetBitErrorRate(ok);
1325  ReturnMasterLock(master);
1326  return val;
1327  }
1328  ReturnMasterLock(master); // if we're the master we don't need this lock..
1329 
1330  uint32_t ber = 0;
1331  int ret = ioctl(fd_frontend, FE_READ_BER, &ber);
1332  if (ret < 0)
1333  {
1334 #if DVB_API_VERSION >=5
1335  if (errno == EOPNOTSUPP)
1336  {
1337  return GetBitErrorRateDVBv5(ok);
1338  }
1339 #endif
1340  LOG(VB_GENERAL, LOG_ERR, LOC +
1341  "Getting Frontend signal error rate failed." + ENO);
1342  }
1343 
1344  if (ok)
1345  *ok = (0 == ret);
1346 
1347  return (double) ber;
1348 }
1349 
1350 #if DVB_API_VERSION >=5
1351 // documented in dvbchannel.h
1352 double DVBChannel::GetUncorrectedBlockCountDVBv5(bool *ok) const
1353 {
1354  struct dtv_property prop;
1355  struct dtv_properties cmd;
1356 
1357  memset(&prop, 0, sizeof(prop));
1358  prop.cmd = DTV_STAT_ERROR_BLOCK_COUNT;
1359  cmd.num = 1;
1360  cmd.props = &prop;
1361  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
1362  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1363  if (ok)
1364  *ok = tmpOk;
1365  double value = 0;
1366  if (tmpOk)
1367  {
1368  if (cmd.props->u.st.stat[0].scale == FE_SCALE_COUNTER)
1369  value = cmd.props->u.st.stat[0].svalue;
1370  else
1371  value = 0;
1372  }
1373  else
1374  {
1375  LOG(VB_GENERAL, LOG_ERR, LOC +
1376  "Getting V5 Frontend uncorrected block count failed." + ENO);
1377  }
1378  return value;
1379 }
1380 #endif
1381 
1382 // documented in dvbchannel.h
1384 {
1385  const DVBChannel *master = GetMasterLock();
1386  if (master != this)
1387  {
1388  double val = master->GetUncorrectedBlockCount(ok);
1389  ReturnMasterLock(master);
1390  return val;
1391  }
1392  ReturnMasterLock(master); // if we're the master we don't need this lock..
1393 
1394  uint32_t ublocks = 0;
1395  int ret = ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
1396  if (ret < 0)
1397  {
1398 #if DVB_API_VERSION >=5
1399  if (errno == EOPNOTSUPP)
1400  {
1401  return GetUncorrectedBlockCountDVBv5(ok);
1402  }
1403 #endif
1404  LOG(VB_GENERAL, LOG_ERR, LOC +
1405  "Getting Frontend uncorrected block count failed." + ENO);
1406  }
1407 
1408  if (ok)
1409  *ok = (0 == ret);
1410 
1411  return (double) ublocks;
1412 }
1413 
1415 {
1417  if (m_pParent)
1418  key += QString(":%1")
1420  DTVChannel *master = DTVChannel::GetMasterLock(key);
1421  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1422  if (master && !dvbm)
1424  return dvbm;
1425 }
1426 
1428 {
1429  DTVChannel *chan = static_cast<DTVChannel*>(dvbm);
1431  dvbm = nullptr;
1432 }
1433 
1435 {
1437  if (m_pParent)
1438  key += QString(":%1")
1440  DTVChannel *master = DTVChannel::GetMasterLock(key);
1441  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1442  if (master && !dvbm)
1444  return dvbm;
1445 }
1446 
1447 void DVBChannel::ReturnMasterLock(DVBChannelCP &dvbm)
1448 {
1449  DTVChannel *chan =
1450  static_cast<DTVChannel*>(const_cast<DVBChannel*>(dvbm));
1452  dvbm = nullptr;
1453 }
1454 
1455 bool DVBChannel::IsMaster(void) const
1456 {
1457  const DVBChannel *master = GetMasterLock();
1458  bool is_master = (master == this);
1459  ReturnMasterLock(master);
1460  return is_master;
1461 }
1462 
1467 static void drain_dvb_events(int fd)
1468 {
1469  struct dvb_frontend_event event;
1470  int ret = 0;
1471  while ((ret = ioctl(fd, FE_GET_EVENT, &event)) == 0);
1472  if (ret < 0)
1473  {
1474  LOG(VB_CHANNEL, LOG_DEBUG, "Draining DVB Event failed. " + ENO);
1475  }
1476 }
1477 
1501 static bool wait_for_backend(int fd, int timeout_ms)
1502 {
1503  struct timeval select_timeout = { 0, (timeout_ms % 1000) * 1000 /*usec*/};
1504  fd_set fd_select_set;
1505  FD_ZERO( &fd_select_set);
1506  FD_SET (fd, &fd_select_set);
1507 
1508  // Try to wait for some output like an event, unfortunately
1509  // this fails on several DVB cards, so we have a timeout.
1510  int ret = 0;
1511  do ret = select(fd+1, &fd_select_set, nullptr, nullptr, &select_timeout);
1512  while ((-1 == ret) && (EINTR == errno));
1513 
1514  if (-1 == ret)
1515  {
1516  LOG(VB_GENERAL, LOG_ERR,
1517  "DVBChan: wait_for_backend: Failed to wait on output" + ENO);
1518 
1519  return false;
1520  }
1521 
1522  // This is supposed to work on all cards, post 2.6.12...
1523  fe_status_t status;
1524  if (ioctl(fd, FE_READ_STATUS, &status) < 0)
1525  {
1526  LOG(VB_GENERAL, LOG_ERR,
1527  "DVBChan: wait_for_backend: Failed to get status" + ENO);
1528 
1529  return false;
1530  }
1531 
1532  LOG(VB_CHANNEL, LOG_INFO, QString("DVBChan: wait_for_backend: Status: %1")
1533  .arg(toString(status)));
1534 
1535  return true;
1536 }
1537 
1538 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
1539  DTVTunerType tuner_type, const DTVMultiplex &tuning,
1540  int intermediate_freq, bool can_fec_auto)
1541 {
1542  dvb_frontend_parameters params;
1543  memset(&params, 0, sizeof(params));
1544 
1545  params.frequency = tuning.frequency;
1546  params.inversion = (fe_spectral_inversion_t) (int) tuning.inversion;
1547 
1548  if (DTVTunerType::kTunerTypeDVBS1 == tuner_type)
1549  {
1550  if (tuning.mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
1551  LOG(VB_GENERAL, LOG_ERR,
1552  "DVBChan: Error, Tuning of a DVB-S2 transport "
1553  "with a DVB-S card will fail.");
1554 
1555  params.frequency = intermediate_freq;
1556  params.u.qpsk.symbol_rate = tuning.symbolrate;
1557  params.u.qpsk.fec_inner = can_fec_auto ? FEC_AUTO
1558  : (fe_code_rate_t) (int) tuning.fec;
1559  }
1560 
1561  if (DTVTunerType::kTunerTypeDVBS2 == tuner_type)
1562  {
1563  LOG(VB_GENERAL, LOG_ERR,
1564  "DVBChan: Error, MythTV was compiled without "
1565  "DVB-S2 headers being present so DVB-S2 tuning will fail.");
1566  }
1567 
1568  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1569  {
1570  params.u.qam.symbol_rate = tuning.symbolrate;
1571  params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.fec;
1572  params.u.qam.modulation = (fe_modulation_t) (int) tuning.modulation;
1573  }
1574 
1575  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1576  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1577  {
1578  params.u.ofdm.bandwidth =
1579  (fe_bandwidth_t) (int) tuning.bandwidth;
1580  params.u.ofdm.code_rate_HP =
1581  (fe_code_rate_t) (int) tuning.hp_code_rate;
1582  params.u.ofdm.code_rate_LP =
1583  (fe_code_rate_t) (int) tuning.lp_code_rate;
1584  params.u.ofdm.constellation =
1585  (fe_modulation_t) (int) tuning.modulation;
1586  params.u.ofdm.transmission_mode =
1587  (fe_transmit_mode_t) (int) tuning.trans_mode;
1588  params.u.ofdm.guard_interval =
1589  (fe_guard_interval_t) (int) tuning.guard_interval;
1590  params.u.ofdm.hierarchy_information =
1591  (fe_hierarchy_t) (int) tuning.hierarchy;
1592  }
1593 
1594  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1595  {
1596  params.u.vsb.modulation =
1597  (fe_modulation_t) (int) tuning.modulation;
1598  }
1599 
1600  return params;
1601 }
1602 
1604  DTVTunerType tuner_type, const dvb_frontend_parameters &params)
1605 {
1606  DTVMultiplex tuning;
1607 
1608  tuning.frequency = params.frequency;
1609  tuning.inversion = params.inversion;
1610 
1611  if ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
1612  (DTVTunerType::kTunerTypeDVBS2 == tuner_type))
1613  {
1614  tuning.symbolrate = params.u.qpsk.symbol_rate;
1615  tuning.fec = params.u.qpsk.fec_inner;
1616  }
1617 
1618  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1619  {
1620  tuning.symbolrate = params.u.qam.symbol_rate;
1621  tuning.fec = params.u.qam.fec_inner;
1622  tuning.modulation = params.u.qam.modulation;
1623  }
1624 
1625  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1626  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1627  {
1628  tuning.bandwidth = params.u.ofdm.bandwidth;
1629  tuning.hp_code_rate = params.u.ofdm.code_rate_HP;
1630  tuning.lp_code_rate = params.u.ofdm.code_rate_LP;
1631  tuning.modulation = params.u.ofdm.constellation;
1632  tuning.trans_mode = params.u.ofdm.transmission_mode;
1633  tuning.guard_interval = params.u.ofdm.guard_interval;
1634  tuning.hierarchy = params.u.ofdm.hierarchy_information;
1635  }
1636 
1637  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1638  {
1639  tuning.modulation = params.u.vsb.modulation;
1640  }
1641 
1642  return tuning;
1643 }
double GetSignalStrength(bool *ok=nullptr) const
Returns signal strength in the range [0.0..1.0] (non-calibrated).
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
double GetBitErrorRate(bool *ok=nullptr) const
Returns # of corrected bits since last call. First call undefined.
void Open(int fd_frontend, bool is_SCR)
Retrieve device tree.
Definition: diseqc.cpp:807
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn't fix the CRC.
Definition: cardutil.cpp:709
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
bool IsMaster(void) const override
Returns true if this is the first of a number of multi-rec devs.
uint GetInputId(void)
Returns the inputid.
Definition: tv_rec.h:241
DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:245
static const int kTunerTypeDVBT
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
uint GetDeviceID(void) const
Definition: diseqc.h:162
#define O_NONBLOCK
Definition: mythmedia.cpp:25
int GetChanID(void) const override
Returns Channel ID.
IsOpenMap is_open
Definition: dvbchannel.h:133
TVRec * m_pParent
Definition: channelbase.h:134
void CheckFrequency(uint64_t frequency) const
Checks tuning frequency.
Definition: dvbchannel.cpp:395
QString toString(MarkTypes type)
static const int kTunerTypeATSC
static DTVMultiplex dvbparams_to_dtvmultiplex(DTVTunerType, const dvb_frontend_parameters &)
DiSEqCDevLNB * FindLNB(const DiSEqCDevSettings &settings)
Returns the LNB device object selected by the configuration chain.
Definition: diseqc.cpp:585
bool IsRunning(void) const
Definition: dvbcam.h:31
uint64_t capabilities
Definition: dvbchannel.h:143
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
double GetSignalStrengthDVBv5(bool *ok) const
Get Signal strength from the DVBv5 interface [0-1.0] It is transformed to a linear relative scale if ...
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:65
void SetPMT(const ProgramMapTable *)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:557
DiSEqCDevSettings diseqc_settings
Definition: dvbchannel.h:137
DTVCodeRate hp_code_rate
High Priority FEC rate.
Definition: dtvmultiplex.h:88
static QReadWriteLock master_map_lock
Definition: dtvchannel.h:179
unsigned int uint
Definition: compat.h:140
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:29
int64_t concurrent_tunings_delay
Definition: dvbchannel.cpp:59
double GetUncorrectedBlockCountDVBv5(bool *ok) const
Get Uncorrected Block Count from the DVBv5 interface.
bool Start(void)
Definition: dvbcam.cpp:90
DiSEqCDev diseqc_dev
Definition: dvbchannel.h:136
uint m_inputid
Definition: channelbase.h:137
DTVRollOff rolloff
Definition: dtvmultiplex.h:97
uint32_t GetIntermediateFrequency(const uint32_t frequency) const
Definition: diseqc.cpp:2304
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
DTVModulation modulation
Definition: dtvmultiplex.h:90
static const int kTunerTypeDVBS1
QString toString() const
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:135
DiSEqCDevTree * diseqc_tree
Definition: dvbchannel.h:138
DTVTunerType tunerType
Definition: dtvchannel.h:163
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
uint tuning_delay
Extra delay to add for broken drivers.
Definition: dvbchannel.h:160
uint last_lnb_dev_id
Definition: dvbchannel.h:158
bool Stop(void)
Definition: dvbcam.cpp:122
DTVGuardInterval guard_interval
Definition: dtvmultiplex.h:92
bool Retune(void) override
Definition: dvbchannel.cpp:910
int fd_frontend
File descriptor for tuning hardware.
Definition: dvbchannel.h:165
QString sistandard
Definition: dtvmultiplex.h:101
QVariant value(int i) const
Definition: mythdbcon.h:182
QMutex tune_delay_lock
Definition: dvbchannel.h:170
DiSEqCDevRotor * FindRotor(const DiSEqCDevSettings &settings, uint index=0)
Returns the nth rotor device object in the tree.
Definition: diseqc.cpp:562
void SetTimeOffset(double offset)
Tells the Conditional Access Module the offset from the computers utc time to dvb time.
Definition: dvbchannel.cpp:569
Definition: dvbcam.h:23
bool IsFECVariable(void) const
double GetUncorrectedBlockCount(bool *ok=nullptr) const
Returns # of uncorrected blocks since last call. First call undefined.
bool Open(void) override
Opens the channel changing hardware for use.
Definition: dvbchannel.h:35
QString m_curchannelname
Definition: channelbase.h:135
static const int kTunerTypeDVBS2
static void ReturnMasterLock(DVBChannelP &dvbm)
double GetSNRDVBv5(bool *ok) const
Get SNR from the DVBv5 interface [0-1.0] It is transformed to a linear relative scale if provided in ...
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
static const int kTunerTypeDVBT2
DTVBandwidth bandwidth
Definition: dtvmultiplex.h:87
bool IsEqual(DTVTunerType type, const DTVMultiplex &other, uint freq_range=0, bool fuzzy=false) const
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:34
static const int kTunerTypeDVBC
bool HasLock(bool *ok=nullptr) const
Returns true iff we have a signal carrier lock.
DTVCodeRate lp_code_rate
Low Priority FEC rate.
Definition: dtvmultiplex.h:89
#define close
Definition: compat.h:16
uint sigmon_delay
Minimum delay between FE_LOCK checks.
Definition: dvbchannel.h:161
uint64_t frequency
Definition: dtvmultiplex.h:84
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:150
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:24
QMutex hw_lock
Definition: dvbchannel.h:152
DiSEqCDevSCR * FindSCR(const DiSEqCDevSettings &settings)
Returns the SCR device object selected by the configuration chain.
Definition: diseqc.cpp:608
static MasterMap master_map
Definition: dtvchannel.h:180
static DTVChannel * GetMasterLock(const QString &key)
Definition: dtvchannel.cpp:146
bool isActive(void) const
Definition: mythdbcon.h:188
Rotor class.
Definition: diseqc.h:292
bool ProbeTuningParams(DTVMultiplex &tuning) const
Fetches DTVMultiplex params from driver.
Definition: dvbchannel.cpp:964
static void drain_dvb_events(int fd)
Reads all the events off the queue, so we can use select in wait_for_backend(int,int).
uint symbol_rate_maximum
Definition: dvbchannel.h:148
unsigned short uint16_t
Definition: iso6937tables.h:1
uint32_t GetIntermediateFrequency(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning) const
Calculate proper intermediate frequency for the given settings and tuning parameters.
Definition: diseqc.cpp:2621
void SetTimeOffset(double offset_in_seconds)
Definition: dvbcam.cpp:320
static bool wait_for_backend(int fd, int timeout_ms)
Waits for backend to get tune message.
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
bool IsOpen(void) const override
Reports whether channel is already open.
Definition: dvbchannel.cpp:376
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
DTVCodeRate fec
Inner Forward Error Correction rate.
Definition: dtvmultiplex.h:95
DTVMultiplex prev_tuning
Last tuning options Tune() succesfully sent to hardware.
Definition: dvbchannel.h:156
QMutex tune_lock
Definition: dvbchannel.h:151
uint64_t symbolrate
Definition: dtvmultiplex.h:85
static QDateTime last_tuning
Definition: dvbchannel.h:169
#define LOC
Definition: dvbchannel.cpp:62
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
bool IsDiSEqCSupported(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static int x0
Definition: mythsocket.cpp:59
bool first_tune
Used to force hardware reset.
Definition: dvbchannel.h:162
bool Tune(const DTVMultiplex &tuning) override
This performs the actual frequency tuning and in some cases input switching.
Definition: dvbchannel.cpp:576
bool Execute(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
Applies settings to the entire tree.
Definition: diseqc.cpp:521
QString sistandard
PSIP table standard: MPEG, DVB, ATSC, OpenCable.
Definition: dtvchannel.h:164
void SetSIStandard(const QString &)
Sets PSIP table standard: MPEG, DVB, ATSC, or OpenCable.
Definition: dtvchannel.cpp:61
DTVHierarchy hierarchy
Definition: dtvmultiplex.h:93
double GetSNR(bool *ok=nullptr) const
Returns signal/noise in the range [0..1.0].
QString frontend_name
Definition: dvbchannel.h:142
Unicable / SCR Class.
Definition: diseqc.h:371
DTVInversion inversion
Definition: dtvmultiplex.h:86
bool CheckModulation(DTVModulation modulation) const
Return true iff modulation is supported modulation on the frontend.
Definition: dvbchannel.cpp:532
DTVMultiplex desired_tuning
Last tuning options Tune() attempted to send to hardware.
Definition: dvbchannel.h:154
void Close(void)
Definition: diseqc.h:102
bool Init(QString &startchannel, bool setchan) override
Definition: dvbchannel.cpp:384
DVBChannel * GetMasterLock(void)
LNB Class.
Definition: diseqc.h:435
bool IsTuningParamsProbeSupported(void) const
Returns true iff tuning info probing is working.
Definition: dvbchannel.cpp:918
bool has_crc_bug
true iff our driver munges PMT
Definition: dvbchannel.h:167
void Close(void) override
Closes the channel changing hardware to use.
Definition: dvbchannel.h:37
DVBChannel(const QString &device, TVRec *parent=nullptr)
Definition: dvbchannel.cpp:69
static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(DTVTunerType, const DTVMultiplex &, int intermediate_freq, bool can_fec_auto)
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1276
QString device
DVB Device.
Definition: dvbchannel.h:166
bool CheckCodeRate(DTVCodeRate rate) const
Return true iff rate is supported rate on the frontend.
Definition: dvbchannel.cpp:513
static void ReturnMasterLock(DTVChannelP &)
Definition: dtvchannel.cpp:158
double GetBitErrorRateDVBv5(bool *ok) const
Get Bit Error Rate from the DVBv5 interface.
void CheckOptions(DTVMultiplex &t) const override
Checks tuning for problems, and tries to fix them.
Definition: dvbchannel.cpp:408
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:615
uint64_t frequency_minimum
Definition: dvbchannel.h:145
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
uint64_t frequency_maximum
Definition: dvbchannel.h:146
DTVTransmitMode trans_mode
Definition: dtvmultiplex.h:91
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:656
DVBCam * dvbcam
Used to decrypt encrypted streams.
Definition: dvbchannel.h:139
uint64_t ext_modulations
Definition: dvbchannel.h:144
virtual bool InitializeInput(void)
Fills in input map from DB.
DTVModulationSystem mod_sys
modulation system (only DVB-S or DVB-S2 atm)
Definition: dtvmultiplex.h:96
uint symbol_rate_minimum
Definition: dvbchannel.h:147
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:716
void SetPMT(const ChannelBase *chan, const ProgramMapTable *pmt)
Definition: dvbcam.cpp:287
bool IsModulationVariable(void) const