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 <utility>
38 #include <sys/poll.h>
39 #include <sys/select.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 
43 // MythTV headers
44 #include "mythconfig.h"
45 #include "mythdb.h"
46 #include "cardutil.h"
47 #include "channelutil.h"
48 #include "dvbtypes.h"
49 #include "dvbchannel.h"
50 #include "dvbcam.h"
51 #include "tv_rec.h"
52 
53 // Returned by drivers on unsupported DVBv3 ioctl calls
54 #ifndef ENOTSUPP
55 #define ENOTSUPP 524
56 #endif
57 
58 // Local functions
59 static void drain_dvb_events(int fd);
60 static bool wait_for_backend(int fd, int timeout_ms);
61 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
62  DTVTunerType /*tuner_type*/, const DTVMultiplex& /*tuning*/, int intermediate_freq, bool can_fec_auto);
64  DTVTunerType /*tuner_type*/, const dvb_frontend_parameters& /*params*/);
65 
66 int64_t concurrent_tunings_delay = 1000;
67 QDateTime DVBChannel::s_lastTuning = QDateTime::currentDateTime();
68 
69 #define LOC QString("DVBChan[%1](%2): ").arg(m_inputId).arg(DVBChannel::GetDevice())
70 
76 DVBChannel::DVBChannel(QString aDevice, TVRec *parent)
77  : DTVChannel(parent), m_device(std::move(aDevice))
78 {
79  s_master_map_lock.lockForWrite();
81  if (m_pParent)
82  key += QString(":%1")
84  s_master_map[key].push_back(this); // == RegisterForMaster
85  auto *master = dynamic_cast<DVBChannel*>(s_master_map[key].front());
86  if (master == this)
87  {
88  m_dvbCam = new DVBCam(m_device);
90  }
91  else
92  {
93  m_dvbCam = master->m_dvbCam;
94  m_hasCrcBug = master->m_hasCrcBug;
95  }
96  s_master_map_lock.unlock();
97 
99 }
100 
102 {
103  // set a new master if there are other instances and we're the master
104  // whether we are the master or not remove us from the map..
105  s_master_map_lock.lockForWrite();
107  if (m_pParent)
108  key += QString(":%1")
110  auto *master = dynamic_cast<DVBChannel*>(s_master_map[key].front());
111  if (master == this)
112  {
113  s_master_map[key].pop_front();
114  DVBChannel *new_master = nullptr;
115  if (!s_master_map[key].empty())
116  new_master = dynamic_cast<DVBChannel*>(s_master_map[key].front());
117  if (new_master)
118  {
119  QMutexLocker master_locker(&(master->m_hwLock));
120  QMutexLocker new_master_locker(&(new_master->m_hwLock));
121  new_master->m_isOpen = master->m_isOpen;
122  }
123  }
124  else
125  {
126  s_master_map[key].removeAll(this);
127  }
128  s_master_map_lock.unlock();
129 
131 
132  // if we're the last one out delete dvbcam
133  s_master_map_lock.lockForRead();
134  MasterMap::iterator mit = s_master_map.find(key);
135  if ((*mit).empty())
136  delete m_dvbCam;
137  m_dvbCam = nullptr;
138  s_master_map_lock.unlock();
139 
140  // diseqc_tree is managed elsewhere
141 }
142 
144 {
145  LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel");
146 
147  QMutexLocker locker(&m_hwLock);
148 
149  IsOpenMap::iterator it = m_isOpen.find(who);
150  if (it == m_isOpen.end())
151  return; // this caller didn't have it open in the first place..
152 
153  m_isOpen.erase(it);
154 
155  DVBChannel *master = GetMasterLock();
156  if (master != nullptr && master != this)
157  {
158  if (m_dvbCam->IsRunning())
159  m_dvbCam->SetPMT(this, nullptr);
160  master->Close(this);
161  m_fdFrontend = -1;
162  ReturnMasterLock(master);
163  return;
164  }
165  ReturnMasterLock(master); // if we're the master we don't need this lock..
166 
167  if (!m_isOpen.empty())
168  return; // not all callers have closed the DVB channel yet..
169 
170  if (m_diseqcTree)
171  m_diseqcTree->Close();
172 
173  if (m_fdFrontend >= 0)
174  {
176  m_fdFrontend = -1;
177 
178  m_dvbCam->Stop();
179  }
180 }
181 
183 {
184  LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel");
185 
186  if (!m_inputId)
187  {
188  if (!InitializeInput())
189  return false;
190  }
191 
192  QMutexLocker locker(&m_hwLock);
193 
194  if (m_fdFrontend >= 0)
195  {
196  m_isOpen[who] = true;
197  return true;
198  }
199 
200  DVBChannel *master = GetMasterLock();
201  if (master != this)
202  {
203  if (!master->Open(who))
204  {
205  ReturnMasterLock(master);
206  return false;
207  }
208 
209  m_fdFrontend = master->m_fdFrontend;
210  m_frontendName = master->m_frontendName;
211  m_tunerType = master->m_tunerType;
212  m_capabilities = master->m_capabilities;
218 
219  m_isOpen[who] = true;
220 
221  if (!InitializeInput())
222  {
223  Close();
224  ReturnMasterLock(master);
225  return false;
226  }
227 
228  ReturnMasterLock(master);
229  return true;
230  }
231  ReturnMasterLock(master); // if we're the master we don't need this lock..
232 
234  QByteArray devn = dvbdev.toLatin1();
235 
236  for (int tries = 1; ; ++tries)
237  {
238  m_fdFrontend = open(devn.constData(), O_RDWR | O_NONBLOCK);
239  if (m_fdFrontend >= 0)
240  break;
241  LOG(VB_GENERAL, LOG_WARNING, LOC +
242  "Opening DVB frontend device failed." + ENO);
243  if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
244  {
245  LOG(VB_GENERAL, LOG_ERR, LOC +
246  QString("Failed to open DVB frontend device due to "
247  "fatal error or too many attempts."));
248  return false;
249  }
250  usleep(50000);
251  }
252 
253  dvb_frontend_info info {};
254  if (ioctl(m_fdFrontend, FE_GET_INFO, &info) < 0)
255  {
256  LOG(VB_GENERAL, LOG_ERR, LOC +
257  "Failed to get frontend information." + ENO);
258 
260  m_fdFrontend = -1;
261  return false;
262  }
263 
264  m_frontendName = info.name;
265  m_capabilities = info.caps;
266  m_frequencyMinimum = info.frequency_min;
267  m_frequencyMaximum = info.frequency_max;
268  m_symbolRateMinimum = info.symbol_rate_min;
269  m_symbolRateMaximum = info.symbol_rate_max;
270 
273 
274  LOG(VB_RECORD, LOG_INFO, LOC +
275  QString("Frontend '%2' tunertype: %3")
276  .arg(m_frontendName).arg(m_tunerType.toString()));
277 
278  // Turn on the power to the LNB
280  {
281 
283  if (m_diseqcTree)
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_diseqcTree->Open(m_fdFrontend, is_SCR);
297  }
298  }
299 
300  m_firstTune = true;
301 
302  if (!InitializeInput())
303  {
304  Close();
305  return false;
306  }
307 
308  if (m_fdFrontend >= 0)
309  m_isOpen[who] = true;
310 
311  return (m_fdFrontend >= 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_hwLock);
318  IsOpenMap::const_iterator it = m_isOpen.find(this);
319  return it != m_isOpen.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_frequencyMinimum || frequency > m_frequencyMaximum))
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_frequencyMinimum).arg(m_frequencyMaximum));
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_diseqcTree)
359  {
360  DVBChannel *master = GetMasterLock();
361  if (master == nullptr || !master->m_diseqcTree)
362  CheckFrequency(tuning.m_frequency);
363  ReturnMasterLock(master);
364  }
365 
366  if (m_tunerType.IsFECVariable() &&
369  (tuning.m_symbolRate < m_symbolRateMinimum ||
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_hpCodeRate))
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_lpCodeRate))
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 
529  if (tuner_type != DTVTunerType::kTunerTypeDVBT &&
530  tuner_type != DTVTunerType::kTunerTypeDVBC &&
531  tuner_type != DTVTunerType::kTunerTypeDVBS1 &&
532  tuner_type != DTVTunerType::kTunerTypeDVBS2 &&
533  tuner_type != DTVTunerType::kTunerTypeDVBT2)
534  {
535  LOG(VB_GENERAL, LOG_ERR, "DVBChan: Unsupported tuner type " +
536  tuner_type.toString());
537  return nullptr;
538  }
539 
540  LOG(VB_CHANNEL, LOG_DEBUG, "DVBChan: modsys " + tuning.m_modSys.toString());
541 
542  auto *cmdseq = (struct dtv_properties*) calloc(1, sizeof(struct dtv_properties));
543  if (!cmdseq)
544  return nullptr;
545 
546  cmdseq->props = (struct dtv_property*) calloc(20, sizeof(*(cmdseq->props)));
547  if (!(cmdseq->props))
548  {
549  free(cmdseq);
550  return nullptr;
551  }
552 
553  // The cx24116 DVB-S2 demod anounce FE_CAN_FEC_AUTO but has apparently
554  // trouble with FEC_AUTO on DVB-S2 transponders
556  can_fec_auto = false;
557 
558  if (tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
559  tuner_type == DTVTunerType::kTunerTypeDVBT ||
560  tuner_type == DTVTunerType::kTunerTypeDVBT2)
561  {
562  cmdseq->props[c].cmd = DTV_DELIVERY_SYSTEM;
563  cmdseq->props[c++].u.data = tuning.m_modSys;
564  }
565 
566  cmdseq->props[c].cmd = DTV_FREQUENCY;
567  cmdseq->props[c++].u.data = intermediate_freq ? intermediate_freq : tuning.m_frequency;
568  cmdseq->props[c].cmd = DTV_MODULATION;
569  cmdseq->props[c++].u.data = tuning.m_modulation;
570  cmdseq->props[c].cmd = DTV_INVERSION;
571  cmdseq->props[c++].u.data = tuning.m_inversion;
572 
573  if (tuner_type == DTVTunerType::kTunerTypeDVBS1 ||
574  tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
575  tuner_type == DTVTunerType::kTunerTypeDVBC)
576  {
577  cmdseq->props[c].cmd = DTV_SYMBOL_RATE;
578  cmdseq->props[c++].u.data = tuning.m_symbolRate;
579  }
580 
581  if (tuner_type.IsFECVariable())
582  {
583  cmdseq->props[c].cmd = DTV_INNER_FEC;
584  cmdseq->props[c++].u.data = can_fec_auto ? FEC_AUTO
585  : (fe_code_rate_t) (int) tuning.m_fec;
586  }
587 
588  if (tuner_type == DTVTunerType::kTunerTypeDVBT ||
589  tuner_type == DTVTunerType::kTunerTypeDVBT2)
590  {
591  cmdseq->props[c].cmd = DTV_BANDWIDTH_HZ;
592  cmdseq->props[c++].u.data = (8-tuning.m_bandwidth) * 1000000;
593  cmdseq->props[c].cmd = DTV_CODE_RATE_HP;
594  cmdseq->props[c++].u.data = tuning.m_hpCodeRate;
595  cmdseq->props[c].cmd = DTV_CODE_RATE_LP;
596  cmdseq->props[c++].u.data = tuning.m_lpCodeRate;
597  cmdseq->props[c].cmd = DTV_TRANSMISSION_MODE;
598  cmdseq->props[c++].u.data = tuning.m_transMode;
599  cmdseq->props[c].cmd = DTV_GUARD_INTERVAL;
600  cmdseq->props[c++].u.data = tuning.m_guardInterval;
601  cmdseq->props[c].cmd = DTV_HIERARCHY;
602  cmdseq->props[c++].u.data = tuning.m_hierarchy;
603  }
604 
606  {
607  cmdseq->props[c].cmd = DTV_PILOT;
608  cmdseq->props[c++].u.data = PILOT_AUTO;
609  cmdseq->props[c].cmd = DTV_ROLLOFF;
610  cmdseq->props[c++].u.data = tuning.m_rolloff;
611  }
613  {
614  cmdseq->props[c].cmd = DTV_ROLLOFF;
615  cmdseq->props[c++].u.data = DTVRollOff::kRollOff_35;
616  }
617 
618  if (do_tune)
619  cmdseq->props[c++].cmd = DTV_TUNE;
620 
621  cmdseq->num = c;
622 
623  return cmdseq;
624 }
625 
626 /*****************************************************************************
627  Tuning functions for each of the five types of cards.
628  *****************************************************************************/
629 
641 bool DVBChannel::Tune(const DTVMultiplex &tuning,
642  bool force_reset,
643  bool same_input)
644 {
645  QMutexLocker lock(&m_tuneLock);
646  QMutexLocker locker(&m_hwLock);
647 
648  DVBChannel *master = GetMasterLock();
649  if (master != this)
650  {
651  LOG(VB_CHANNEL, LOG_INFO, LOC + "Tuning on slave channel");
652  SetSIStandard(tuning.m_sistandard);
653  bool ok = master->Tune(tuning, force_reset, false);
654  ReturnMasterLock(master);
655  return ok;
656  }
657  ReturnMasterLock(master); // if we're the master we don't need this lock..
658 
659 
660  int intermediate_freq = 0;
661  bool can_fec_auto = false;
662  bool reset = (force_reset || m_firstTune);
663 
665  {
666  LOG(VB_GENERAL, LOG_ERR, LOC +
667  "DVB-S/S2 needs device tree for LNB handling");
668  return false;
669  }
670 
671  m_desiredTuning = tuning;
672 
673  if (m_fdFrontend < 0)
674  {
675  LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!");
676 
677  return false;
678  }
679 
680  // Remove any events in queue before tuning.
682 
683  LOG(VB_CHANNEL, LOG_INFO, LOC + "\nOld Params: " + m_prevTuning.toString() +
684  "\nNew Params: " + tuning.toString());
685 
686  // DVB-S is in kHz, other DVB is in Hz
687  bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == m_tunerType) ||
689  int freq_mult = (is_dvbs) ? 1 : 1000;
690  QString suffix = (is_dvbs) ? "kHz" : "Hz";
691 
692  if (reset || !m_prevTuning.IsEqual(m_tunerType, tuning, 500 * freq_mult))
693  {
694  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2")
695  .arg(intermediate_freq ? intermediate_freq : tuning.m_frequency)
696  .arg(suffix));
697 
698  m_tuneDelayLock.lock();
699 
700  if (QDateTime::currentDateTime() < s_lastTuning)
701  {
702  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Next tuning after less than %1ms. Delaying by %1ms")
704  usleep(concurrent_tunings_delay * 1000);
705  }
706 
707  s_lastTuning = QDateTime::currentDateTime();
709 
710  m_tuneDelayLock.unlock();
711 
712  // send DVB-S setup
713  if (m_diseqcTree)
714  {
715  // configure for new input
716  if (!same_input)
718 
719  // execute diseqc commands
720  if (!m_diseqcTree->Execute(m_diseqcSettings, tuning))
721  {
722  LOG(VB_GENERAL, LOG_ERR, LOC +
723  "Tune(): Failed to setup DiSEqC devices");
724  return false;
725  }
726 
727  // retrieve actual intermediate frequency
729  if (!lnb)
730  {
731  LOG(VB_GENERAL, LOG_ERR, LOC +
732  "Tune(): No LNB for this configuration");
733  return false;
734  }
735 
736  if (lnb->GetDeviceID() != m_lastLnbDevId)
737  {
738  m_lastLnbDevId = lnb->GetDeviceID();
739  // make sure we tune to frequency, if the lnb has changed
740  m_firstTune = true;
741  }
742 
743  intermediate_freq = lnb->GetIntermediateFrequency(
744  m_diseqcSettings, tuning);
745 
746  // retrieve scr intermediate frequency
748  if (lnb && scr)
749  {
750  intermediate_freq = scr->GetIntermediateFrequency(intermediate_freq);
751  }
752 
753  // if card can auto-FEC, use it -- sometimes NITs are inaccurate
754  if (m_capabilities & FE_CAN_FEC_AUTO)
755  can_fec_auto = true;
756 
757  // Check DVB-S intermediate frequency here since it requires a fully
758  // initialized diseqc tree
759  CheckFrequency(intermediate_freq);
760  }
761 
764  {
765  struct dtv_property p_clear = {};
766  struct dtv_properties cmdseq_clear = {};
767 
768  p_clear.cmd = DTV_CLEAR;
769  cmdseq_clear.num = 1;
770  cmdseq_clear.props = &p_clear;
771 
772  if ((ioctl(m_fdFrontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0)
773  {
774  LOG(VB_GENERAL, LOG_ERR, LOC +
775  "Tune(): Clearing DTV properties cache failed." + ENO);
776  return false;
777  }
778 
779  struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties(
780  m_tunerType, tuning, intermediate_freq, can_fec_auto);
781 
782  if (!cmds) {
783  LOG(VB_GENERAL, LOG_ERR, LOC +
784  "Failed to convert DTVMultiplex to DTV_PROPERTY sequence");
785  return false;
786  }
787 
788  if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG))
789  {
790  for (uint i = 0; i < cmds->num; i++)
791  {
792  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
793  QString("prop %1: cmd = %2, data %3")
794  .arg(i).arg(cmds->props[i].cmd)
795  .arg(cmds->props[i].u.data));
796  }
797  }
798 
799  int res = ioctl(m_fdFrontend, FE_SET_PROPERTY, cmds);
800 
801  free(cmds->props);
802  free(cmds);
803 
804  if (res < 0)
805  {
806  LOG(VB_GENERAL, LOG_ERR, LOC +
807  "Tune(): Setting Frontend tuning parameters failed." + ENO);
808  return false;
809  }
810  }
811  else
812  {
813  struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams(
814  m_tunerType, tuning, intermediate_freq, can_fec_auto);
815 
816  if (ioctl(m_fdFrontend, FE_SET_FRONTEND, &params) < 0)
817  {
818  LOG(VB_GENERAL, LOG_ERR, LOC +
819  "Tune(): Setting Frontend tuning parameters failed." + ENO);
820  return false;
821  }
822  }
823 
824  // Extra delay to add for broken DVB drivers
825  if (m_tuningDelay)
826  usleep(m_tuningDelay * 1000);
827 
828  wait_for_backend(m_fdFrontend, 50 /* msec */);
829 
830  m_prevTuning = tuning;
831  m_firstTune = false;
832  }
833 
834  SetSIStandard(tuning.m_sistandard);
835 
836  LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful");
837 
838  return true;
839 }
840 
842 {
843  return Tune(m_desiredTuning, true, true);
844 }
845 
850 {
851  QMutexLocker locker(&m_hwLock);
852 
853  if (m_fdFrontend < 0)
854  {
855  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
856 
857  return false;
858  }
859 
860  DVBChannel *master = GetMasterLock();
861  if (master != this)
862  {
863  bool ok = master->IsTuningParamsProbeSupported();
864  ReturnMasterLock(master);
865  return ok;
866  }
867  ReturnMasterLock(master); // if we're the master we don't need this lock..
868 
869  if (m_diseqcTree)
870  {
871  // TODO We need to implement the inverse of
872  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
873  // to accurately reflect the frequency before LNB transform.
874  return false;
875  }
876 
877  dvb_frontend_parameters params {};
878 
879  int res = ioctl(m_fdFrontend, FE_GET_FRONTEND, &params);
880  if (res < 0)
881  {
882  LOG(VB_CHANNEL, LOG_ERR, LOC + "Getting device frontend failed." + ENO);
883  }
884 
885  return (res >= 0);
886 }
887 
896 {
897  QMutexLocker locker(&m_hwLock);
898 
899  if (m_fdFrontend < 0)
900  {
901  LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
902 
903  return false;
904  }
905 
906  DVBChannel *master = GetMasterLock();
907  if (master != this)
908  {
909  bool ok = master->ProbeTuningParams(tuning);
910  ReturnMasterLock(master);
911  return ok;
912  }
913  ReturnMasterLock(master); // if we're the master we don't need this lock..
914 
915  if (m_diseqcTree)
916  {
917  // TODO We need to implement the inverse of
918  // lnb->GetIntermediateFrequency() for ProbeTuningParams()
919  // to accurately reflect the frequency before LNB transform.
920  return false;
921  }
922 
924  {
925  // TODO implement probing of tuning parameters with FE_GET_PROPERTY
926  return false;
927  }
928 
929  dvb_frontend_parameters params {};
930  if (ioctl(m_fdFrontend, FE_GET_FRONTEND, &params) < 0)
931  {
932  LOG(VB_GENERAL, LOG_ERR, LOC +
933  "Getting Frontend tuning parameters failed." + ENO);
934 
935  return false;
936  }
937 
938  uint mplex = tuning.m_mplex;
939  QString sistandard = tuning.m_sistandard;
940 
941  tuning = dvbparams_to_dtvmultiplex(m_tunerType, params);
942 
943  tuning.m_mplex = mplex;
944  tuning.m_sistandard = sistandard;
945 
946  return true;
947 }
948 
954 {
955  int found = 0;
956  int id = -1;
958 
959  query.prepare("SELECT chanid,visible "
960  "FROM channel, capturecard "
961  "WHERE channel.deleted IS NULL AND "
962  " 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 += static_cast<int>(query.value(1).toInt() > 0);
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_diseqcTree)
1003 
1004  return nullptr;
1005 }
1006 
1007 // documented in dvbchannel.h
1008 bool DVBChannel::HasLock(bool *ok) const
1009 {
1010  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 #if ((DVB_API_VERSION > 5) || ((DVB_API_VERSION == 5) && (DVB_API_VERSION_MINOR > 10)))
1020  fe_status_t status = FE_NONE;
1021 #else // debian9, centos7
1022  fe_status_t status = (fe_status_t)0;
1023 #endif
1024  memset(&status, 0, sizeof(status));
1025 
1026  int ret = ioctl(m_fdFrontend, FE_READ_STATUS, &status);
1027  if (ret < 0)
1028  {
1029  LOG(VB_GENERAL, LOG_ERR, LOC +
1030  "FE_READ_STATUS failed" + ENO);
1031  }
1032 
1033  if (ok)
1034  *ok = (0 == ret);
1035 
1036  return (status & FE_HAS_LOCK) != 0;
1037 }
1038 
1039 // documented in dvbchannel.h
1041 {
1042  struct dtv_property prop = {};
1043  struct dtv_properties cmd = {};
1044 
1045  prop.cmd = DTV_STAT_SIGNAL_STRENGTH;
1046  cmd.num = 1;
1047  cmd.props = &prop;
1048  int ret = ioctl(m_fdFrontend, FE_GET_PROPERTY, &cmd);
1049  LOG(VB_RECORD, LOG_DEBUG, LOC +
1050  QString("FE DTV signal strength ret=%1 res=%2 len=%3 scale=%4 val=%5")
1051  .arg(ret)
1052  .arg(cmd.props->result)
1053  .arg(cmd.props->u.st.len)
1054  .arg(cmd.props->u.st.stat[0].scale)
1055  .arg(cmd.props->u.st.stat[0].svalue)
1056  );
1057  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1058  if (ok)
1059  *ok = tmpOk;
1060  double value = 0;
1061  if (tmpOk)
1062  {
1063  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1064  {
1065  // -20dBm is a great signal so make that 100%
1066  // -100dBm lower than the noise floor so that is 0%
1067  // svalue is in 0.001 dBm
1068  // If the value is outside the range -100 to 0 dBm
1069  // we do not believe it.
1070  int svalue = cmd.props->u.st.stat[0].svalue;
1071  if (svalue >= -100000 && svalue <= -0)
1072  {
1073  // convert value from -100dBm to -20dBm to a 0-1 range
1074  value = svalue + 100000.0;
1075  value = value / 80000.0;
1076  if (value > 1.0)
1077  value = 1.0;
1078  }
1079  }
1080  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1081  {
1082  // returned as 16 bit unsigned
1083  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1084  }
1085  }
1086  else
1087  {
1088  LOG(VB_RECORD, LOG_ERR, LOC +
1089  "Getting DVBv5 Frontend signal strength failed." + ENO);
1090  }
1091  return value;
1092 }
1093 
1094 // documented in dvbchannel.h
1095 double DVBChannel::GetSignalStrength(bool *ok) const
1096 {
1097  DVBChannel *master = GetMasterLock();
1098  if (master != this)
1099  {
1100  double val = master->GetSignalStrength(ok);
1101  ReturnMasterLock(master);
1102  return val;
1103  }
1104  ReturnMasterLock(master); // if we're the master we don't need this lock..
1105 
1106  // We use uint16_t for sig because this is correct for DVB API 4.0,
1107  // and works better than the correct int16_t for the 3.x API
1108  uint16_t sig = 0;
1109  int ret = ioctl(m_fdFrontend, FE_READ_SIGNAL_STRENGTH, &sig);
1110  if (ret < 0)
1111  {
1112  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1113  {
1114  return GetSignalStrengthDVBv5(ok);
1115  }
1116  LOG(VB_RECORD, LOG_ERR, LOC +
1117  "Getting Frontend signal strength failed." + ENO);
1118  }
1119 
1120  if (ok)
1121  *ok = (0 == ret);
1122 
1123  return sig * (1.0 / 65535.0);
1124 }
1125 
1126 // documented in dvbchannel.h
1127 double DVBChannel::GetSNRDVBv5(bool *ok) const
1128 {
1129  struct dtv_property prop = {};
1130  struct dtv_properties cmd = {};
1131 
1132  memset(&prop, 0, sizeof(prop));
1133  prop.cmd = DTV_STAT_CNR;
1134  cmd.num = 1;
1135  cmd.props = &prop;
1136  int ret = ioctl(m_fdFrontend, FE_GET_PROPERTY, &cmd);
1137  LOG(VB_RECORD, LOG_DEBUG, LOC +
1138  QString("FE DTV cnr ret=%1 res=%2 len=%3 scale=%4 val=%5")
1139  .arg(ret)
1140  .arg(cmd.props->result)
1141  .arg(cmd.props->u.st.len)
1142  .arg(cmd.props->u.st.stat[0].scale)
1143  .arg(cmd.props->u.st.stat[0].svalue)
1144  );
1145  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1146  if (ok)
1147  *ok = tmpOk;
1148  double value = 0;
1149  if (tmpOk)
1150  {
1151  if (cmd.props->u.st.stat[0].scale == FE_SCALE_DECIBEL)
1152  {
1153  // svalue is in 0.001 dB
1154  value = cmd.props->u.st.stat[0].svalue;
1155  // let 50dB+ CNR be 100% quality and 0dB be 0%
1156  // convert 0.001 dB from 0-50000 to a 0-1 range
1157  value = value / 50000.0;
1158  if (value > 1.0)
1159  value = 1.0;
1160  else if (value < 0)
1161  value = 0.0;
1162  }
1163  else if (cmd.props->u.st.stat[0].scale == FE_SCALE_RELATIVE)
1164  {
1165  // returned as 16 bit unsigned
1166  value = cmd.props->u.st.stat[0].uvalue / 65535.0;
1167  }
1168  }
1169  else
1170  {
1171  LOG(VB_RECORD, LOG_ERR, LOC +
1172  "Getting DVBv5 Frontend signal/noise ratio failed." + ENO);
1173  }
1174  return value;
1175 }
1176 
1177 // documented in dvbchannel.h
1178 double DVBChannel::GetSNR(bool *ok) const
1179 {
1180  DVBChannel *master = GetMasterLock();
1181  if (master != this)
1182  {
1183  double val = master->GetSNR(ok);
1184  ReturnMasterLock(master);
1185  return val;
1186  }
1187  ReturnMasterLock(master); // if we're the master we don't need this lock..
1188 
1189  // We use uint16_t for sig because this is correct for DVB API 4.0,
1190  // and works better than the correct int16_t for the 3.x API
1191  uint16_t snr = 0;
1192  int ret = ioctl(m_fdFrontend, FE_READ_SNR, &snr);
1193  if (ret < 0)
1194  {
1195  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1196  {
1197  return GetSNRDVBv5(ok);
1198  }
1199  LOG(VB_GENERAL, LOG_ERR, LOC +
1200  "Getting Frontend signal/noise ratio failed." + ENO);
1201  }
1202 
1203  if (ok)
1204  *ok = (0 == ret);
1205 
1206  return snr * (1.0 / 65535.0);
1207 }
1208 
1209 // documented in dvbchannel.h
1210 double DVBChannel::GetBitErrorRateDVBv5(bool *ok) const
1211 {
1212  struct dtv_property prop[2] = {};
1213  struct dtv_properties cmd = {};
1214 
1215  prop[0].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
1216  prop[1].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
1217  cmd.num = 2;
1218  cmd.props = prop;
1219  int ret = ioctl(m_fdFrontend, FE_GET_PROPERTY, &cmd);
1220  LOG(VB_RECORD, LOG_DEBUG, LOC +
1221  QString("FE DTV bit error rate ret=%1 res=%2 len=%3 scale=%4 val=%5 res=%6 len=%7 scale=%8 val=%9")
1222  .arg(ret)
1223  .arg(cmd.props[0].result)
1224  .arg(cmd.props[0].u.st.len)
1225  .arg(cmd.props[0].u.st.stat[0].scale)
1226  .arg(cmd.props[0].u.st.stat[0].uvalue)
1227  .arg(cmd.props[1].result)
1228  .arg(cmd.props[1].u.st.len)
1229  .arg(cmd.props[1].u.st.stat[0].scale)
1230  .arg(cmd.props[1].u.st.stat[0].uvalue)
1231  );
1232  bool tmpOk = (ret == 0) &&
1233  (cmd.props[0].u.st.len > 0) &&
1234  (cmd.props[1].u.st.len > 0);
1235  if (ok)
1236  *ok = tmpOk;
1237  double value = 0;
1238  if (tmpOk)
1239  {
1240  if ((cmd.props[0].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1241  (cmd.props[1].u.st.stat[0].scale == FE_SCALE_COUNTER) &&
1242  (cmd.props[1].u.st.stat[0].uvalue != 0))
1243  {
1244  value = static_cast<double>(
1245  static_cast<long double>(cmd.props[0].u.st.stat[0].uvalue) /
1246  cmd.props[1].u.st.stat[0].uvalue);
1247  }
1248  }
1249  else
1250  {
1251  LOG(VB_RECORD, LOG_ERR, LOC +
1252  "Getting DVBv5 Frontend bit error rate failed." + ENO);
1253  }
1254  return value;
1255 }
1256 
1257 // documented in dvbchannel.h
1258 double DVBChannel::GetBitErrorRate(bool *ok) const
1259 {
1260  DVBChannel *master = GetMasterLock();
1261  if (master != this)
1262  {
1263  double val = master->GetBitErrorRate(ok);
1264  ReturnMasterLock(master);
1265  return val;
1266  }
1267  ReturnMasterLock(master); // if we're the master we don't need this lock..
1268 
1269  uint32_t ber = 0;
1270  int ret = ioctl(m_fdFrontend, FE_READ_BER, &ber);
1271  if (ret < 0)
1272  {
1273  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1274  {
1275  return GetBitErrorRateDVBv5(ok);
1276  }
1277  LOG(VB_RECORD, LOG_ERR, LOC +
1278  "Getting Frontend bit error rate failed." + ENO);
1279  }
1280 
1281  if (ok)
1282  *ok = (0 == ret);
1283 
1284  return (double) ber;
1285 }
1286 
1287 // documented in dvbchannel.h
1289 {
1290  struct dtv_property prop = {};
1291  struct dtv_properties cmd = {};
1292 
1293  prop.cmd = DTV_STAT_ERROR_BLOCK_COUNT;
1294  cmd.num = 1;
1295  cmd.props = &prop;
1296  int ret = ioctl(m_fdFrontend, FE_GET_PROPERTY, &cmd);
1297  LOG(VB_RECORD, LOG_DEBUG, LOC +
1298  QString("FE DTV uncorrected block count ret=%1 res=%2 len=%3 scale=%4 val=%5")
1299  .arg(ret)
1300  .arg(cmd.props[0].result)
1301  .arg(cmd.props[0].u.st.len)
1302  .arg(cmd.props[0].u.st.stat[0].scale)
1303  .arg(cmd.props[0].u.st.stat[0].svalue)
1304  );
1305  bool tmpOk = (ret == 0) && (cmd.props->u.st.len > 0);
1306  if (ok)
1307  *ok = tmpOk;
1308  double value = 0;
1309  if (tmpOk)
1310  {
1311  if (cmd.props->u.st.stat[0].scale == FE_SCALE_COUNTER)
1312  value = cmd.props->u.st.stat[0].uvalue;
1313  }
1314  else
1315  {
1316  LOG(VB_RECORD, LOG_DEBUG, LOC +
1317  "Getting DVBv5 Frontend uncorrected block count failed." + ENO);
1318  }
1319  return value;
1320 }
1321 
1322 // documented in dvbchannel.h
1324 {
1325  DVBChannel *master = GetMasterLock();
1326  if (master != this)
1327  {
1328  double val = master->GetUncorrectedBlockCount(ok);
1329  ReturnMasterLock(master);
1330  return val;
1331  }
1332  ReturnMasterLock(master); // if we're the master we don't need this lock..
1333 
1334  uint32_t ublocks = 0;
1335  int ret = ioctl(m_fdFrontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
1336  if (ret < 0)
1337  {
1338  if (errno == EOPNOTSUPP || errno == ENOTSUPP)
1339  {
1340  return GetUncorrectedBlockCountDVBv5(ok);
1341  }
1342  LOG(VB_GENERAL, LOG_ERR, LOC +
1343  "Getting Frontend uncorrected block count failed." + ENO);
1344  }
1345 
1346  if (ok)
1347  *ok = (0 == ret);
1348 
1349  return (double) ublocks;
1350 }
1351 
1353 {
1354  auto *chan = static_cast<DTVChannel*>(dvbm);
1356  dvbm = nullptr;
1357 }
1358 
1360 {
1362  if (m_pParent)
1363  key += QString(":%1")
1365  DTVChannel *master = DTVChannel::GetMasterLock(key);
1366  auto *dvbm = dynamic_cast<DVBChannel*>(master);
1367  if (master && !dvbm)
1369  return dvbm;
1370 }
1371 
1372 bool DVBChannel::IsMaster(void) const
1373 {
1374  DVBChannel *master = GetMasterLock();
1375  bool is_master = (master == this);
1376  ReturnMasterLock(master);
1377  return is_master;
1378 }
1379 
1384 static void drain_dvb_events(int fd)
1385 {
1386  struct dvb_frontend_event event {};
1387  int ret = 0;
1388  while ((ret = ioctl(fd, FE_GET_EVENT, &event)) == 0);
1389  if ((ret < 0) && (EAGAIN != errno))
1390  {
1391  LOG(VB_CHANNEL, LOG_DEBUG, "Draining DVB Event failed. " + ENO);
1392  }
1393 }
1394 
1418 static bool wait_for_backend(int fd, int timeout_ms)
1419 {
1420  struct timeval select_timeout = { timeout_ms/1000, (timeout_ms % 1000) * 1000 /*usec*/};
1421  fd_set fd_select_set;
1422  FD_ZERO( &fd_select_set); // NOLINT(readability-isolate-declaration)
1423  FD_SET (fd, &fd_select_set);
1424 
1425  // Try to wait for some output like an event, unfortunately
1426  // this fails on several DVB cards, so we have a timeout.
1427  int ret = 0;
1428  do ret = select(fd+1, &fd_select_set, nullptr, nullptr, &select_timeout);
1429  while ((-1 == ret) && (EINTR == errno));
1430 
1431  if (-1 == ret)
1432  {
1433  LOG(VB_GENERAL, LOG_ERR,
1434  "DVBChan: wait_for_backend: Failed to wait on output" + ENO);
1435 
1436  return false;
1437  }
1438 
1439  // This is supposed to work on all cards, post 2.6.12...
1440 #if ((DVB_API_VERSION > 5) || ((DVB_API_VERSION == 5) && (DVB_API_VERSION_MINOR > 10)))
1441  fe_status_t status = FE_NONE;
1442 #else // debian9, centos7
1443  fe_status_t status = (fe_status_t)0;
1444 #endif
1445  memset(&status, 0, sizeof(status));
1446 
1447  if (ioctl(fd, FE_READ_STATUS, &status) < 0)
1448  {
1449  LOG(VB_GENERAL, LOG_ERR,
1450  "DVBChan: wait_for_backend: Failed to get status" + ENO);
1451 
1452  return false;
1453  }
1454 
1455  LOG(VB_CHANNEL, LOG_INFO, QString("DVBChan: wait_for_backend: Status: %1")
1456  .arg(toString(status)));
1457 
1458  return true;
1459 }
1460 
1461 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
1462  DTVTunerType tuner_type, const DTVMultiplex &tuning,
1463  int intermediate_freq, bool can_fec_auto)
1464 {
1465  dvb_frontend_parameters params {};
1466 
1467  params.frequency = tuning.m_frequency;
1468  params.inversion = (fe_spectral_inversion_t) (int) tuning.m_inversion;
1469 
1470  if (DTVTunerType::kTunerTypeDVBS1 == tuner_type)
1471  {
1472  if (tuning.m_modSys == DTVModulationSystem::kModulationSystem_DVBS2)
1473  {
1474  LOG(VB_GENERAL, LOG_ERR,
1475  "DVBChan: Error, Tuning of a DVB-S2 transport "
1476  "with a DVB-S card will fail.");
1477  }
1478 
1479  params.frequency = intermediate_freq;
1480  params.u.qpsk.symbol_rate = tuning.m_symbolRate;
1481  params.u.qpsk.fec_inner = can_fec_auto ? FEC_AUTO
1482  : (fe_code_rate_t) (int) tuning.m_fec;
1483  }
1484 
1485  if (DTVTunerType::kTunerTypeDVBS2 == tuner_type)
1486  {
1487  LOG(VB_GENERAL, LOG_ERR,
1488  "DVBChan: Error, MythTV was compiled without "
1489  "DVB-S2 headers being present so DVB-S2 tuning will fail.");
1490  }
1491 
1492  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1493  {
1494  params.u.qam.symbol_rate = tuning.m_symbolRate;
1495  params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.m_fec;
1496  params.u.qam.modulation = (fe_modulation_t) (int) tuning.m_modulation;
1497  }
1498 
1499  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1500  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1501  {
1502  params.u.ofdm.bandwidth =
1503  (fe_bandwidth_t) (int) tuning.m_bandwidth;
1504  params.u.ofdm.code_rate_HP =
1505  (fe_code_rate_t) (int) tuning.m_hpCodeRate;
1506  params.u.ofdm.code_rate_LP =
1507  (fe_code_rate_t) (int) tuning.m_lpCodeRate;
1508  params.u.ofdm.constellation =
1509  (fe_modulation_t) (int) tuning.m_modulation;
1510  params.u.ofdm.transmission_mode =
1511  (fe_transmit_mode_t) (int) tuning.m_transMode;
1512  params.u.ofdm.guard_interval =
1513  (fe_guard_interval_t) (int) tuning.m_guardInterval;
1514  params.u.ofdm.hierarchy_information =
1515  (fe_hierarchy_t) (int) tuning.m_hierarchy;
1516  }
1517 
1518  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1519  {
1520  params.u.vsb.modulation =
1521  (fe_modulation_t) (int) tuning.m_modulation;
1522  }
1523 
1524  return params;
1525 }
1526 
1528  DTVTunerType tuner_type, const dvb_frontend_parameters &params)
1529 {
1530  DTVMultiplex tuning;
1531 
1532  tuning.m_frequency = params.frequency;
1533  tuning.m_inversion = params.inversion;
1534 
1535  if ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
1536  (DTVTunerType::kTunerTypeDVBS2 == tuner_type))
1537  {
1538  tuning.m_symbolRate = params.u.qpsk.symbol_rate;
1539  tuning.m_fec = params.u.qpsk.fec_inner;
1540  }
1541 
1542  if (DTVTunerType::kTunerTypeDVBC == tuner_type)
1543  {
1544  tuning.m_symbolRate = params.u.qam.symbol_rate;
1545  tuning.m_fec = params.u.qam.fec_inner;
1546  tuning.m_modulation = params.u.qam.modulation;
1547  }
1548 
1549  if (DTVTunerType::kTunerTypeDVBT == tuner_type ||
1550  DTVTunerType::kTunerTypeDVBT2 == tuner_type)
1551  {
1552  tuning.m_bandwidth = params.u.ofdm.bandwidth;
1553  tuning.m_hpCodeRate = params.u.ofdm.code_rate_HP;
1554  tuning.m_lpCodeRate = params.u.ofdm.code_rate_LP;
1555  tuning.m_modulation = params.u.ofdm.constellation;
1556  tuning.m_transMode = params.u.ofdm.transmission_mode;
1557  tuning.m_guardInterval = params.u.ofdm.guard_interval;
1558  tuning.m_hierarchy = params.u.ofdm.hierarchy_information;
1559  }
1560 
1561  if (DTVTunerType::kTunerTypeATSC == tuner_type)
1562  {
1563  tuning.m_modulation = params.u.vsb.modulation;
1564  }
1565 
1566  return tuning;
1567 }
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
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:1075
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
double GetBitErrorRate(bool *ok=nullptr) const
Returns # of corrected bits since last call. First call undefined.
DTVMultiplex m_prevTuning
Last tuning options Tune() succesfully sent to hardware.
Definition: dvbchannel.h:151
void Open(int fd_frontend, bool is_SCR)
Retrieve device tree.
Definition: diseqc.cpp:798
DiSEqCDevTree * m_diseqcTree
Definition: dvbchannel.h:132
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:735
DVBCam * m_dvbCam
Used to decrypt encrypted streams.
Definition: dvbchannel.h:134
DTVGuardInterval m_guardInterval
Definition: dtvmultiplex.h:102
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
static QReadWriteLock s_master_map_lock
Definition: dtvchannel.h:180
bool m_hasCrcBug
true iff our driver munges PMT
Definition: dvbchannel.h:167
bool IsMaster(void) const override
Returns true if this is the first of a number of multi-rec devs.
uint m_inputId
Definition: channelbase.h:137
uint64_t m_symbolRate
Definition: dtvmultiplex.h:95
static DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:239
static const int kTunerTypeDVBT
uint GetDeviceID(void) const
Definition: diseqc.h:164
~DVBChannel() override
Definition: dvbchannel.cpp:101
uint64_t m_capabilities
Definition: dvbchannel.h:138
#define O_NONBLOCK
Definition: mythmedia.cpp:25
int GetChanID(void) const override
Returns Channel ID.
Definition: dvbchannel.cpp:953
DTVBandwidth m_bandwidth
Definition: dtvmultiplex.h:97
TVRec * m_pParent
Definition: channelbase.h:134
void CheckFrequency(uint64_t frequency) const
Checks tuning frequency.
Definition: dvbchannel.cpp:333
QString toString(MarkTypes type)
static const int kTunerTypeATSC
uint m_sigMonDelay
Minimum delay between FE_LOCK checks.
Definition: dvbchannel.h:158
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:577
bool IsRunning(void) const
Definition: dvbcam.h:31
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
DVBChannel * GetMasterLock(void) const
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
uint m_symbolRateMinimum
Definition: dvbchannel.h:142
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:234
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:29
int64_t concurrent_tunings_delay
Definition: dvbchannel.cpp:66
double GetUncorrectedBlockCountDVBv5(bool *ok) const
Get Uncorrected Block Count from the DVBv5 interface.
bool Start(void)
Definition: dvbcam.cpp:88
DTVInversion m_inversion
Definition: dtvmultiplex.h:96
uint64_t m_extModulations
Definition: dvbchannel.h:139
static const int kTunerTypeDVBS1
QString toString() const
QString m_frontendName
Definition: dvbchannel.h:137
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
uint64_t m_frequencyMinimum
Definition: dvbchannel.h:140
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:120
bool Retune(void) override
Definition: dvbchannel.cpp:841
bool m_firstTune
Used to force hardware reset.
Definition: dvbchannel.h:160
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:554
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
static const int kTunerTypeDVBS2
DTVModulation m_modulation
Definition: dtvmultiplex.h:100
QMutex m_tuneLock
Definition: dvbchannel.h:146
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
DVBChannel(QString device, TVRec *parent=nullptr)
Definition: dvbchannel.cpp:76
bool IsEqual(DTVTunerType type, const DTVMultiplex &other, uint freq_range=0, bool fuzzy=false) const
MSqlQuery query(MSqlQuery::InitCon())
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:142
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:14
DiSEqCDevSCR * FindSCR(const DiSEqCDevSettings &settings)
Returns the SCR device object selected by the configuration chain.
Definition: diseqc.cpp:600
QString m_curChannelName
Definition: channelbase.h:135
static DTVChannel * GetMasterLock(const QString &key)
Definition: dtvchannel.cpp:135
static QDateTime s_lastTuning
Definition: dvbchannel.h:169
bool isActive(void) const
Definition: mythdbcon.h:204
Rotor class.
Definition: diseqc.h:295
bool ProbeTuningParams(DTVMultiplex &tuning) const
Fetches DTVMultiplex params from driver.
Definition: dvbchannel.cpp:895
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).
void SetPMT(const ProgramMapTable *pmt)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:495
uint32_t GetIntermediateFrequency(uint32_t frequency) const
Definition: diseqc.cpp:2246
uint32_t GetIntermediateFrequency(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning) const
Calculate proper intermediate frequency for the given settings and tuning parameters.
Definition: diseqc.cpp:2553
QString m_device
DVB Device.
Definition: dvbchannel.h:165
void SetTimeOffset(double offset_in_seconds)
Definition: dvbcam.cpp:320
static bool wait_for_backend(int fd, int timeout_ms)
Waits for backend to get tune message.
unsigned int uint
Definition: compat.h:140
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=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:69
QMutex m_hwLock
Definition: dvbchannel.h:147
DTVTransmitMode m_transMode
Definition: dtvmultiplex.h:101
QString m_sistandard
Definition: dtvmultiplex.h:111
QMutex m_tuneDelayLock
Definition: dvbchannel.h:170
#define LOC
Definition: dvbchannel.cpp:69
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
static void ReturnMasterLock(DVBChannel *&dvbm)
DTVRollOff m_rolloff
Definition: dtvmultiplex.h:107
bool IsDiSEqCSupported(void) const
void SetSIStandard(const QString &si_std)
Sets PSIP table standard: MPEG, DVB, ATSC, or OpenCable.
Definition: dtvchannel.cpp:50
bool Tune(const DTVMultiplex &tuning) override
This performs the actual frequency tuning and in some cases input switching.
Definition: dvbchannel.cpp:513
unsigned short uint16_t
Definition: iso6937tables.h:1
bool Execute(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
Applies settings to the entire tree.
Definition: diseqc.cpp:513
static DTVTunerType ProbeTunerType(int fd_frontend)
Definition: cardutil.cpp:800
double GetSNR(bool *ok=nullptr) const
Returns signal/noise in the range [0..1.0].
int m_fdFrontend
File descriptor for tuning hardware.
Definition: dvbchannel.h:164
Unicable / SCR Class.
Definition: diseqc.h:375
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
static void ReturnMasterLock(DTVChannelP &chan)
Definition: dtvchannel.cpp:147
LNB Class.
Definition: diseqc.h:440
bool IsTuningParamsProbeSupported(void) const
Returns true iff tuning info probing is working.
Definition: dvbchannel.cpp:849
void Close(void) override
Closes the channel changing hardware to use.
Definition: dvbchannel.h:37
DTVCodeRate m_hpCodeRate
High Priority FEC rate.
Definition: dtvmultiplex.h:98
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:1769
bool CheckCodeRate(DTVCodeRate rate) const
Return true iff rate is supported rate on the frontend.
Definition: dvbchannel.cpp:451
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
uint m_tuningDelay
Extra delay to add for broken drivers.
Definition: dvbchannel.h:156
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
uint m_symbolRateMaximum
Definition: dvbchannel.h:143
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
DiSEqCDevSettings m_diseqcSettings
Definition: dvbchannel.h:131
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:666
IsOpenMap m_isOpen
Definition: dvbchannel.h:128
uint64_t m_frequencyMaximum
Definition: dvbchannel.h:141
uint m_lastLnbDevId
Definition: dvbchannel.h:153
#define ENOTSUPP
Definition: dvbchannel.cpp:55
DTVCodeRate m_lpCodeRate
Low Priority FEC rate.
Definition: dtvmultiplex.h:99
virtual bool InitializeInput(void)
Fills in input map from DB.
DTVMultiplex m_desiredTuning
Last tuning options Tune() attempted to send to hardware.
Definition: dvbchannel.h:149
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:742
DTVModulationSystem m_modSys
Modulation system.
Definition: dtvmultiplex.h:106
uint64_t m_frequency
Definition: dtvmultiplex.h:94
void SetPMT(const ChannelBase *chan, const ProgramMapTable *pmt)
Definition: dvbcam.cpp:287
bool IsModulationVariable(void) const
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23