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  prop.cmd = DTV_STAT_SIGNAL_STRENGTH;
1042  cmd.num = 1;
1043  cmd.props = &prop;
1044  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1045  LOG(VB_RECORD, LOG_DEBUG, LOC +
1046  QString("FE DTV signal strength ret=%1 res=%2 len=%3 scale=%4 val=%5")
1047  .arg(ret)
1048  .arg(cmd.props->result)
1049  .arg(cmd.props->u.st.len)
1050  .arg(cmd.props->u.st.stat[0].scale)
1051  .arg(cmd.props->u.st.stat[0].svalue)
1052  );
1053  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1054  if (ok)
1055  *ok = tmpOk;
1056  double value = 0;
1057  if (tmpOk)
1058  {
1059  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1060  {
1061  // -20dBm is a great signal so make that 100%
1062  // -100dBm lower than the noise floor so that is 0%
1063  // svalue is in 0.001 dBm
1064  // If the value is outside the range -100 to 0 dBm
1065  // we do not believe it.
1066  int svalue = cmd.props->u.st.stat[0].svalue;
1067  if (svalue >= -100000 && svalue <= -0)
1068  {
1069  // convert value from -100dBm to -20dBm to a 0-1 range
1070  value = svalue + 100000.0;
1071  value = value / 80000.0;
1072  if (value > 1.0)
1073  value = 1.0;
1074  }
1075  }
1076  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1077  {
1078  // returned as 16 bit unsigned
1079  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1080  }
1081  }
1082  else
1083  {
1084  LOG(VB_RECORD, LOG_ERR, LOC +
1085  "Getting DVBv5 Frontend signal strength failed." + ENO);
1086  }
1087  return value;
1088 }
1089 
1090 // documented in dvbchannel.h
1091 double DVBChannel::GetSignalStrength(bool *ok) const
1092 {
1093  const DVBChannel *master = GetMasterLock();
1094  if (master != this)
1095  {
1096  double val = master->GetSignalStrength(ok);
1097  ReturnMasterLock(master);
1098  return val;
1099  }
1100  ReturnMasterLock(master); // if we're the master we don't need this lock..
1101 
1102  // We use uint16_t for sig because this is correct for DVB API 4.0,
1103  // and works better than the correct int16_t for the 3.x API
1104  uint16_t sig = 0;
1105  int ret = ioctl(m_fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig);
1106  if (ret < 0)
1107  {
1108  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1109  {
1110  return GetSignalStrengthDVBv5(ok);
1111  }
1112  LOG(VB_RECORD, LOG_ERR, LOC +
1113  "Getting Frontend signal strength failed." + ENO);
1114  }
1115 
1116  if (ok)
1117  *ok = (0 == ret);
1118 
1119  return sig * (1.0 / 65535.0);
1120 }
1121 
1122 // documented in dvbchannel.h
1123 double DVBChannel::GetSNRDVBv5(bool *ok) const
1124 {
1125  struct dtv_property prop = {};
1126  struct dtv_properties cmd = {};
1127 
1128  memset(&prop, 0, sizeof(prop));
1129  prop.cmd = DTV_STAT_CNR;
1130  cmd.num = 1;
1131  cmd.props = &prop;
1132  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1133  LOG(VB_RECORD, LOG_DEBUG, LOC +
1134  QString("FE DTV cnr ret=%1 res=%2 len=%3 scale=%4 val=%5")
1135  .arg(ret)
1136  .arg(cmd.props->result)
1137  .arg(cmd.props->u.st.len)
1138  .arg(cmd.props->u.st.stat[0].scale)
1139  .arg(cmd.props->u.st.stat[0].svalue)
1140  );
1141  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1142  if (ok)
1143  *ok = tmpOk;
1144  double value = 0;
1145  if (tmpOk)
1146  {
1147  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1148  {
1149  // svalue is in 0.001 dB
1150  value = cmd.props->u.st.stat[0].svalue;
1151  // let 50dB+ CNR be 100% quality and 0dB be 0%
1152  // convert 0.001 dB from 0-50000 to a 0-1 range
1153  value = value / 50000.0;
1154  if (value > 1.0)
1155  value = 1.0;
1156  else if (value < 0)
1157  value = 0.0;
1158  }
1159  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1160  {
1161  // returned as 16 bit unsigned
1162  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1163  }
1164  }
1165  else
1166  {
1167  LOG(VB_RECORD, LOG_ERR, LOC +
1168  "Getting DVBv5 Frontend signal/noise ratio failed." + ENO);
1169  }
1170  return value;
1171 }
1172 
1173 // documented in dvbchannel.h
1174 double DVBChannel::GetSNR(bool *ok) const
1175 {
1176  const DVBChannel *master = GetMasterLock();
1177  if (master != this)
1178  {
1179  double val = master->GetSNR(ok);
1180  ReturnMasterLock(master);
1181  return val;
1182  }
1183  ReturnMasterLock(master); // if we're the master we don't need this lock..
1184 
1185  // We use uint16_t for sig because this is correct for DVB API 4.0,
1186  // and works better than the correct int16_t for the 3.x API
1187  uint16_t snr = 0;
1188  int ret = ioctl(m_fd_frontend, FE_READ_SNR, &snr);
1189  if (ret < 0)
1190  {
1191  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1192  {
1193  return GetSNRDVBv5(ok);
1194  }
1195  LOG(VB_GENERAL, LOG_ERR, LOC +
1196  "Getting Frontend signal/noise ratio failed." + ENO);
1197  }
1198 
1199  if (ok)
1200  *ok = (0 == ret);
1201 
1202  return snr * (1.0 / 65535.0);
1203 }
1204 
1205 // documented in dvbchannel.h
1206 double DVBChannel::GetBitErrorRateDVBv5(bool *ok) const
1207 {
1208  struct dtv_property prop[2] = {};
1209  struct dtv_properties cmd = {};
1210 
1211  prop[0].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
1212  prop[1].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
1213  cmd.num = 2;
1214  cmd.props = prop;
1215  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1216  LOG(VB_RECORD, LOG_DEBUG, LOC +
1217  QString("FE DTV bit error rate ret=%1 res=%2 len=%3 scale=%4 val=%5 res=%6 len=%7 scale=%8 val=%9")
1218  .arg(ret)
1219  .arg(cmd.props[0].result)
1220  .arg(cmd.props[0].u.st.len)
1221  .arg(cmd.props[0].u.st.stat[0].scale)
1222  .arg(cmd.props[0].u.st.stat[0].uvalue)
1223  .arg(cmd.props[1].result)
1224  .arg(cmd.props[1].u.st.len)
1225  .arg(cmd.props[1].u.st.stat[0].scale)
1226  .arg(cmd.props[1].u.st.stat[0].uvalue)
1227  );
1228  bool tmpOk = (ret == 0) &&
1229  (cmd.props[0].u.st.len > 0) &&
1230  (cmd.props[1].u.st.len > 0);
1231  if (ok)
1232  *ok = tmpOk;
1233  double value = 0;
1234  if (tmpOk)
1235  {
1236  if ((cmd.props[0].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1237  (cmd.props[1].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1238  (cmd.props[1].u.st.stat[0].uvalue != 0))
1239  {
1240  value = static_cast<double>(
1241  static_cast<long double>(cmd.props[0].u.st.stat[0].uvalue) /
1242  cmd.props[1].u.st.stat[0].uvalue);
1243  }
1244  }
1245  else
1246  {
1247  LOG(VB_RECORD, LOG_ERR, LOC +
1248  "Getting DVBv5 Frontend bit error rate failed." + ENO);
1249  }
1250  return value;
1251 }
1252 
1253 // documented in dvbchannel.h
1254 double DVBChannel::GetBitErrorRate(bool *ok) const
1255 {
1256  const DVBChannel *master = GetMasterLock();
1257  if (master != this)
1258  {
1259  double val = master->GetBitErrorRate(ok);
1260  ReturnMasterLock(master);
1261  return val;
1262  }
1263  ReturnMasterLock(master); // if we're the master we don't need this lock..
1264 
1265  uint32_t ber = 0;
1266  int ret = ioctl(m_fd_frontend, FE_READ_BER, &ber);
1267  if (ret < 0)
1268  {
1269  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1270  {
1271  return GetBitErrorRateDVBv5(ok);
1272  }
1273  LOG(VB_RECORD, LOG_ERR, LOC +
1274  "Getting Frontend bit error rate failed." + ENO);
1275  }
1276 
1277  if (ok)
1278  *ok = (0 == ret);
1279 
1280  return (double) ber;
1281 }
1282 
1283 // documented in dvbchannel.h
1285 {
1286  struct dtv_property prop = {};
1287  struct dtv_properties cmd = {};
1288 
1289  prop.cmd = DTV_STAT_ERROR_BLOCK_COUNT;
1290  cmd.num = 1;
1291  cmd.props = &prop;
1292  int ret = ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd);
1293  LOG(VB_RECORD, LOG_DEBUG, LOC +
1294  QString("FE DTV uncorrected block count ret=%1 res=%2 len=%3 scale=%4 val=%5")
1295  .arg(ret)
1296  .arg(cmd.props[0].result)
1297  .arg(cmd.props[0].u.st.len)
1298  .arg(cmd.props[0].u.st.stat[0].scale)
1299  .arg(cmd.props[0].u.st.stat[0].svalue)
1300  );
1301  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1302  if (ok)
1303  *ok = tmpOk;
1304  double value = 0;
1305  if (tmpOk)
1306  {
1307  if (cmd.props->u.st.stat[0].scale == FE_SCALE_COUNTER)
1308  value = cmd.props->u.st.stat[0].uvalue;
1309  }
1310  else
1311  {
1312  LOG(VB_RECORD, LOG_DEBUG, LOC +
1313  "Getting DVBv5 Frontend uncorrected block count failed." + ENO);
1314  }
1315  return value;
1316 }
1317 
1318 // documented in dvbchannel.h
1320 {
1321  const DVBChannel *master = GetMasterLock();
1322  if (master != this)
1323  {
1324  double val = master->GetUncorrectedBlockCount(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 ublocks = 0;
1331  int ret = ioctl(m_fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
1332  if (ret < 0)
1333  {
1334  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1335  {
1336  return GetUncorrectedBlockCountDVBv5(ok);
1337  }
1338  LOG(VB_GENERAL, LOG_ERR, LOC +
1339  "Getting Frontend uncorrected block count failed." + ENO);
1340  }
1341 
1342  if (ok)
1343  *ok = (0 == ret);
1344 
1345  return (double) ublocks;
1346 }
1347 
1349 {
1351  if (m_pParent)
1352  key += QString(":%1")
1354  DTVChannel *master = DTVChannel::GetMasterLock(key);
1355  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1356  if (master && !dvbm)
1358  return dvbm;
1359 }
1360 
1362 {
1363  DTVChannel *chan = static_cast<DTVChannel*>(dvbm);
1365  dvbm = nullptr;
1366 }
1367 
1369 {
1371  if (m_pParent)
1372  key += QString(":%1")
1374  DTVChannel *master = DTVChannel::GetMasterLock(key);
1375  DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
1376  if (master && !dvbm)
1378  return dvbm;
1379 }
1380 
1381 void DVBChannel::ReturnMasterLock(DVBChannelCP &dvbm)
1382 {
1383  DTVChannel *chan =
1384  static_cast<DTVChannel*>(const_cast<DVBChannel*>(dvbm));
1386  dvbm = nullptr;
1387 }
1388 
1389 bool DVBChannel::IsMaster(void) const
1390 {
1391  const DVBChannel *master = GetMasterLock();
1392  bool is_master = (master == this);
1393  ReturnMasterLock(master);
1394  return is_master;
1395 }
1396 
1401 static void drain_dvb_events(int fd)
1402 {
1403  struct dvb_frontend_event event;
1404  int ret = 0;
1405  while ((ret = ioctl(fd, FE_GET_EVENT, &event)) == 0);
1406  if ((ret < 0) && (EAGAIN != errno))
1407  {
1408  LOG(VB_CHANNEL, LOG_DEBUG, "Draining DVB Event failed. " + ENO);
1409  }
1410 }
1411 
1435 static bool wait_for_backend(int fd, int timeout_ms)
1436 {
1437  struct timeval select_timeout = { timeout_ms/1000, (timeout_ms % 1000) * 1000 /*usec*/};
1438  fd_set fd_select_set;
1439  FD_ZERO( &fd_select_set);
1440  FD_SET (fd, &fd_select_set);
1441 
1442  // Try to wait for some output like an event, unfortunately
1443  // this fails on several DVB cards, so we have a timeout.
1444  int ret = 0;
1445  do ret = select(fd+1, &fd_select_set, nullptr, nullptr, &select_timeout);
1446  while ((-1 == ret) && (EINTR == errno));
1447 
1448  if (-1 == ret)
1449  {
1450  LOG(VB_GENERAL, LOG_ERR,
1451  "DVBChan: wait_for_backend: Failed to wait on output" + ENO);
1452 
1453  return false;
1454  }
1455 
1456  // This is supposed to work on all cards, post 2.6.12...
1457  fe_status_t status;
1458  memset(&status, 0, sizeof(status));
1459 
1460  if (ioctl(fd, FE_READ_STATUS, &status) < 0)
1461  {
1462  LOG(VB_GENERAL, LOG_ERR,
1463  "DVBChan: wait_for_backend: Failed to get status" + ENO);
1464 
1465  return false;
1466  }
1467 
1468  LOG(VB_CHANNEL, LOG_INFO, QString("DVBChan: wait_for_backend: Status: %1")
1469  .arg(toString(status)));
1470 
1471  return true;
1472 }
1473 
1474 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
1475  DTVTunerType tuner_type, const DTVMultiplex &tuning,
1476  int intermediate_freq, bool can_fec_auto)
1477 {
1478  dvb_frontend_parameters params;
1479  memset(&params, 0, sizeof(params));
1480 
1481  params.frequency = tuning.m_frequency;
1482  params.inversion = (fe_spectral_inversion_t) (int) tuning.m_inversion;
1483 
1484  if (DTVTunerType::kTunerTypeDVBS1 == tuner_type)
1485  {
1486  if (tuning.m_mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
1487  LOG(VB_GENERAL, LOG_ERR,
1488  "DVBChan: Error, Tuning of a DVB-S2 transport "
1489  "with a DVB-S card will fail.");
1490 
1491  params.frequency = intermediate_freq;
1492  params.u.qpsk.symbol_rate = tuning.m_symbolrate;
1493  params.u.qpsk.fec_inner = can_fec_auto ? FEC_AUTO
1494  : (fe_code_rate_t) (int) tuning.m_fec;
1495  }
1496 
1497  if (DTVTunerType::kTunerTypeDVBS2 == tuner_type)
1498  {
1499  LOG(VB_GENERAL, LOG_ERR,
1500  "DVBChan: Error, MythTV was compiled without "
1501  "DVB-S2 headers being present so DVB-S2 tuning will fail.");
1502  }
1503 
1504  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1505  {
1506  params.u.qam.symbol_rate = tuning.m_symbolrate;
1507  params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.m_fec;
1508  params.u.qam.modulation = (fe_modulation_t) (int) tuning.m_modulation;
1509  }
1510 
1511  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1512  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1513  {
1514  params.u.ofdm.bandwidth =
1515  (fe_bandwidth_t) (int) tuning.m_bandwidth;
1516  params.u.ofdm.code_rate_HP =
1517  (fe_code_rate_t) (int) tuning.m_hp_code_rate;
1518  params.u.ofdm.code_rate_LP =
1519  (fe_code_rate_t) (int) tuning.m_lp_code_rate;
1520  params.u.ofdm.constellation =
1521  (fe_modulation_t) (int) tuning.m_modulation;
1522  params.u.ofdm.transmission_mode =
1523  (fe_transmit_mode_t) (int) tuning.m_trans_mode;
1524  params.u.ofdm.guard_interval =
1525  (fe_guard_interval_t) (int) tuning.m_guard_interval;
1526  params.u.ofdm.hierarchy_information =
1527  (fe_hierarchy_t) (int) tuning.m_hierarchy;
1528  }
1529 
1530  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1531  {
1532  params.u.vsb.modulation =
1533  (fe_modulation_t) (int) tuning.m_modulation;
1534  }
1535 
1536  return params;
1537 }
1538 
1540  DTVTunerType tuner_type, const dvb_frontend_parameters &params)
1541 {
1542  DTVMultiplex tuning;
1543 
1544  tuning.m_frequency = params.frequency;
1545  tuning.m_inversion = params.inversion;
1546 
1547  if ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
1548  (DTVTunerType::kTunerTypeDVBS2 == tuner_type))
1549  {
1550  tuning.m_symbolrate = params.u.qpsk.symbol_rate;
1551  tuning.m_fec = params.u.qpsk.fec_inner;
1552  }
1553 
1554  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1555  {
1556  tuning.m_symbolrate = params.u.qam.symbol_rate;
1557  tuning.m_fec = params.u.qam.fec_inner;
1558  tuning.m_modulation = params.u.qam.modulation;
1559  }
1560 
1561  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1562  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1563  {
1564  tuning.m_bandwidth = params.u.ofdm.bandwidth;
1565  tuning.m_hp_code_rate = params.u.ofdm.code_rate_HP;
1566  tuning.m_lp_code_rate = params.u.ofdm.code_rate_LP;
1567  tuning.m_modulation = params.u.ofdm.constellation;
1568  tuning.m_trans_mode = params.u.ofdm.transmission_mode;
1569  tuning.m_guard_interval = params.u.ofdm.guard_interval;
1570  tuning.m_hierarchy = params.u.ofdm.hierarchy_information;
1571  }
1572 
1573  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1574  {
1575  tuning.m_modulation = params.u.vsb.modulation;
1576  }
1577 
1578  return tuning;
1579 }
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:1048
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:801
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:743
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:580
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:2259
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:557
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:603
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:2566
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:516
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:806
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:1725
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:750
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