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 // Returned by drivers on unsupported DVBv3 ioctl calls
53 #ifndef ENOTSUPP
54 #define ENOTSUPP 524
55 #endif
56 
57 // Local functions
58 static void drain_dvb_events(int fd);
59 static bool wait_for_backend(int fd, int timeout_ms);
60 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
61  DTVTunerType /*tuner_type*/, const DTVMultiplex& /*tuning*/, int intermediate_freq, bool can_fec_auto);
63  DTVTunerType /*tuner_type*/, const dvb_frontend_parameters& /*params*/);
64 
65 int64_t concurrent_tunings_delay = 1000;
66 QDateTime DVBChannel::s_last_tuning = QDateTime::currentDateTime();
67 
68 #define LOC QString("DVBChan[%1](%2): ").arg(m_inputid).arg(DVBChannel::GetDevice())
69 
75 DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent)
76  : DTVChannel(parent), m_device(aDevice)
77 {
78  s_master_map_lock.lockForWrite();
80  if (m_pParent)
81  key += QString(":%1")
83  s_master_map[key].push_back(this); // == RegisterForMaster
84  DVBChannel *master = static_cast<DVBChannel*>(s_master_map[key].front());
85  if (master == this)
86  {
87  m_dvbcam = new DVBCam(m_device);
89  }
90  else
91  {
92  m_dvbcam = master->m_dvbcam;
93  m_has_crc_bug = master->m_has_crc_bug;
94  }
95  s_master_map_lock.unlock();
96 
98 }
99 
101 {
102  // set a new master if there are other instances and we're the master
103  // whether we are the master or not remove us from the map..
104  s_master_map_lock.lockForWrite();
106  if (m_pParent)
107  key += QString(":%1")
109  DVBChannel *master = static_cast<DVBChannel*>(s_master_map[key].front());
110  if (master == this)
111  {
112  s_master_map[key].pop_front();
113  DVBChannel *new_master = nullptr;
114  if (!s_master_map[key].empty())
115  new_master = dynamic_cast<DVBChannel*>(s_master_map[key].front());
116  if (new_master)
117  {
118  QMutexLocker master_locker(&(master->m_hw_lock));
119  QMutexLocker new_master_locker(&(new_master->m_hw_lock));
120  new_master->m_is_open = master->m_is_open;
121  }
122  }
123  else
124  {
125  s_master_map[key].removeAll(this);
126  }
127  s_master_map_lock.unlock();
128 
130 
131  // if we're the last one out delete dvbcam
132  s_master_map_lock.lockForRead();
133  MasterMap::iterator mit = s_master_map.find(key);
134  if ((*mit).empty())
135  delete m_dvbcam;
136  m_dvbcam = nullptr;
137  s_master_map_lock.unlock();
138 
139  // diseqc_tree is managed elsewhere
140 }
141 
143 {
144  LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel");
145 
146  QMutexLocker locker(&m_hw_lock);
147 
148  IsOpenMap::iterator it = m_is_open.find(who);
149  if (it == m_is_open.end())
150  return; // this caller didn't have it open in the first place..
151 
152  m_is_open.erase(it);
153 
154  DVBChannel *master = GetMasterLock();
155  if (master != nullptr && master != this)
156  {
157  if (m_dvbcam->IsRunning())
158  m_dvbcam->SetPMT(this, nullptr);
159  master->Close(this);
160  m_fd_frontend = -1;
161  ReturnMasterLock(master);
162  return;
163  }
164  ReturnMasterLock(master); // if we're the master we don't need this lock..
165 
166  if (!m_is_open.empty())
167  return; // not all callers have closed the DVB channel yet..
168 
169  if (m_diseqc_tree)
170  m_diseqc_tree->Close();
171 
172  if (m_fd_frontend >= 0)
173  {
175  m_fd_frontend = -1;
176 
177  m_dvbcam->Stop();
178  }
179 }
180 
182 {
183  LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel");
184 
185  if (!m_inputid)
186  {
187  if (!InitializeInput())
188  return false;
189  }
190 
191  QMutexLocker locker(&m_hw_lock);
192 
193  if (m_fd_frontend >= 0)
194  {
195  m_is_open[who] = true;
196  return true;
197  }
198 
199  DVBChannel *master = GetMasterLock();
200  if (master != this)
201  {
202  if (!master->Open(who))
203  {
204  ReturnMasterLock(master);
205  return false;
206  }
207 
208  m_fd_frontend = master->m_fd_frontend;
210  m_tunerType = master->m_tunerType;
211  m_capabilities = master->m_capabilities;
217 
218  m_is_open[who] = true;
219 
220  if (!InitializeInput())
221  {
222  Close();
223  ReturnMasterLock(master);
224  return false;
225  }
226 
227  ReturnMasterLock(master);
228  return true;
229  }
230  ReturnMasterLock(master); // if we're the master we don't need this lock..
231 
233  QByteArray devn = dvbdev.toLatin1();
234 
235  for (int tries = 1; ; ++tries)
236  {
237  m_fd_frontend = open(devn.constData(), O_RDWR | O_NONBLOCK);
238  if (m_fd_frontend >= 0)
239  break;
240  LOG(VB_GENERAL, LOG_WARNING, LOC +
241  "Opening DVB frontend device failed." + ENO);
242  if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
243  {
244  LOG(VB_GENERAL, LOG_ERR, LOC +
245  QString("Failed to open DVB frontend device due to "
246  "fatal error or too many attempts."));
247  return false;
248  }
249  usleep(50000);
250  }
251 
252  dvb_frontend_info info;
253  memset(&info, 0, sizeof(info));
254  if (ioctl(m_fd_frontend, FE_GET_INFO, &info) < 0)
255  {
256  LOG(VB_GENERAL, LOG_ERR, LOC +
257  "Failed to get frontend information." + ENO);
258 
260  m_fd_frontend = -1;
261  return false;
262  }
263 
264  m_frontend_name = info.name;
265  m_capabilities = info.caps;
266  m_frequency_minimum = info.frequency_min;
267  m_frequency_maximum = info.frequency_max;
268  m_symbol_rate_minimum = info.symbol_rate_min;
269  m_symbol_rate_maximum = info.symbol_rate_max;
270 
273 
274  LOG(VB_RECORD, LOG_INFO, LOC +
275  QString("Frontend '%2' tunertype: %3")
276  .arg(m_frontend_name).arg(m_tunerType.toString()));
277 
278  // Turn on the power to the LNB
280  {
281 
283  if (m_diseqc_tree)
284  {
285  bool is_SCR = false;
286 
288  if (scr)
289  {
290  is_SCR = true;
291  LOG(VB_CHANNEL, LOG_INFO, LOC + "Requested DVB channel is on SCR system");
292  }
293  else
294  LOG(VB_CHANNEL, LOG_INFO, LOC + "Requested DVB channel is on non-SCR system");
295 
296  m_diseqc_tree->Open(m_fd_frontend, is_SCR);
297  }
298  }
299 
300  m_first_tune = true;
301 
302  if (!InitializeInput())
303  {
304  Close();
305  return false;
306  }
307 
308  if (m_fd_frontend >= 0)
309  m_is_open[who] = true;
310 
311  return (m_fd_frontend >= 0);
312 }
313 
314 bool DVBChannel::IsOpen(void) const
315 {
316  // Have to acquire the hw lock to prevent is_open being modified whilst we're searching it
317  QMutexLocker locker(&m_hw_lock);
318  IsOpenMap::const_iterator it = m_is_open.find(this);
319  return it != m_is_open.end();
320 }
321 
322 bool DVBChannel::Init(QString &startchannel, bool setchan)
323 {
324  if (setchan && !IsOpen())
325  Open(this);
326 
327  return ChannelBase::Init(startchannel, setchan);
328 }
329 
333 void DVBChannel::CheckFrequency(uint64_t frequency) const
334 {
337  (frequency < m_frequency_minimum || frequency > m_frequency_maximum))
338  {
339  LOG(VB_GENERAL, LOG_WARNING, LOC +
340  QString("Your frequency setting (%1) is out of range. "
341  "(min/max:%2/%3)")
342  .arg(frequency).arg(m_frequency_minimum).arg(m_frequency_maximum));
343  }
344 }
345 
347 {
348  if ((tuning.m_inversion == DTVInversion::kInversionAuto) &&
349  ((m_capabilities & FE_CAN_INVERSION_AUTO) == 0U))
350  {
351  LOG(VB_GENERAL, LOG_WARNING, LOC +
352  "'Auto' inversion parameter unsupported by this driver, "
353  "falling back to 'off'.");
355  }
356 
357  // DVB-S needs a fully initialized diseqc tree and is checked later in Tune
358  if (!m_diseqc_tree)
359  {
360  const DVBChannel *master = GetMasterLock();
361  if (master == nullptr || !master->m_diseqc_tree)
362  CheckFrequency(tuning.m_frequency);
363  ReturnMasterLock(master);
364  }
365 
366  if (m_tunerType.IsFECVariable() &&
371  {
372  LOG(VB_GENERAL, LOG_WARNING, LOC +
373  QString("Symbol Rate setting (%1) is out of range (min/max:%2/%3)")
374  .arg(tuning.m_symbolrate)
376  }
377 
378  if (m_tunerType.IsFECVariable() && !CheckCodeRate(tuning.m_fec))
379  {
380  LOG(VB_GENERAL, LOG_WARNING, LOC +
381  "Selected fec_inner parameter unsupported by this driver.");
382  }
383 
385  {
386  LOG(VB_GENERAL, LOG_WARNING, LOC +
387  "Selected modulation parameter unsupported by this driver.");
388  }
389 
392  {
393  LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
394  return;
395  }
396 
397  // Check OFDM Tuning params
398 
399  if (!CheckCodeRate(tuning.m_hp_code_rate))
400  {
401  LOG(VB_GENERAL, LOG_WARNING, LOC +
402  "Selected code_rate_hp parameter unsupported by this driver.");
403  }
404 
405  if (!CheckCodeRate(tuning.m_lp_code_rate))
406  {
407  LOG(VB_GENERAL, LOG_WARNING, LOC +
408  "Selected code_rate_lp parameter unsupported by this driver.");
409  }
410 
411  if ((tuning.m_bandwidth == DTVBandwidth::kBandwidthAuto) &&
412  ((m_capabilities & FE_CAN_BANDWIDTH_AUTO) == 0U))
413  {
414  LOG(VB_GENERAL, LOG_WARNING, LOC +
415  "'Auto' bandwidth parameter unsupported by this driver.");
416  }
417 
419  ((m_capabilities & FE_CAN_TRANSMISSION_MODE_AUTO) == 0U))
420  {
421  LOG(VB_GENERAL, LOG_WARNING, LOC +
422  "'Auto' transmission_mode parameter unsupported by this driver.");
423  }
424 
426  ((m_capabilities & FE_CAN_GUARD_INTERVAL_AUTO) == 0U))
427  {
428  LOG(VB_GENERAL, LOG_WARNING, LOC +
429  "'Auto' guard_interval parameter unsupported by this driver.");
430  }
431 
432  if ((tuning.m_hierarchy == DTVHierarchy::kHierarchyAuto) &&
433  ((m_capabilities & FE_CAN_HIERARCHY_AUTO) == 0U))
434  {
435  LOG(VB_GENERAL, LOG_WARNING, LOC +
436  "'Auto' hierarchy parameter unsupported by this driver. ");
437  }
438 
439  if (!CheckModulation(tuning.m_modulation))
440  {
441  LOG(VB_GENERAL, LOG_WARNING, LOC +
442  "Selected modulation parameter unsupported by this driver.");
443  }
444 
445  LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
446 }
447 
452 {
453  const uint64_t caps = m_capabilities;
454  return
455  ((DTVCodeRate::kFECNone == rate)) ||
456  ((DTVCodeRate::kFEC_1_2 == rate) && ((caps & FE_CAN_FEC_1_2) != 0U)) ||
457  ((DTVCodeRate::kFEC_2_3 == rate) && ((caps & FE_CAN_FEC_2_3) != 0U)) ||
458  ((DTVCodeRate::kFEC_3_4 == rate) && ((caps & FE_CAN_FEC_3_4) != 0U)) ||
459  ((DTVCodeRate::kFEC_4_5 == rate) && ((caps & FE_CAN_FEC_4_5) != 0U)) ||
460  ((DTVCodeRate::kFEC_5_6 == rate) && ((caps & FE_CAN_FEC_5_6) != 0U)) ||
461  ((DTVCodeRate::kFEC_6_7 == rate) && ((caps & FE_CAN_FEC_6_7) != 0U)) ||
462  ((DTVCodeRate::kFEC_7_8 == rate) && ((caps & FE_CAN_FEC_7_8) != 0U)) ||
463  ((DTVCodeRate::kFEC_8_9 == rate) && ((caps & FE_CAN_FEC_8_9) != 0U)) ||
464  ((DTVCodeRate::kFECAuto == rate) && ((caps & FE_CAN_FEC_AUTO) != 0U));
465 }
466 
471 {
472  const DTVModulation m = modulation;
473  const uint64_t c = m_capabilities;
474 
475  return
476  ((DTVModulation::kModulationQPSK == m) && ((c & FE_CAN_QPSK) != 0U)) ||
477 #if HAVE_FE_CAN_2G_MODULATION
478  ((DTVModulation::kModulation8PSK == m) && ((c & FE_CAN_2G_MODULATION) != 0U)) ||
479  ((DTVModulation::kModulation16APSK == m) && ((c & FE_CAN_2G_MODULATION) != 0U)) ||
480  ((DTVModulation::kModulation32APSK == m) && ((c & FE_CAN_2G_MODULATION) != 0U)) ||
481 #endif //HAVE_FE_CAN_2G_MODULATION
482  ((DTVModulation::kModulationQAM16 == m) && ((c & FE_CAN_QAM_16) != 0U)) ||
483  ((DTVModulation::kModulationQAM32 == m) && ((c & FE_CAN_QAM_32) != 0U)) ||
484  ((DTVModulation::kModulationQAM64 == m) && ((c & FE_CAN_QAM_64) != 0U)) ||
485  ((DTVModulation::kModulationQAM128 == m) && ((c & FE_CAN_QAM_128) != 0U)) ||
486  ((DTVModulation::kModulationQAM256 == m) && ((c & FE_CAN_QAM_256) != 0U)) ||
487  ((DTVModulation::kModulationQAMAuto == m) && ((c & FE_CAN_QAM_AUTO) != 0U)) ||
488  ((DTVModulation::kModulation8VSB == m) && ((c & FE_CAN_8VSB) != 0U)) ||
489  ((DTVModulation::kModulation16VSB == m) && ((c & FE_CAN_16VSB) != 0U));
490 }
491 
496 {
497  if (!m_dvbcam->IsRunning())
498  m_dvbcam->Start();
499  if (pmt && m_dvbcam->IsRunning())
500  m_dvbcam->SetPMT(this, pmt);
501 }
502 
507 void DVBChannel::SetTimeOffset(double offset)
508 {
509  if (m_dvbcam->IsRunning())
510  m_dvbcam->SetTimeOffset(offset);
511 }
512 
513 bool DVBChannel::Tune(const DTVMultiplex &tuning)
514 {
515  if (!m_inputid)
516  {
517  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Tune(): Invalid input."));
518  return false;
519  }
520  return Tune(tuning, false, false);
521 }
522 
523 static struct dtv_properties *dtvmultiplex_to_dtvproperties(
524  DTVTunerType tuner_type, const DTVMultiplex &tuning, int intermediate_freq,
525  bool can_fec_auto, bool do_tune = true)
526 {
527  uint c = 0;
528  struct dtv_properties *cmdseq;
529 
530  if (tuner_type != DTVTunerType::kTunerTypeDVBT &&
531  tuner_type != DTVTunerType::kTunerTypeDVBC &&
532  tuner_type != DTVTunerType::kTunerTypeDVBS1 &&
533  tuner_type != DTVTunerType::kTunerTypeDVBS2 &&
534  tuner_type != DTVTunerType::kTunerTypeDVBT2)
535  {
536  LOG(VB_GENERAL, LOG_ERR, "DVBChan: Unsupported tuner type " +
537  tuner_type.toString());
538  return nullptr;
539  }
540 
541  LOG(VB_CHANNEL, LOG_DEBUG, "DVBChan: modsys " + tuning.m_mod_sys.toString());
542 
543  cmdseq = (struct dtv_properties*) calloc(1, sizeof(*cmdseq));
544  if (!cmdseq)
545  return nullptr;
546 
547  cmdseq->props = (struct dtv_property*) calloc(20, sizeof(*(cmdseq->props)));
548  if (!(cmdseq->props))
549  {
550  free(cmdseq);
551  return nullptr;
552  }
553 
554  // The cx24116 DVB-S2 demod anounce FE_CAN_FEC_AUTO but has apparently
555  // trouble with FEC_AUTO on DVB-S2 transponders
557  can_fec_auto = false;
558 
559  if (tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
560  tuner_type == DTVTunerType::kTunerTypeDVBT ||
561  tuner_type == DTVTunerType::kTunerTypeDVBT2)
562  {
563  cmdseq->props[c].cmd = DTV_DELIVERY_SYSTEM;
564  cmdseq->props[c++].u.data = tuning.m_mod_sys;
565  }
566 
567  cmdseq->props[c].cmd = DTV_FREQUENCY;
568  cmdseq->props[c++].u.data = intermediate_freq ? intermediate_freq : tuning.m_frequency;
569  cmdseq->props[c].cmd = DTV_MODULATION;
570  cmdseq->props[c++].u.data = tuning.m_modulation;
571  cmdseq->props[c].cmd = DTV_INVERSION;
572  cmdseq->props[c++].u.data = tuning.m_inversion;
573 
574  if (tuner_type == DTVTunerType::kTunerTypeDVBS1 ||
575  tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
576  tuner_type == DTVTunerType::kTunerTypeDVBC)
577  {
578  cmdseq->props[c].cmd = DTV_SYMBOL_RATE;
579  cmdseq->props[c++].u.data = tuning.m_symbolrate;
580  }
581 
582  if (tuner_type.IsFECVariable())
583  {
584  cmdseq->props[c].cmd = DTV_INNER_FEC;
585  cmdseq->props[c++].u.data = can_fec_auto ? FEC_AUTO
586  : (fe_code_rate_t) (int) tuning.m_fec;
587  }
588 
589  if (tuner_type == DTVTunerType::kTunerTypeDVBT ||
590  tuner_type == DTVTunerType::kTunerTypeDVBT2)
591  {
592  cmdseq->props[c].cmd = DTV_BANDWIDTH_HZ;
593  cmdseq->props[c++].u.data = (8-tuning.m_bandwidth) * 1000000;
594  cmdseq->props[c].cmd = DTV_CODE_RATE_HP;
595  cmdseq->props[c++].u.data = tuning.m_hp_code_rate;
596  cmdseq->props[c].cmd = DTV_CODE_RATE_LP;
597  cmdseq->props[c++].u.data = tuning.m_lp_code_rate;
598  cmdseq->props[c].cmd = DTV_TRANSMISSION_MODE;
599  cmdseq->props[c++].u.data = tuning.m_trans_mode;
600  cmdseq->props[c].cmd = DTV_GUARD_INTERVAL;
601  cmdseq->props[c++].u.data = tuning.m_guard_interval;
602  cmdseq->props[c].cmd = DTV_HIERARCHY;
603  cmdseq->props[c++].u.data = tuning.m_hierarchy;
604  }
605 
607  {
608  cmdseq->props[c].cmd = DTV_PILOT;
609  cmdseq->props[c++].u.data = PILOT_AUTO;
610  cmdseq->props[c].cmd = DTV_ROLLOFF;
611  cmdseq->props[c++].u.data = tuning.m_rolloff;
612  }
614  {
615  cmdseq->props[c].cmd = DTV_ROLLOFF;
616  cmdseq->props[c++].u.data = DTVRollOff::kRollOff_35;
617  }
618 
619  if (do_tune)
620  cmdseq->props[c++].cmd = DTV_TUNE;
621 
622  cmdseq->num = c;
623 
624  return cmdseq;
625 }
626 
627 /*****************************************************************************
628  Tuning functions for each of the five types of cards.
629  *****************************************************************************/
630 
642 bool DVBChannel::Tune(const DTVMultiplex &tuning,
643  bool force_reset,
644  bool same_input)
645 {
646  QMutexLocker lock(&m_tune_lock);
647  QMutexLocker locker(&m_hw_lock);
648 
649  DVBChannel *master = GetMasterLock();
650  if (master != this)
651  {
652  LOG(VB_CHANNEL, LOG_INFO, LOC + "Tuning on slave channel");
653  SetSIStandard(tuning.m_sistandard);
654  bool ok = master->Tune(tuning, force_reset, false);
655  ReturnMasterLock(master);
656  return ok;
657  }
658  ReturnMasterLock(master); // if we're the master we don't need this lock..
659 
660 
661  int intermediate_freq = 0;
662  bool can_fec_auto = false;
663  bool reset = (force_reset || m_first_tune);
664 
666  {
667  LOG(VB_GENERAL, LOG_ERR, LOC +
668  "DVB-S/S2 needs device tree for LNB handling");
669  return false;
670  }
671 
672  m_desired_tuning = tuning;
673 
674  if (m_fd_frontend < 0)
675  {
676  LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!");
677 
678  return false;
679  }
680 
681  // Remove any events in queue before tuning.
683 
684  LOG(VB_CHANNEL, LOG_INFO, LOC + "\nOld Params: " + m_prev_tuning.toString() +
685  "\nNew Params: " + tuning.toString());
686 
687  // DVB-S is in kHz, other DVB is in Hz
688  bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == m_tunerType) ||
690  int freq_mult = (is_dvbs) ? 1 : 1000;
691  QString suffix = (is_dvbs) ? "kHz" : "Hz";
692 
693  if (reset || !m_prev_tuning.IsEqual(m_tunerType, tuning, 500 * freq_mult))
694  {
695  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2")
696  .arg(intermediate_freq ? intermediate_freq : tuning.m_frequency)
697  .arg(suffix));
698 
699  m_tune_delay_lock.lock();
700 
701  if (QDateTime::currentDateTime() < s_last_tuning)
702  {
703  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Next tuning after less than %1ms. Delaying by %1ms")
705  usleep(concurrent_tunings_delay * 1000);
706  }
707 
708  s_last_tuning = QDateTime::currentDateTime();
710 
711  m_tune_delay_lock.unlock();
712 
713  // send DVB-S setup
714  if (m_diseqc_tree)
715  {
716  // configure for new input
717  if (!same_input)
719 
720  // execute diseqc commands
721  if (!m_diseqc_tree->Execute(m_diseqc_settings, tuning))
722  {
723  LOG(VB_GENERAL, LOG_ERR, LOC +
724  "Tune(): Failed to setup DiSEqC devices");
725  return false;
726  }
727 
728  // retrieve actual intermediate frequency
730  if (!lnb)
731  {
732  LOG(VB_GENERAL, LOG_ERR, LOC +
733  "Tune(): No LNB for this configuration");
734  return false;
735  }
736 
737  if (lnb->GetDeviceID() != m_last_lnb_dev_id)
738  {
740  // make sure we tune to frequency, if the lnb has changed
741  m_first_tune = true;
742  }
743 
744  intermediate_freq = lnb->GetIntermediateFrequency(
745  m_diseqc_settings, tuning);
746 
747  // retrieve scr intermediate frequency
749  if (lnb && scr)
750  {
751  intermediate_freq = scr->GetIntermediateFrequency(intermediate_freq);
752  }
753 
754  // if card can auto-FEC, use it -- sometimes NITs are inaccurate
755  if (m_capabilities & FE_CAN_FEC_AUTO)
756  can_fec_auto = true;
757 
758  // Check DVB-S intermediate frequency here since it requires a fully
759  // initialized diseqc tree
760  CheckFrequency(intermediate_freq);
761  }
762 
765  {
766  struct dtv_property p_clear;
767  struct dtv_properties cmdseq_clear;
768 
769  p_clear.cmd = DTV_CLEAR;
770  cmdseq_clear.num = 1;
771  cmdseq_clear.props = &p_clear;
772 
773  if ((ioctl(m_fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0)
774  {
775  LOG(VB_GENERAL, LOG_ERR, LOC +
776  "Tune(): Clearing DTV properties cache failed." + ENO);
777  return false;
778  }
779 
780  struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties(
781  m_tunerType, tuning, intermediate_freq, can_fec_auto);
782 
783  if (!cmds) {
784  LOG(VB_GENERAL, LOG_ERR, LOC +
785  "Failed to convert DTVMultiplex to DTV_PROPERTY sequence");
786  return false;
787  }
788 
789  if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG))
790  {
791  for (uint i = 0; i < cmds->num; i++)
792  {
793  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
794  QString("prop %1: cmd = %2, data %3")
795  .arg(i).arg(cmds->props[i].cmd)
796  .arg(cmds->props[i].u.data));
797  }
798  }
799 
800  int res = ioctl(m_fd_frontend, FE_SET_PROPERTY, cmds);
801 
802  free(cmds->props);
803  free(cmds);
804 
805  if (res < 0)
806  {
807  LOG(VB_GENERAL, LOG_ERR, LOC +
808  "Tune(): Setting Frontend tuning parameters failed." + ENO);
809  return false;
810  }
811  }
812  else
813  {
814  struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams(
815  m_tunerType, tuning, intermediate_freq, can_fec_auto);
816 
817  if (ioctl(m_fd_frontend, FE_SET_FRONTEND, &params) < 0)
818  {
819  LOG(VB_GENERAL, LOG_ERR, LOC +
820  "Tune(): Setting Frontend tuning parameters failed." + ENO);
821  return false;
822  }
823  }
824 
825  // Extra delay to add for broken DVB drivers
826  if (m_tuning_delay)
827  usleep(m_tuning_delay * 1000);
828 
829  wait_for_backend(m_fd_frontend, 50 /* msec */);
830 
831  m_prev_tuning = tuning;
832  m_first_tune = false;
833  }
834 
835  SetSIStandard(tuning.m_sistandard);
836 
837  LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful");
838 
839  return true;
840 }
841 
843 {
844  return Tune(m_desired_tuning, true, true);
845 }
846 
851 {
852  QMutexLocker locker(&m_hw_lock);
853 
854  if (m_fd_frontend < 0)
855  {
856  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
857 
858  return false;
859  }
860 
861  const DVBChannel *master = GetMasterLock();
862  if (master != this)
863  {
864  bool ok = master->IsTuningParamsProbeSupported();
865  ReturnMasterLock(master);
866  return ok;
867  }
868  ReturnMasterLock(master); // if we're the master we don't need this lock..
869 
870  if (m_diseqc_tree)
871  {
872  // TODO We need to implement the inverse of
873  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
874  // to accurately reflect the frequency before LNB transform.
875  return false;
876  }
877 
878  dvb_frontend_parameters params;
879 
880  int res = ioctl(m_fd_frontend, FE_GET_FRONTEND, &params);
881  if (res < 0)
882  {
883  LOG(VB_CHANNEL, LOG_ERR, LOC + "Getting device frontend failed." + ENO);
884  }
885 
886  return (res >= 0);
887 }
888 
897 {
898  QMutexLocker locker(&m_hw_lock);
899 
900  if (m_fd_frontend < 0)
901  {
902  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
903 
904  return false;
905  }
906 
907  const DVBChannel *master = GetMasterLock();
908  if (master != this)
909  {
910  bool ok = master->ProbeTuningParams(tuning);
911  ReturnMasterLock(master);
912  return ok;
913  }
914  ReturnMasterLock(master); // if we're the master we don't need this lock..
915 
916  if (m_diseqc_tree)
917  {
918  // TODO We need to implement the inverse of
919  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
920  // to accurately reflect the frequency before LNB transform.
921  return false;
922  }
923 
925  {
926  // TODO implement probing of tuning parameters with FE_GET_PROPERTY
927  return false;
928  }
929 
930  dvb_frontend_parameters params;
931  if (ioctl(m_fd_frontend, FE_GET_FRONTEND, &params) < 0)
932  {
933  LOG(VB_GENERAL, LOG_ERR, LOC +
934  "Getting Frontend tuning parameters failed." + ENO);
935 
936  return false;
937  }
938 
939  uint mplex = tuning.m_mplex;
940  QString sistandard = tuning.m_sistandard;
941 
942  tuning = dvbparams_to_dtvmultiplex(m_tunerType, params);
943 
944  tuning.m_mplex = mplex;
945  tuning.m_sistandard = sistandard;
946 
947  return true;
948 }
949 
955 {
956  int found = 0;
957  int id = -1;
958  MSqlQuery query(MSqlQuery::InitCon());
959 
960  query.prepare("SELECT chanid,visible "
961  "FROM channel, capturecard "
962  "WHERE capturecard.sourceid = channel.sourceid AND "
963  " channel.channum = :CHANNUM AND "
964  " capturecard.cardid = :INPUTID");
965 
966  query.bindValue(":CHANNUM", m_curchannelname);
967  query.bindValue(":INPUTID", m_inputid);
968 
969  if (!query.exec() || !query.isActive())
970  {
971  MythDB::DBError("fetching chanid", query);
972  return -1;
973  }
974 
975  while (query.next())
976  {
977  found += query.value(1).toInt();
978  if (id == -1 || found)
979  id = query.value(0).toInt();
980  }
981 
982  if (!found)
983  {
984  LOG(VB_GENERAL, LOG_INFO,
985  QString("No visible channel ids for %1")
986  .arg(m_curchannelname));
987  }
988 
989  if (found > 1)
990  {
991  LOG(VB_GENERAL, LOG_WARNING,
992  QString("Found multiple visible channel ids for %1")
993  .arg(m_curchannelname));
994  }
995 
996  return id;
997 }
998 
1000 {
1001  if (m_diseqc_tree)
1003 
1004  return nullptr;
1005 }
1006 
1007 // documented in dvbchannel.h
1008 bool DVBChannel::HasLock(bool *ok) const
1009 {
1010  const DVBChannel *master = GetMasterLock();
1011  if (master != this)
1012  {
1013  bool haslock = master->HasLock(ok);
1014  ReturnMasterLock(master);
1015  return haslock;
1016  }
1017  ReturnMasterLock(master); // if we're the master we don't need this lock..
1018 
1019  fe_status_t status;
1020  memset(&status, 0, sizeof(status));
1021 
1022  int ret = ioctl(m_fd_frontend, FE_READ_STATUS, &status);
1023  if (ret < 0)
1024  {
1025  LOG(VB_GENERAL, LOG_ERR, LOC +
1026  "FE_READ_STATUS failed" + ENO);
1027  }
1028 
1029  if (ok)
1030  *ok = (0 == ret);
1031 
1032  return (status & FE_HAS_LOCK) != 0;
1033 }
1034 
1035 // documented in dvbchannel.h
1037 {
1038  struct dtv_property prop;
1039  struct dtv_properties cmd;
1040 
1041  memset(&prop, 0, sizeof(prop));
1042  prop.cmd = DTV_STAT_SIGNAL_STRENGTH;
1043  cmd.num = 1;
1044  cmd.props = &prop;
1045  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1046  LOG(VB_RECORD, LOG_DEBUG, LOC +
1047  QString("FE DTV signal strength ret=%1 res=%2 len=%3 scale=%4 val=%5")
1048  .arg(ret)
1049  .arg(cmd.props->result)
1050  .arg(cmd.props->u.st.len)
1051  .arg(cmd.props->u.st.stat[0].scale)
1052  .arg(cmd.props->u.st.stat[0].svalue)
1053  );
1054  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1055  if (ok)
1056  *ok = tmpOk;
1057  double value = 0;
1058  if (tmpOk)
1059  {
1060  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1061  {
1062  // -20dBm is a great signal so make that 100%
1063  // -100dBm lower than the noise floor so that is 0%
1064  // svalue is in 0.001 dBm
1065  // If the value is outside the range -100 to 0 dBm
1066  // we do not believe it.
1067  int svalue = cmd.props->u.st.stat[0].svalue;
1068  if (svalue >= -100000 && svalue <= -0)
1069  {
1070  // convert value from -100dBm to -20dBm to a 0-1 range
1071  value = svalue + 100000.0;
1072  value = value / 80000.0;
1073  if (value > 1.0)
1074  value = 1.0;
1075  }
1076  }
1077  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1078  {
1079  // returned as 16 bit unsigned
1080  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1081  }
1082  }
1083  else
1084  {
1085  LOG(VB_RECORD, LOG_ERR, LOC +
1086  "Getting DVBv5 Frontend signal strength failed." + ENO);
1087  }
1088  return value;
1089 }
1090 
1091 // documented in dvbchannel.h
1092 double DVBChannel::GetSignalStrength(bool *ok) const
1093 {
1094  const DVBChannel *master = GetMasterLock();
1095  if (master != this)
1096  {
1097  double val = master->GetSignalStrength(ok);
1098  ReturnMasterLock(master);
1099  return val;
1100  }
1101  ReturnMasterLock(master); // if we're the master we don't need this lock..
1102 
1103  // We use uint16_t for sig because this is correct for DVB API 4.0,
1104  // and works better than the correct int16_t for the 3.x API
1105  uint16_t sig = 0;
1106  int ret = ioctl(m_fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig);
1107  if (ret < 0)
1108  {
1109  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1110  {
1111  return GetSignalStrengthDVBv5(ok);
1112  }
1113  LOG(VB_RECORD, LOG_ERR, LOC +
1114  "Getting Frontend signal strength failed." + ENO);
1115  }
1116 
1117  if (ok)
1118  *ok = (0 == ret);
1119 
1120  return sig * (1.0 / 65535.0);
1121 }
1122 
1123 // documented in dvbchannel.h
1124 double DVBChannel::GetSNRDVBv5(bool *ok) const
1125 {
1126  struct dtv_property prop;
1127  struct dtv_properties cmd;
1128 
1129  memset(&prop, 0, sizeof(prop));
1130  prop.cmd = DTV_STAT_CNR;
1131  cmd.num = 1;
1132  cmd.props = &prop;
1133  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1134  LOG(VB_RECORD, LOG_DEBUG, LOC +
1135  QString("FE DTV cnr ret=%1 res=%2 len=%3 scale=%4 val=%5")
1136  .arg(ret)
1137  .arg(cmd.props->result)
1138  .arg(cmd.props->u.st.len)
1139  .arg(cmd.props->u.st.stat[0].scale)
1140  .arg(cmd.props->u.st.stat[0].svalue)
1141  );
1142  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1143  if (ok)
1144  *ok = tmpOk;
1145  double value = 0;
1146  if (tmpOk)
1147  {
1148  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1149  {
1150  // svalue is in 0.001 dB
1151  value = cmd.props->u.st.stat[0].svalue;
1152  // let 50dB+ CNR be 100% quality and 0dB be 0%
1153  // convert 0.001 dB from 0-50000 to a 0-1 range
1154  value = value / 50000.0;
1155  if (value > 1.0)
1156  value = 1.0;
1157  else if (value < 0)
1158  value = 0.0;
1159  }
1160  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1161  {
1162  // returned as 16 bit unsigned
1163  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1164  }
1165  }
1166  else
1167  {
1168  LOG(VB_RECORD, LOG_ERR, LOC +
1169  "Getting DVBv5 Frontend signal/noise ratio failed." + ENO);
1170  }
1171  return value;
1172 }
1173 
1174 // documented in dvbchannel.h
1175 double DVBChannel::GetSNR(bool *ok) const
1176 {
1177  const DVBChannel *master = GetMasterLock();
1178  if (master != this)
1179  {
1180  double val = master->GetSNR(ok);
1181  ReturnMasterLock(master);
1182  return val;
1183  }
1184  ReturnMasterLock(master); // if we're the master we don't need this lock..
1185 
1186  // We use uint16_t for sig because this is correct for DVB API 4.0,
1187  // and works better than the correct int16_t for the 3.x API
1188  uint16_t snr = 0;
1189  int ret = ioctl(m_fd_frontend, FE_READ_SNR, &snr);
1190  if (ret < 0)
1191  {
1192  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1193  {
1194  return GetSNRDVBv5(ok);
1195  }
1196  LOG(VB_GENERAL, LOG_ERR, LOC +
1197  "Getting Frontend signal/noise ratio failed." + ENO);
1198  }
1199 
1200  if (ok)
1201  *ok = (0 == ret);
1202 
1203  return snr * (1.0 / 65535.0);
1204 }
1205 
1206 // documented in dvbchannel.h
1207 double DVBChannel::GetBitErrorRateDVBv5(bool *ok) const
1208 {
1209  struct dtv_property prop[2];
1210  struct dtv_properties cmd;
1211 
1212  memset(&prop, 0, sizeof(prop));
1213  prop[0].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
1214  prop[1].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
1215  cmd.num = 2;
1216  cmd.props = prop;
1217  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1218  LOG(VB_RECORD, LOG_DEBUG, LOC +
1219  QString("FE DTV bit error rate ret=%1 res=%2 len=%3 scale=%4 val=%5 res=%6 len=%7 scale=%8 val=%9")
1220  .arg(ret)
1221  .arg(cmd.props[0].result)
1222  .arg(cmd.props[0].u.st.len)
1223  .arg(cmd.props[0].u.st.stat[0].scale)
1224  .arg(cmd.props[0].u.st.stat[0].uvalue)
1225  .arg(cmd.props[1].result)
1226  .arg(cmd.props[1].u.st.len)
1227  .arg(cmd.props[1].u.st.stat[0].scale)
1228  .arg(cmd.props[1].u.st.stat[0].uvalue)
1229  );
1230  bool tmpOk = (ret == 0) &&
1231  (cmd.props[0].u.st.len > 0) &&
1232  (cmd.props[1].u.st.len > 0);
1233  if (ok)
1234  *ok = tmpOk;
1235  double value = 0;
1236  if (tmpOk)
1237  {
1238  if ((cmd.props[0].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1239  (cmd.props[1].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1240  (cmd.props[1].u.st.stat[0].uvalue != 0))
1241  {
1242  value = static_cast<double>(
1243  static_cast<long double>(cmd.props[0].u.st.stat[0].uvalue) /
1244  cmd.props[1].u.st.stat[0].uvalue);
1245  }
1246  }
1247  else
1248  {
1249  LOG(VB_RECORD, LOG_ERR, LOC +
1250  "Getting DVBv5 Frontend bit error rate failed." + ENO);
1251  }
1252  return value;
1253 }
1254 
1255 // documented in dvbchannel.h
1256 double DVBChannel::GetBitErrorRate(bool *ok) const
1257 {
1258  const DVBChannel *master = GetMasterLock();
1259  if (master != this)
1260  {
1261  double val = master->GetBitErrorRate(ok);
1262  ReturnMasterLock(master);
1263  return val;
1264  }
1265  ReturnMasterLock(master); // if we're the master we don't need this lock..
1266 
1267  uint32_t ber = 0;
1268  int ret = ioctl(m_fd_frontend, FE_READ_BER, &ber);
1269  if (ret < 0)
1270  {
1271  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1272  {
1273  return GetBitErrorRateDVBv5(ok);
1274  }
1275  LOG(VB_RECORD, LOG_ERR, LOC +
1276  "Getting Frontend bit error rate failed." + ENO);
1277  }
1278 
1279  if (ok)
1280  *ok = (0 == ret);
1281 
1282  return (double) ber;
1283 }
1284 
1285 // documented in dvbchannel.h
1287 {
1288  struct dtv_property prop;
1289  struct dtv_properties cmd;
1290 
1291  memset(&prop, 0, sizeof(prop));
1292  prop.cmd = DTV_STAT_ERROR_BLOCK_COUNT;
1293  cmd.num = 1;
1294  cmd.props = &prop;
1295  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1296  LOG(VB_RECORD, LOG_DEBUG, LOC +
1297  QString("FE DTV uncorrected block count ret=%1 res=%2 len=%3 scale=%4 val=%5")
1298  .arg(ret)
1299  .arg(cmd.props[0].result)
1300  .arg(cmd.props[0].u.st.len)
1301  .arg(cmd.props[0].u.st.stat[0].scale)
1302  .arg(cmd.props[0].u.st.stat[0].svalue)
1303  );
1304  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1305  if (ok)
1306  *ok = tmpOk;
1307  double value = 0;
1308  if (tmpOk)
1309  {
1310  if (cmd.props->u.st.stat[0].scale == FE_SCALE_COUNTER)
1311  value = cmd.props->u.st.stat[0].uvalue;
1312  }
1313  else
1314  {
1315  LOG(VB_RECORD, LOG_DEBUG, LOC +
1316  "Getting DVBv5 Frontend uncorrected block count failed." + ENO);
1317  }
1318  return value;
1319 }
1320 
1321 // documented in dvbchannel.h
1323 {
1324  const DVBChannel *master = GetMasterLock();
1325  if (master != this)
1326  {
1327  double val = master->GetUncorrectedBlockCount(ok);
1328  ReturnMasterLock(master);
1329  return val;
1330  }
1331  ReturnMasterLock(master); // if we're the master we don't need this lock..
1332 
1333  uint32_t ublocks = 0;
1334  int ret = ioctl(m_fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
1335  if (ret < 0)
1336  {
1337  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1338  {
1339  return GetUncorrectedBlockCountDVBv5(ok);
1340  }
1341  LOG(VB_GENERAL, LOG_ERR, LOC +
1342  "Getting Frontend uncorrected block count failed." + ENO);
1343  }
1344 
1345  if (ok)
1346  *ok = (0 == ret);
1347 
1348  return (double) ublocks;
1349 }
1350 
1352 {
1354  if (m_pParent)
1355  key += QString(":%1")
1357  DTVChannel *master = DTVChannel::GetMasterLock(key);
1358  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1359  if (master && !dvbm)
1361  return dvbm;
1362 }
1363 
1365 {
1366  DTVChannel *chan = static_cast<DTVChannel*>(dvbm);
1368  dvbm = nullptr;
1369 }
1370 
1372 {
1374  if (m_pParent)
1375  key += QString(":%1")
1377  DTVChannel *master = DTVChannel::GetMasterLock(key);
1378  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1379  if (master && !dvbm)
1381  return dvbm;
1382 }
1383 
1384 void DVBChannel::ReturnMasterLock(DVBChannelCP &dvbm)
1385 {
1386  DTVChannel *chan =
1387  static_cast<DTVChannel*>(const_cast<DVBChannel*>(dvbm));
1389  dvbm = nullptr;
1390 }
1391 
1392 bool DVBChannel::IsMaster(void) const
1393 {
1394  const DVBChannel *master = GetMasterLock();
1395  bool is_master = (master == this);
1396  ReturnMasterLock(master);
1397  return is_master;
1398 }
1399 
1404 static void drain_dvb_events(int fd)
1405 {
1406  struct dvb_frontend_event event;
1407  int ret = 0;
1408  while ((ret = ioctl(fd, FE_GET_EVENT, &event)) == 0);
1409  if ((ret < 0) && (EAGAIN != errno))
1410  {
1411  LOG(VB_CHANNEL, LOG_DEBUG, "Draining DVB Event failed. " + ENO);
1412  }
1413 }
1414 
1438 static bool wait_for_backend(int fd, int timeout_ms)
1439 {
1440  struct timeval select_timeout = { timeout_ms/1000, (timeout_ms % 1000) * 1000 /*usec*/};
1441  fd_set fd_select_set;
1442  FD_ZERO( &fd_select_set);
1443  FD_SET (fd, &fd_select_set);
1444 
1445  // Try to wait for some output like an event, unfortunately
1446  // this fails on several DVB cards, so we have a timeout.
1447  int ret = 0;
1448  do ret = select(fd+1, &fd_select_set, nullptr, nullptr, &select_timeout);
1449  while ((-1 == ret) && (EINTR == errno));
1450 
1451  if (-1 == ret)
1452  {
1453  LOG(VB_GENERAL, LOG_ERR,
1454  "DVBChan: wait_for_backend: Failed to wait on output" + ENO);
1455 
1456  return false;
1457  }
1458 
1459  // This is supposed to work on all cards, post 2.6.12...
1460  fe_status_t status;
1461  memset(&status, 0, sizeof(status));
1462 
1463  if (ioctl(fd, FE_READ_STATUS, &status) < 0)
1464  {
1465  LOG(VB_GENERAL, LOG_ERR,
1466  "DVBChan: wait_for_backend: Failed to get status" + ENO);
1467 
1468  return false;
1469  }
1470 
1471  LOG(VB_CHANNEL, LOG_INFO, QString("DVBChan: wait_for_backend: Status: %1")
1472  .arg(toString(status)));
1473 
1474  return true;
1475 }
1476 
1477 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
1478  DTVTunerType tuner_type, const DTVMultiplex &tuning,
1479  int intermediate_freq, bool can_fec_auto)
1480 {
1481  dvb_frontend_parameters params;
1482  memset(&params, 0, sizeof(params));
1483 
1484  params.frequency = tuning.m_frequency;
1485  params.inversion = (fe_spectral_inversion_t) (int) tuning.m_inversion;
1486 
1487  if (DTVTunerType::kTunerTypeDVBS1 == tuner_type)
1488  {
1489  if (tuning.m_mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
1490  LOG(VB_GENERAL, LOG_ERR,
1491  "DVBChan: Error, Tuning of a DVB-S2 transport "
1492  "with a DVB-S card will fail.");
1493 
1494  params.frequency = intermediate_freq;
1495  params.u.qpsk.symbol_rate = tuning.m_symbolrate;
1496  params.u.qpsk.fec_inner = can_fec_auto ? FEC_AUTO
1497  : (fe_code_rate_t) (int) tuning.m_fec;
1498  }
1499 
1500  if (DTVTunerType::kTunerTypeDVBS2 == tuner_type)
1501  {
1502  LOG(VB_GENERAL, LOG_ERR,
1503  "DVBChan: Error, MythTV was compiled without "
1504  "DVB-S2 headers being present so DVB-S2 tuning will fail.");
1505  }
1506 
1507  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1508  {
1509  params.u.qam.symbol_rate = tuning.m_symbolrate;
1510  params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.m_fec;
1511  params.u.qam.modulation = (fe_modulation_t) (int) tuning.m_modulation;
1512  }
1513 
1514  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1515  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1516  {
1517  params.u.ofdm.bandwidth =
1518  (fe_bandwidth_t) (int) tuning.m_bandwidth;
1519  params.u.ofdm.code_rate_HP =
1520  (fe_code_rate_t) (int) tuning.m_hp_code_rate;
1521  params.u.ofdm.code_rate_LP =
1522  (fe_code_rate_t) (int) tuning.m_lp_code_rate;
1523  params.u.ofdm.constellation =
1524  (fe_modulation_t) (int) tuning.m_modulation;
1525  params.u.ofdm.transmission_mode =
1526  (fe_transmit_mode_t) (int) tuning.m_trans_mode;
1527  params.u.ofdm.guard_interval =
1528  (fe_guard_interval_t) (int) tuning.m_guard_interval;
1529  params.u.ofdm.hierarchy_information =
1530  (fe_hierarchy_t) (int) tuning.m_hierarchy;
1531  }
1532 
1533  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1534  {
1535  params.u.vsb.modulation =
1536  (fe_modulation_t) (int) tuning.m_modulation;
1537  }
1538 
1539  return params;
1540 }
1541 
1543  DTVTunerType tuner_type, const dvb_frontend_parameters &params)
1544 {
1545  DTVMultiplex tuning;
1546 
1547  tuning.m_frequency = params.frequency;
1548  tuning.m_inversion = params.inversion;
1549 
1550  if ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
1551  (DTVTunerType::kTunerTypeDVBS2 == tuner_type))
1552  {
1553  tuning.m_symbolrate = params.u.qpsk.symbol_rate;
1554  tuning.m_fec = params.u.qpsk.fec_inner;
1555  }
1556 
1557  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1558  {
1559  tuning.m_symbolrate = params.u.qam.symbol_rate;
1560  tuning.m_fec = params.u.qam.fec_inner;
1561  tuning.m_modulation = params.u.qam.modulation;
1562  }
1563 
1564  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1565  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1566  {
1567  tuning.m_bandwidth = params.u.ofdm.bandwidth;
1568  tuning.m_hp_code_rate = params.u.ofdm.code_rate_HP;
1569  tuning.m_lp_code_rate = params.u.ofdm.code_rate_LP;
1570  tuning.m_modulation = params.u.ofdm.constellation;
1571  tuning.m_trans_mode = params.u.ofdm.transmission_mode;
1572  tuning.m_guard_interval = params.u.ofdm.guard_interval;
1573  tuning.m_hierarchy = params.u.ofdm.hierarchy_information;
1574  }
1575 
1576  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1577  {
1578  tuning.m_modulation = params.u.vsb.modulation;
1579  }
1580 
1581  return tuning;
1582 }
double GetSignalStrength(bool *ok=nullptr) const
Returns signal strength in the range [0.0..1.0] (non-calibrated).
static int SetDefaultDeliverySystem(uint inputid, int fd)
Definition: cardutil.cpp:1052
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
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:794
uint64_t m_symbolrate
Definition: dtvmultiplex.h:95
DTVGuardInterval m_guard_interval
Definition: dtvmultiplex.h:102
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:746
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
static QReadWriteLock s_master_map_lock
Definition: dtvchannel.h:180
uint64_t m_frequency_maximum
Definition: dvbchannel.h:147
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:240
static const int kTunerTypeDVBT
uint GetDeviceID(void) const
Definition: diseqc.h:163
int m_fd_frontend
File descriptor for tuning hardware.
Definition: dvbchannel.h:170
uint64_t m_capabilities
Definition: dvbchannel.h:144
#define O_NONBLOCK
Definition: mythmedia.cpp:25
int GetChanID(void) const override
Returns Channel ID.
Definition: dvbchannel.cpp:954
DTVBandwidth m_bandwidth
Definition: dtvmultiplex.h:97
TVRec * m_pParent
Definition: channelbase.h:134
uint m_last_lnb_dev_id
Definition: dvbchannel.h:159
void CheckFrequency(uint64_t frequency) const
Checks tuning frequency.
Definition: dvbchannel.cpp:333
QString toString(MarkTypes type)
static const int kTunerTypeATSC
DTVHierarchy m_hierarchy
Definition: dtvmultiplex.h:103
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:573
bool IsRunning(void) const
Definition: dvbcam.h:31
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:57
void SetPMT(const ProgramMapTable *)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:495
QString m_frontend_name
Definition: dvbchannel.h:143
uint64_t m_ext_modulations
Definition: dvbchannel.h:145
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:65
double GetUncorrectedBlockCountDVBv5(bool *ok) const
Get Uncorrected Block Count from the DVBv5 interface.
bool Start(void)
Definition: dvbcam.cpp:86
DTVInversion m_inversion
Definition: dtvmultiplex.h:96
QMutex m_hw_lock
Definition: dvbchannel.h:153
uint m_inputid
Definition: channelbase.h:137
DiSEqCDev m_diseqc_dev
Definition: dvbchannel.h:136
uint32_t GetIntermediateFrequency(const uint32_t frequency) const
Definition: diseqc.cpp:2252
DTVCodeRate m_lp_code_rate
Low Priority FEC rate.
Definition: dtvmultiplex.h:99
uint64_t m_frequency_minimum
Definition: dvbchannel.h:146
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
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:130
DTVTunerType m_tunerType
Definition: dtvchannel.h:163
QMutex m_tune_lock
Definition: dvbchannel.h:152
DiSEqCDevTree * m_diseqc_tree
Definition: dvbchannel.h:138
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
Definition: dvbchannel.cpp:999
DTVCodeRate m_fec
Inner Forward Error Correction rate.
Definition: dtvmultiplex.h:105
static MasterMap s_master_map
Definition: dtvchannel.h:181
bool Stop(void)
Definition: dvbcam.cpp:118
bool Retune(void) override
Definition: dvbchannel.cpp:842
QVariant value(int i) const
Definition: mythdbcon.h:198
DiSEqCDevRotor * FindRotor(const DiSEqCDevSettings &settings, uint index=0)
Returns the nth rotor device object in the tree.
Definition: diseqc.cpp:550
void SetTimeOffset(double offset)
Tells the Conditional Access Module the offset from the computers utc time to dvb time.
Definition: dvbchannel.cpp:507
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
DTVCodeRate m_hp_code_rate
High Priority FEC rate.
Definition: dtvmultiplex.h:98
static const int kTunerTypeDVBS2
DTVModulation m_modulation
Definition: dtvmultiplex.h:100
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 ...
static const int kTunerTypeDVBT2
uint m_tuning_delay
Extra delay to add for broken drivers.
Definition: dvbchannel.h:162
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.
#define close
Definition: compat.h:16
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:150
DTVMultiplex m_desired_tuning
Last tuning options Tune() attempted to send to hardware.
Definition: dvbchannel.h:155
bool m_first_tune
Used to force hardware reset.
Definition: dvbchannel.h:166
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:24
DiSEqCDevSCR * FindSCR(const DiSEqCDevSettings &settings)
Returns the SCR device object selected by the configuration chain.
Definition: diseqc.cpp:596
static DTVChannel * GetMasterLock(const QString &key)
Definition: dtvchannel.cpp:135
bool isActive(void) const
Definition: mythdbcon.h:204
Rotor class.
Definition: diseqc.h:293
bool ProbeTuningParams(DTVMultiplex &tuning) const
Fetches DTVMultiplex params from driver.
Definition: dvbchannel.cpp:896
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).
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:2559
QString m_device
DVB Device.
Definition: dvbchannel.h:171
void SetTimeOffset(double offset_in_seconds)
Definition: dvbcam.cpp:316
bool m_has_crc_bug
true iff our driver munges PMT
Definition: dvbchannel.h:173
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:535
static struct dtv_properties * dtvmultiplex_to_dtvproperties(DTVTunerType tuner_type, const DTVMultiplex &tuning, int intermediate_freq, bool can_fec_auto, bool do_tune=true)
Definition: dvbchannel.cpp:523
bool IsOpen(void) const override
Reports whether channel is already open.
Definition: dvbchannel.cpp:314
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
QString m_sistandard
Definition: dtvmultiplex.h:111
uint m_symbol_rate_maximum
Definition: dvbchannel.h:149
static QDateTime s_last_tuning
Definition: dvbchannel.h:175
#define LOC
Definition: dvbchannel.cpp:68
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
DTVRollOff m_rolloff
Definition: dtvmultiplex.h:107
bool IsDiSEqCSupported(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool Tune(const DTVMultiplex &tuning) override
This performs the actual frequency tuning and in some cases input switching.
Definition: dvbchannel.cpp:513
bool Execute(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
Applies settings to the entire tree.
Definition: diseqc.cpp:509
uint m_symbol_rate_minimum
Definition: dvbchannel.h:148
void SetSIStandard(const QString &)
Sets PSIP table standard: MPEG, DVB, ATSC, or OpenCable.
Definition: dtvchannel.cpp:50
QMutex m_tune_delay_lock
Definition: dvbchannel.h:176
static DTVTunerType ProbeTunerType(int fd_frontend)
Definition: cardutil.cpp:809
double GetSNR(bool *ok=nullptr) const
Returns signal/noise in the range [0..1.0].
Unicable / SCR Class.
Definition: diseqc.h:373
bool CheckModulation(DTVModulation modulation) const
Return true iff modulation is supported modulation on the frontend.
Definition: dvbchannel.cpp:470
void Close(void)
Definition: diseqc.h:102
bool Init(QString &startchannel, bool setchan) override
Definition: dvbchannel.cpp:322
DVBChannel * GetMasterLock(void)
LNB Class.
Definition: diseqc.h:438
bool IsTuningParamsProbeSupported(void) const
Returns true iff tuning info probing is working.
Definition: dvbchannel.cpp:850
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:75
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:1731
bool CheckCodeRate(DTVCodeRate rate) const
Return true iff rate is supported rate on the frontend.
Definition: dvbchannel.cpp:451
static void ReturnMasterLock(DTVChannelP &)
Definition: dtvchannel.cpp:147
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:346
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
DTVMultiplex m_prev_tuning
Last tuning options Tune() succesfully sent to hardware.
Definition: dvbchannel.h:157
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
IsOpenMap m_is_open
Definition: dvbchannel.h:133
DTVModulationSystem m_mod_sys
Modulation system.
Definition: dtvmultiplex.h:106
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:656
#define ENOTSUPP
Definition: dvbchannel.cpp:54
DVBCam * m_dvbcam
Used to decrypt encrypted streams.
Definition: dvbchannel.h:140
DiSEqCDevSettings m_diseqc_settings
Definition: dvbchannel.h:137
virtual bool InitializeInput(void)
Fills in input map from DB.
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:753
uint m_sigmon_delay
Minimum delay between FE_LOCK checks.
Definition: dvbchannel.h:164
uint64_t m_frequency
Definition: dtvmultiplex.h:94
DTVTransmitMode m_trans_mode
Definition: dtvmultiplex.h:101
void SetPMT(const ChannelBase *chan, const ProgramMapTable *pmt)
Definition: dvbcam.cpp:283
bool IsModulationVariable(void) const