00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <fcntl.h>
00036 #include <unistd.h>
00037 #include <sys/poll.h>
00038 #include <sys/select.h>
00039 #include <sys/time.h>
00040 #include <sys/types.h>
00041
00042
00043 #include "mythconfig.h"
00044 #include "mythdb.h"
00045 #include "cardutil.h"
00046 #include "channelutil.h"
00047 #include "dvbtypes.h"
00048 #include "dvbchannel.h"
00049 #include "dvbcam.h"
00050
00051 static void drain_dvb_events(int fd);
00052 static bool wait_for_backend(int fd, int timeout_ms);
00053 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
00054 DTVTunerType, const DTVMultiplex&, int intermediate_freq, bool can_fec_auto);
00055 static DTVMultiplex dvbparams_to_dtvmultiplex(
00056 DTVTunerType, const dvb_frontend_parameters&);
00057
00058 #define LOC QString("DVBChan(%1:%2): ").arg(GetCardID()).arg(device)
00059
00065 DVBChannel::DVBChannel(const QString &aDevice, TVRec *parent)
00066 : DTVChannel(parent),
00067
00068 diseqc_tree(NULL), dvbcam(NULL),
00069
00070 frontend_name(QString::null),
00071
00072 tune_lock(), hw_lock(QMutex::Recursive),
00073 last_lnb_dev_id(-1),
00074 tuning_delay(0), sigmon_delay(25),
00075 first_tune(true),
00076
00077 fd_frontend(-1), device(aDevice),
00078 has_crc_bug(false)
00079 {
00080 master_map_lock.lockForWrite();
00081 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
00082 master_map[devname].push_back(this);
00083 DVBChannel *master = dynamic_cast<DVBChannel*>(master_map[devname].front());
00084 if (master == this)
00085 {
00086 dvbcam = new DVBCam(device);
00087 has_crc_bug = CardUtil::HasDVBCRCBug(device);
00088 }
00089 else
00090 {
00091 dvbcam = master->dvbcam;
00092 has_crc_bug = master->has_crc_bug;
00093 }
00094 master_map_lock.unlock();
00095
00096 sigmon_delay = CardUtil::GetMinSignalMonitoringDelay(device);
00097 }
00098
00099 DVBChannel::~DVBChannel()
00100 {
00101
00102
00103 master_map_lock.lockForWrite();
00104 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
00105 DVBChannel *master = dynamic_cast<DVBChannel*>(master_map[devname].front());
00106 if (master == this)
00107 {
00108 master_map[devname].pop_front();
00109 DVBChannel *new_master = NULL;
00110 if (!master_map[devname].empty())
00111 new_master = dynamic_cast<DVBChannel*>(master_map[devname].front());
00112 if (new_master)
00113 new_master->is_open = master->is_open;
00114 }
00115 else
00116 {
00117 master_map[devname].removeAll(this);
00118 }
00119 master_map_lock.unlock();
00120
00121 Close();
00122
00123
00124 master_map_lock.lockForRead();
00125 MasterMap::iterator mit = master_map.find(devname);
00126 if ((*mit).empty())
00127 delete dvbcam;
00128 dvbcam = NULL;
00129 master_map_lock.unlock();
00130
00131
00132 }
00133
00134 void DVBChannel::Close(DVBChannel *who)
00135 {
00136 LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel");
00137
00138 IsOpenMap::iterator it = is_open.find(who);
00139 if (it == is_open.end())
00140 return;
00141
00142 is_open.erase(it);
00143
00144 QMutexLocker locker(&hw_lock);
00145
00146 DVBChannel *master = GetMasterLock();
00147 if (master != NULL && master != this)
00148 {
00149 if (dvbcam->IsRunning())
00150 dvbcam->SetPMT(this, NULL);
00151 master->Close(this);
00152 fd_frontend = -1;
00153 ReturnMasterLock(master);
00154 return;
00155 }
00156 ReturnMasterLock(master);
00157
00158 if (!is_open.empty())
00159 return;
00160
00161 if (diseqc_tree)
00162 diseqc_tree->Close();
00163
00164 if (fd_frontend >= 0)
00165 {
00166 close(fd_frontend);
00167 fd_frontend = -1;
00168
00169 dvbcam->Stop();
00170 }
00171 }
00172
00173 bool DVBChannel::Open(DVBChannel *who)
00174 {
00175 LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel");
00176
00177 QMutexLocker locker(&hw_lock);
00178
00179 if (fd_frontend >= 0)
00180 {
00181 is_open[who] = true;
00182 return true;
00183 }
00184
00185 DVBChannel *master = GetMasterLock();
00186 if (master != this)
00187 {
00188 if (!master->Open(who))
00189 {
00190 ReturnMasterLock(master);
00191 return false;
00192 }
00193
00194 fd_frontend = master->fd_frontend;
00195 frontend_name = master->frontend_name;
00196 tunerType = master->tunerType;
00197 capabilities = master->capabilities;
00198 ext_modulations = master->ext_modulations;
00199 frequency_minimum = master->frequency_minimum;
00200 frequency_maximum = master->frequency_maximum;
00201 symbol_rate_minimum = master->symbol_rate_minimum;
00202 symbol_rate_maximum = master->symbol_rate_maximum;
00203
00204 is_open[who] = true;
00205
00206 if (!InitializeInputs())
00207 {
00208 Close();
00209 ReturnMasterLock(master);
00210 return false;
00211 }
00212
00213 ReturnMasterLock(master);
00214 return true;
00215 }
00216 ReturnMasterLock(master);
00217
00218 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
00219 QByteArray devn = devname.toAscii();
00220
00221 for (int tries = 1; ; ++tries)
00222 {
00223 fd_frontend = open(devn.constData(), O_RDWR | O_NONBLOCK);
00224 if (fd_frontend >= 0)
00225 break;
00226 LOG(VB_GENERAL, LOG_WARNING, LOC +
00227 "Opening DVB frontend device failed." + ENO);
00228 if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
00229 {
00230 LOG(VB_GENERAL, LOG_ERR, LOC +
00231 QString("Failed to open DVB frontend device due to "
00232 "fatal error or too many attempts."));
00233 return false;
00234 }
00235 usleep(50000);
00236 }
00237
00238 dvb_frontend_info info;
00239 memset(&info, 0, sizeof(info));
00240 if (ioctl(fd_frontend, FE_GET_INFO, &info) < 0)
00241 {
00242 LOG(VB_GENERAL, LOG_ERR, LOC +
00243 "Failed to get frontend information." + ENO);
00244
00245 close(fd_frontend);
00246 fd_frontend = -1;
00247 return false;
00248 }
00249
00250 frontend_name = info.name;
00251 tunerType = info.type;
00252 #if HAVE_FE_CAN_2G_MODULATION
00253 if (tunerType == DTVTunerType::kTunerTypeDVBS1 &&
00254 (info.caps & FE_CAN_2G_MODULATION))
00255 tunerType = DTVTunerType::kTunerTypeDVBS2;
00256 #endif // HAVE_FE_CAN_2G_MODULATION
00257 capabilities = info.caps;
00258 frequency_minimum = info.frequency_min;
00259 frequency_maximum = info.frequency_max;
00260 symbol_rate_minimum = info.symbol_rate_min;
00261 symbol_rate_maximum = info.symbol_rate_max;
00262
00263 LOG(VB_RECORD, LOG_INFO, LOC +
00264 QString("Using DVB card %1, with frontend '%2'.")
00265 .arg(device).arg(frontend_name));
00266
00267
00268 if (tunerType.IsDiSEqCSupported())
00269 {
00270 diseqc_tree = diseqc_dev.FindTree(GetCardID());
00271 if (diseqc_tree)
00272 diseqc_tree->Open(fd_frontend);
00273 }
00274
00275 dvbcam->Start();
00276
00277 first_tune = true;
00278
00279 if (!InitializeInputs())
00280 {
00281 Close();
00282 return false;
00283 }
00284
00285 if (fd_frontend >= 0)
00286 is_open[who] = true;
00287
00288 return (fd_frontend >= 0);
00289 }
00290
00291 bool DVBChannel::IsOpen(void) const
00292 {
00293 IsOpenMap::const_iterator it = is_open.find(this);
00294 return it != is_open.end();
00295 }
00296
00297 bool DVBChannel::Init(QString &inputname, QString &startchannel, bool setchan)
00298 {
00299 if (setchan && !IsOpen())
00300 Open(this);
00301
00302 return ChannelBase::Init(inputname, startchannel, setchan);
00303 }
00304
00305 bool DVBChannel::SwitchToInput(const QString &inputname, const QString &chan)
00306 {
00307 int input = GetInputByName(inputname);
00308
00309 bool ok = false;
00310 if (input >= 0)
00311 {
00312 m_currentInputID = input;
00313 ok = SetChannelByString(chan);
00314 }
00315 else
00316 {
00317 LOG(VB_GENERAL, LOG_ERR, LOC +
00318 QString("DVBChannel: Could not find input: %1 on card when "
00319 "setting channel %2\n").arg(inputname).arg(chan));
00320 }
00321 return ok;
00322 }
00323
00324 bool DVBChannel::SwitchToInput(int newInputNum, bool setstarting)
00325 {
00326 if (!ChannelBase::SwitchToInput(newInputNum, false))
00327 return false;
00328
00329 m_currentInputID = newInputNum;
00330 InputMap::const_iterator it = m_inputs.find(m_currentInputID);
00331 return SetChannelByString((*it)->startChanNum);
00332 }
00333
00334
00338 void DVBChannel::CheckFrequency(uint64_t frequency) const
00339 {
00340 if (frequency_minimum && frequency_maximum &&
00341 (frequency_minimum <= frequency_maximum) &&
00342 (frequency < frequency_minimum || frequency > frequency_maximum))
00343 {
00344 LOG(VB_GENERAL, LOG_WARNING, LOC +
00345 QString("Your frequency setting (%1) is out of range. "
00346 "(min/max:%2/%3)")
00347 .arg(frequency).arg(frequency_minimum).arg(frequency_maximum));
00348 }
00349 }
00350
00351 void DVBChannel::CheckOptions(DTVMultiplex &tuning) const
00352 {
00353 if ((tuning.inversion == DTVInversion::kInversionAuto) &&
00354 !(capabilities & FE_CAN_INVERSION_AUTO))
00355 {
00356 LOG(VB_GENERAL, LOG_WARNING, LOC +
00357 "'Auto' inversion parameter unsupported by this driver, "
00358 "falling back to 'off'.");
00359 tuning.inversion = DTVInversion::kInversionOff;
00360 }
00361
00362
00363 if (!diseqc_tree)
00364 CheckFrequency(tuning.frequency);
00365
00366 if (tunerType.IsFECVariable() &&
00367 symbol_rate_minimum && symbol_rate_maximum &&
00368 (symbol_rate_minimum <= symbol_rate_maximum) &&
00369 (tuning.symbolrate < symbol_rate_minimum ||
00370 tuning.symbolrate > symbol_rate_maximum))
00371 {
00372 LOG(VB_GENERAL, LOG_WARNING, LOC +
00373 QString("Symbol Rate setting (%1) is out of range (min/max:%2/%3)")
00374 .arg(tuning.symbolrate)
00375 .arg(symbol_rate_minimum).arg(symbol_rate_maximum));
00376 }
00377
00378 if (tunerType.IsFECVariable() && !CheckCodeRate(tuning.fec))
00379 {
00380 LOG(VB_GENERAL, LOG_WARNING, LOC +
00381 "Selected fec_inner parameter unsupported by this driver.");
00382 }
00383
00384 if (tunerType.IsModulationVariable() && !CheckModulation(tuning.modulation))
00385 {
00386 LOG(VB_GENERAL, LOG_WARNING, LOC +
00387 "Selected modulation parameter unsupported by this driver.");
00388 }
00389
00390 if (DTVTunerType::kTunerTypeDVBT != tunerType)
00391 {
00392 LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
00393 return;
00394 }
00395
00396
00397
00398 if (!CheckCodeRate(tuning.hp_code_rate))
00399 {
00400 LOG(VB_GENERAL, LOG_WARNING, LOC +
00401 "Selected code_rate_hp parameter unsupported by this driver.");
00402 }
00403
00404 if (!CheckCodeRate(tuning.lp_code_rate))
00405 {
00406 LOG(VB_GENERAL, LOG_WARNING, LOC +
00407 "Selected code_rate_lp parameter unsupported by this driver.");
00408 }
00409
00410 if ((tuning.bandwidth == DTVBandwidth::kBandwidthAuto) &&
00411 !(capabilities & FE_CAN_BANDWIDTH_AUTO))
00412 {
00413 LOG(VB_GENERAL, LOG_WARNING, LOC +
00414 "'Auto' bandwidth parameter unsupported by this driver.");
00415 }
00416
00417 if ((tuning.trans_mode == DTVTransmitMode::kTransmissionModeAuto) &&
00418 !(capabilities & FE_CAN_TRANSMISSION_MODE_AUTO))
00419 {
00420 LOG(VB_GENERAL, LOG_WARNING, LOC +
00421 "'Auto' transmission_mode parameter unsupported by this driver.");
00422 }
00423
00424 if ((tuning.guard_interval == DTVGuardInterval::kGuardIntervalAuto) &&
00425 !(capabilities & FE_CAN_GUARD_INTERVAL_AUTO))
00426 {
00427 LOG(VB_GENERAL, LOG_WARNING, LOC +
00428 "'Auto' guard_interval parameter unsupported by this driver.");
00429 }
00430
00431 if ((tuning.hierarchy == DTVHierarchy::kHierarchyAuto) &&
00432 !(capabilities & FE_CAN_HIERARCHY_AUTO))
00433 {
00434 LOG(VB_GENERAL, LOG_WARNING, LOC +
00435 "'Auto' hierarchy parameter unsupported by this driver. ");
00436 }
00437
00438 if (!CheckModulation(tuning.modulation))
00439 {
00440 LOG(VB_GENERAL, LOG_WARNING, LOC +
00441 "Selected modulation parameter unsupported by this driver.");
00442 }
00443
00444 LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString());
00445 }
00446
00450 bool DVBChannel::CheckCodeRate(DTVCodeRate rate) const
00451 {
00452 const uint64_t caps = capabilities;
00453 return
00454 ((DTVCodeRate::kFECNone == rate)) ||
00455 ((DTVCodeRate::kFEC_1_2 == rate) && (caps & FE_CAN_FEC_1_2)) ||
00456 ((DTVCodeRate::kFEC_2_3 == rate) && (caps & FE_CAN_FEC_2_3)) ||
00457 ((DTVCodeRate::kFEC_3_4 == rate) && (caps & FE_CAN_FEC_3_4)) ||
00458 ((DTVCodeRate::kFEC_4_5 == rate) && (caps & FE_CAN_FEC_4_5)) ||
00459 ((DTVCodeRate::kFEC_5_6 == rate) && (caps & FE_CAN_FEC_5_6)) ||
00460 ((DTVCodeRate::kFEC_6_7 == rate) && (caps & FE_CAN_FEC_6_7)) ||
00461 ((DTVCodeRate::kFEC_7_8 == rate) && (caps & FE_CAN_FEC_7_8)) ||
00462 ((DTVCodeRate::kFEC_8_9 == rate) && (caps & FE_CAN_FEC_8_9)) ||
00463 ((DTVCodeRate::kFECAuto == rate) && (caps & FE_CAN_FEC_AUTO));
00464 }
00465
00469 bool DVBChannel::CheckModulation(DTVModulation modulation) const
00470 {
00471 const DTVModulation m = modulation;
00472 const uint64_t c = capabilities;
00473
00474 return
00475 ((DTVModulation::kModulationQPSK == m) && (c & FE_CAN_QPSK)) ||
00476 #if HAVE_FE_CAN_2G_MODULATION
00477 ((DTVModulation::kModulation8PSK == m) && (c & FE_CAN_2G_MODULATION)) ||
00478 #endif
00479 ((DTVModulation::kModulationQAM16 == m) && (c & FE_CAN_QAM_16)) ||
00480 ((DTVModulation::kModulationQAM32 == m) && (c & FE_CAN_QAM_32)) ||
00481 ((DTVModulation::kModulationQAM64 == m) && (c & FE_CAN_QAM_64)) ||
00482 ((DTVModulation::kModulationQAM128 == m) && (c & FE_CAN_QAM_128)) ||
00483 ((DTVModulation::kModulationQAM256 == m) && (c & FE_CAN_QAM_256)) ||
00484 ((DTVModulation::kModulationQAMAuto == m) && (c & FE_CAN_QAM_AUTO)) ||
00485 ((DTVModulation::kModulation8VSB == m) && (c & FE_CAN_8VSB)) ||
00486 ((DTVModulation::kModulation16VSB == m) && (c & FE_CAN_16VSB));
00487 }
00488
00492 void DVBChannel::SetPMT(const ProgramMapTable *pmt)
00493 {
00494 if (pmt && dvbcam->IsRunning())
00495 dvbcam->SetPMT(this, pmt);
00496 }
00497
00502 void DVBChannel::SetTimeOffset(double offset)
00503 {
00504 if (dvbcam->IsRunning())
00505 dvbcam->SetTimeOffset(offset);
00506 }
00507
00508
00509 bool DVBChannel::Tune(const DTVMultiplex &tuning, QString inputname)
00510 {
00511 int inputid = inputname.isEmpty() ?
00512 m_currentInputID : GetInputByName(inputname);
00513 if (inputid < 0)
00514 {
00515 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Tune(): Invalid input '%1'.")
00516 .arg(inputname));
00517 return false;
00518 }
00519 return Tune(tuning, inputid, false, false);
00520 }
00521
00522 #if DVB_API_VERSION >= 5
00523 static struct dtv_properties *dtvmultiplex_to_dtvproperties(
00524 DTVTunerType tuner_type, const DTVMultiplex &tuning, int intermediate_freq,
00525 bool can_fec_auto, bool do_tune = true)
00526 {
00527 uint c = 0;
00528 struct dtv_properties *cmdseq;
00529
00530 if (tuner_type != DTVTunerType::kTunerTypeDVBT &&
00531 tuner_type != DTVTunerType::kTunerTypeDVBC &&
00532 tuner_type != DTVTunerType::kTunerTypeDVBS1 &&
00533 tuner_type != DTVTunerType::kTunerTypeDVBS2)
00534 {
00535 LOG(VB_GENERAL, LOG_ERR, "DVBChan: Unsupported tuner type " +
00536 tuner_type.toString());
00537 return NULL;
00538 }
00539
00540 cmdseq = (struct dtv_properties*) calloc(1, sizeof(*cmdseq));
00541 if (!cmdseq)
00542 return NULL;
00543
00544 cmdseq->props = (struct dtv_property*) calloc(11, sizeof(*(cmdseq->props)));
00545 if (!(cmdseq->props))
00546 {
00547 free(cmdseq);
00548 return NULL;
00549 }
00550
00551
00552
00553 if (tuning.mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
00554 can_fec_auto = false;
00555
00556 if (tuner_type == DTVTunerType::kTunerTypeDVBS2)
00557 {
00558 cmdseq->props[c].cmd = DTV_DELIVERY_SYSTEM;
00559 cmdseq->props[c++].u.data = tuning.mod_sys;
00560 }
00561
00562 cmdseq->props[c].cmd = DTV_FREQUENCY;
00563 cmdseq->props[c++].u.data = intermediate_freq ? intermediate_freq : tuning.frequency;
00564 cmdseq->props[c].cmd = DTV_MODULATION;
00565 cmdseq->props[c++].u.data = tuning.modulation;
00566 cmdseq->props[c].cmd = DTV_INVERSION;
00567 cmdseq->props[c++].u.data = tuning.inversion;
00568
00569 if (tuner_type == DTVTunerType::kTunerTypeDVBS1 ||
00570 tuner_type == DTVTunerType::kTunerTypeDVBS2 ||
00571 tuner_type == DTVTunerType::kTunerTypeDVBC)
00572 {
00573 cmdseq->props[c].cmd = DTV_SYMBOL_RATE;
00574 cmdseq->props[c++].u.data = tuning.symbolrate;
00575 }
00576
00577 if (tuner_type.IsFECVariable())
00578 {
00579 cmdseq->props[c].cmd = DTV_INNER_FEC;
00580 cmdseq->props[c++].u.data = can_fec_auto ? FEC_AUTO : tuning.fec;
00581 }
00582
00583 if (tuner_type == DTVTunerType::kTunerTypeDVBT)
00584 {
00585 cmdseq->props[c].cmd = DTV_BANDWIDTH_HZ;
00586 cmdseq->props[c++].u.data = (8-tuning.bandwidth) * 1000000;
00587 cmdseq->props[c].cmd = DTV_CODE_RATE_HP;
00588 cmdseq->props[c++].u.data = tuning.hp_code_rate;
00589 cmdseq->props[c].cmd = DTV_CODE_RATE_LP;
00590 cmdseq->props[c++].u.data = tuning.lp_code_rate;
00591 cmdseq->props[c].cmd = DTV_TRANSMISSION_MODE;
00592 cmdseq->props[c++].u.data = tuning.trans_mode;
00593 cmdseq->props[c].cmd = DTV_GUARD_INTERVAL;
00594 cmdseq->props[c++].u.data = tuning.guard_interval;
00595 cmdseq->props[c].cmd = DTV_HIERARCHY;
00596 cmdseq->props[c++].u.data = tuning.hierarchy;
00597 }
00598
00599 if (tuning.mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
00600 {
00601 cmdseq->props[c].cmd = DTV_PILOT;
00602 cmdseq->props[c++].u.data = PILOT_AUTO;
00603 cmdseq->props[c].cmd = DTV_ROLLOFF;
00604 cmdseq->props[c++].u.data = tuning.rolloff;
00605 }
00606 else if (tuning.mod_sys == DTVModulationSystem::kModulationSystem_DVBS)
00607 {
00608 cmdseq->props[c].cmd = DTV_ROLLOFF;
00609 cmdseq->props[c++].u.data = DTVRollOff::kRollOff_35;
00610 }
00611
00612 if (do_tune)
00613 cmdseq->props[c++].cmd = DTV_TUNE;
00614
00615 cmdseq->num = c;
00616
00617 return cmdseq;
00618 }
00619 #endif
00620
00621
00622
00623
00624
00625
00638 bool DVBChannel::Tune(const DTVMultiplex &tuning,
00639 uint inputid,
00640 bool force_reset,
00641 bool same_input)
00642 {
00643 QMutexLocker lock(&tune_lock);
00644 QMutexLocker locker(&hw_lock);
00645
00646 DVBChannel *master = GetMasterLock();
00647 if (master != this)
00648 {
00649 LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel");
00650 SetSIStandard(tuning.sistandard);
00651 bool ok = master->Tune(tuning, inputid, force_reset, false);
00652 ReturnMasterLock(master);
00653 return ok;
00654 }
00655 ReturnMasterLock(master);
00656
00657
00658 int intermediate_freq = 0;
00659 bool can_fec_auto = false;
00660 bool reset = (force_reset || first_tune);
00661
00662 if (tunerType.IsDiSEqCSupported() && !diseqc_tree)
00663 {
00664 LOG(VB_GENERAL, LOG_ERR, LOC +
00665 "DVB-S needs device tree for LNB handling");
00666 return false;
00667 }
00668
00669 desired_tuning = tuning;
00670
00671 if (fd_frontend < 0)
00672 {
00673 LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!");
00674
00675 return false;
00676 }
00677
00678
00679 drain_dvb_events(fd_frontend);
00680
00681
00682 if (diseqc_tree)
00683 {
00684
00685 if (!same_input)
00686 diseqc_settings.Load(inputid);
00687
00688
00689 if (!diseqc_tree->Execute(diseqc_settings, tuning))
00690 {
00691 LOG(VB_GENERAL, LOG_ERR, LOC +
00692 "Tune(): Failed to setup DiSEqC devices");
00693 return false;
00694 }
00695
00696
00697 DiSEqCDevLNB *lnb = diseqc_tree->FindLNB(diseqc_settings);
00698 if (!lnb)
00699 {
00700 LOG(VB_GENERAL, LOG_ERR, LOC +
00701 "Tune(): No LNB for this configuration");
00702 return false;
00703 }
00704
00705 if (lnb->GetDeviceID() != last_lnb_dev_id)
00706 {
00707 last_lnb_dev_id = lnb->GetDeviceID();
00708
00709 reset = first_tune = true;
00710 }
00711
00712 intermediate_freq = lnb->GetIntermediateFrequency(
00713 diseqc_settings, tuning);
00714
00715
00716 if (capabilities & FE_CAN_FEC_AUTO)
00717 can_fec_auto = true;
00718
00719
00720
00721 CheckFrequency(intermediate_freq);
00722 }
00723
00724 LOG(VB_CHANNEL, LOG_INFO, LOC + "Old Params: " + prev_tuning.toString() +
00725 "\n\t\t\t" + LOC + "New Params: " + tuning.toString());
00726
00727
00728 bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tunerType) ||
00729 (DTVTunerType::kTunerTypeDVBS2 == tunerType));
00730 int freq_mult = (is_dvbs) ? 1 : 1000;
00731 QString suffix = (is_dvbs) ? "kHz" : "Hz";
00732
00733 if (reset || !prev_tuning.IsEqual(tunerType, tuning, 500 * freq_mult))
00734 {
00735 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2")
00736 .arg(intermediate_freq ? intermediate_freq : tuning.frequency)
00737 .arg(suffix));
00738
00739 #if DVB_API_VERSION >=5
00740 if (DTVTunerType::kTunerTypeDVBS2 == tunerType)
00741 {
00742 struct dtv_property p_clear;
00743 struct dtv_properties cmdseq_clear;
00744
00745 p_clear.cmd = DTV_CLEAR;
00746 cmdseq_clear.num = 1;
00747 cmdseq_clear.props = &p_clear;
00748
00749 if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0)
00750 {
00751 LOG(VB_GENERAL, LOG_ERR, LOC +
00752 "Tune(): Clearing DTV properties cache failed." + ENO);
00753 return false;
00754 }
00755
00756 struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties(
00757 tunerType, tuning, intermediate_freq, can_fec_auto);
00758
00759 if (!cmds) {
00760 LOG(VB_GENERAL, LOG_ERR, LOC +
00761 "Failed to convert DTVMultiplex to DTV_PROPERTY sequence");
00762 return false;
00763 }
00764
00765 if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG))
00766 {
00767 for (uint i = 0; i < cmds->num; i++)
00768 {
00769 LOG(VB_CHANNEL, LOG_DEBUG, LOC +
00770 QString("prop %1: cmd = %2, data %3")
00771 .arg(i).arg(cmds->props[i].cmd)
00772 .arg(cmds->props[i].u.data));
00773 }
00774 }
00775
00776 int res = ioctl(fd_frontend, FE_SET_PROPERTY, cmds);
00777
00778 free(cmds->props);
00779 free(cmds);
00780
00781 if (res < 0)
00782 {
00783 LOG(VB_GENERAL, LOG_ERR, LOC +
00784 "Tune(): Setting Frontend tuning parameters failed." + ENO);
00785 return false;
00786 }
00787 }
00788 else
00789 #endif
00790 {
00791 struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams(
00792 tunerType, tuning, intermediate_freq, can_fec_auto);
00793
00794 if (ioctl(fd_frontend, FE_SET_FRONTEND, ¶ms) < 0)
00795 {
00796 LOG(VB_GENERAL, LOG_ERR, LOC +
00797 "Tune(): Setting Frontend tuning parameters failed." + ENO);
00798 return false;
00799 }
00800 }
00801
00802
00803 if (tuning_delay)
00804 usleep(tuning_delay * 1000);
00805
00806 wait_for_backend(fd_frontend, 5 );
00807
00808 prev_tuning = tuning;
00809 first_tune = false;
00810 }
00811
00812 SetSIStandard(tuning.sistandard);
00813
00814 LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful.");
00815
00816 return true;
00817 }
00818
00819 bool DVBChannel::Retune(void)
00820 {
00821 return Tune(desired_tuning, m_currentInputID, true, true);
00822 }
00823
00824 QString DVBChannel::GetFrontendName(void) const
00825 {
00826 QString tmp = frontend_name;
00827 tmp.detach();
00828 return tmp;
00829 }
00830
00834 bool DVBChannel::IsTuningParamsProbeSupported(void) const
00835 {
00836 QMutexLocker locker(&hw_lock);
00837
00838 if (fd_frontend < 0)
00839 {
00840 LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
00841
00842 return false;
00843 }
00844
00845 const DVBChannel *master = GetMasterLock();
00846 if (master != this)
00847 {
00848 bool ok = master->IsTuningParamsProbeSupported();
00849 ReturnMasterLock(master);
00850 return ok;
00851 }
00852 ReturnMasterLock(master);
00853
00854 if (diseqc_tree)
00855 {
00856
00857
00858
00859 return false;
00860 }
00861
00862 dvb_frontend_parameters params;
00863
00864 int res = ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms);
00865 if (res < 0)
00866 {
00867 LOG(VB_CHANNEL, LOG_ERR, LOC + "Getting device frontend failed." + ENO);
00868 }
00869
00870 return (res >= 0);
00871 }
00872
00880 bool DVBChannel::ProbeTuningParams(DTVMultiplex &tuning) const
00881 {
00882 QMutexLocker locker(&hw_lock);
00883
00884 if (fd_frontend < 0)
00885 {
00886 LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!");
00887
00888 return false;
00889 }
00890
00891 const DVBChannel *master = GetMasterLock();
00892 if (master != this)
00893 {
00894 bool ok = master->ProbeTuningParams(tuning);
00895 ReturnMasterLock(master);
00896 return ok;
00897 }
00898 ReturnMasterLock(master);
00899
00900 if (diseqc_tree)
00901 {
00902
00903
00904
00905 return false;
00906 }
00907
00908 if (tunerType == DTVTunerType::kTunerTypeDVBS2)
00909 {
00910
00911 return false;
00912 }
00913
00914 dvb_frontend_parameters params;
00915 if (ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms) < 0)
00916 {
00917 LOG(VB_GENERAL, LOG_ERR, LOC +
00918 "Getting Frontend tuning parameters failed." + ENO);
00919
00920 return false;
00921 }
00922
00923 uint mplex = tuning.mplex;
00924 QString sistandard = tuning.sistandard; sistandard.detach();
00925
00926 tuning = dvbparams_to_dtvmultiplex(tunerType, params);
00927
00928 tuning.mplex = mplex;
00929 tuning.sistandard = sistandard;
00930
00931 return true;
00932 }
00933
00938 int DVBChannel::GetChanID() const
00939 {
00940 int cardid = GetCardID();
00941
00942 MSqlQuery query(MSqlQuery::InitCon());
00943
00944 query.prepare("SELECT chanid "
00945 "FROM channel, cardinput "
00946 "WHERE cardinput.sourceid = channel.sourceid AND "
00947 " channel.channum = :CHANNUM AND "
00948 " cardinput.cardid = :CARDID");
00949
00950 query.bindValue(":CHANNUM", m_curchannelname);
00951 query.bindValue(":CARDID", cardid);
00952
00953 if (!query.exec() || !query.isActive())
00954 {
00955 MythDB::DBError("fetching chanid", query);
00956 return -1;
00957 }
00958
00959 if (!query.next())
00960 return -1;
00961
00962 return query.value(0).toInt();
00963 }
00964
00965 const DiSEqCDevRotor *DVBChannel::GetRotor(void) const
00966 {
00967 if (diseqc_tree)
00968 return diseqc_tree->FindRotor(diseqc_settings);
00969
00970 return NULL;
00971 }
00972
00973
00974 bool DVBChannel::HasLock(bool *ok) const
00975 {
00976 const DVBChannel *master = GetMasterLock();
00977 if (master != this)
00978 {
00979 bool haslock = master->HasLock(ok);
00980 ReturnMasterLock(master);
00981 return haslock;
00982 }
00983 ReturnMasterLock(master);
00984
00985 fe_status_t status;
00986 memset(&status, 0, sizeof(status));
00987
00988 int ret = ioctl(fd_frontend, FE_READ_STATUS, &status);
00989 if (ret < 0)
00990 {
00991 LOG(VB_GENERAL, LOG_ERR, LOC +
00992 "Getting Frontend status failed." + ENO);
00993 }
00994
00995 if (ok)
00996 *ok = (0 == ret);
00997
00998 return status & FE_HAS_LOCK;
00999 }
01000
01001
01002 double DVBChannel::GetSignalStrength(bool *ok) const
01003 {
01004 const DVBChannel *master = GetMasterLock();
01005 if (master != this)
01006 {
01007 double val = master->GetSignalStrength(ok);
01008 ReturnMasterLock(master);
01009 return val;
01010 }
01011 ReturnMasterLock(master);
01012
01013
01014
01015 uint16_t sig = 0;
01016
01017 int ret = ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig);
01018 if (ret < 0)
01019 {
01020 LOG(VB_GENERAL, LOG_ERR, LOC +
01021 "Getting Frontend signal strength failed." + ENO);
01022 }
01023
01024 if (ok)
01025 *ok = (0 == ret);
01026
01027 return sig * (1.0 / 65535.0);
01028 }
01029
01030
01031 double DVBChannel::GetSNR(bool *ok) const
01032 {
01033 const DVBChannel *master = GetMasterLock();
01034 if (master != this)
01035 {
01036 double val = master->GetSNR(ok);
01037 ReturnMasterLock(master);
01038 return val;
01039 }
01040 ReturnMasterLock(master);
01041
01042
01043
01044
01045 uint16_t snr = 0;
01046 int ret = ioctl(fd_frontend, FE_READ_SNR, &snr);
01047 if (ret < 0)
01048 {
01049 LOG(VB_GENERAL, LOG_ERR, LOC +
01050 "Getting Frontend signal/noise ratio failed." + ENO);
01051 }
01052
01053 if (ok)
01054 *ok = (0 == ret);
01055
01056 return snr * (1.0 / 65535.0);
01057 }
01058
01059
01060 double DVBChannel::GetBitErrorRate(bool *ok) const
01061 {
01062 const DVBChannel *master = GetMasterLock();
01063 if (master != this)
01064 {
01065 double val = master->GetBitErrorRate(ok);
01066 ReturnMasterLock(master);
01067 return val;
01068 }
01069 ReturnMasterLock(master);
01070
01071 uint32_t ber = 0;
01072 int ret = ioctl(fd_frontend, FE_READ_BER, &ber);
01073 if (ret < 0)
01074 {
01075 LOG(VB_GENERAL, LOG_ERR, LOC +
01076 "Getting Frontend signal error rate failed." + ENO);
01077 }
01078
01079 if (ok)
01080 *ok = (0 == ret);
01081
01082 return (double) ber;
01083 }
01084
01085
01086 double DVBChannel::GetUncorrectedBlockCount(bool *ok) const
01087 {
01088 const DVBChannel *master = GetMasterLock();
01089 if (master != this)
01090 {
01091 double val = master->GetUncorrectedBlockCount(ok);
01092 ReturnMasterLock(master);
01093 return val;
01094 }
01095 ReturnMasterLock(master);
01096
01097 uint32_t ublocks = 0;
01098 int ret = ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
01099 if (ret < 0)
01100 {
01101 LOG(VB_GENERAL, LOG_ERR, LOC +
01102 "Getting Frontend uncorrected block count failed." + ENO);
01103 }
01104
01105 if (ok)
01106 *ok = (0 == ret);
01107
01108 return (double) ublocks;
01109 }
01110
01111 DVBChannel *DVBChannel::GetMasterLock(void)
01112 {
01113 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
01114 DTVChannel *master = DTVChannel::GetMasterLock(devname);
01115 DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
01116 if (master && !dvbm)
01117 DTVChannel::ReturnMasterLock(master);
01118 return dvbm;
01119 }
01120
01121 void DVBChannel::ReturnMasterLock(DVBChannelP &dvbm)
01122 {
01123 DTVChannel *chan = static_cast<DTVChannel*>(dvbm);
01124 DTVChannel::ReturnMasterLock(chan);
01125 dvbm = NULL;
01126 }
01127
01128 const DVBChannel *DVBChannel::GetMasterLock(void) const
01129 {
01130 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
01131 DTVChannel *master = DTVChannel::GetMasterLock(devname);
01132 DVBChannel *dvbm = dynamic_cast<DVBChannel*>(master);
01133 if (master && !dvbm)
01134 DTVChannel::ReturnMasterLock(master);
01135 return dvbm;
01136 }
01137
01138 void DVBChannel::ReturnMasterLock(DVBChannelCP &dvbm)
01139 {
01140 DTVChannel *chan =
01141 static_cast<DTVChannel*>(const_cast<DVBChannel*>(dvbm));
01142 DTVChannel::ReturnMasterLock(chan);
01143 dvbm = NULL;
01144 }
01145
01146 bool DVBChannel::IsMaster(void) const
01147 {
01148 const DVBChannel *master = GetMasterLock();
01149 bool is_master = (master == this);
01150 ReturnMasterLock(master);
01151 return is_master;
01152 }
01153
01158 static void drain_dvb_events(int fd)
01159 {
01160 struct dvb_frontend_event event;
01161 int ret = 0;
01162 while ((ret = ioctl(fd, FE_GET_EVENT, &event)) == 0);
01163 if (ret < 0)
01164 {
01165 LOG(VB_CHANNEL, LOG_DEBUG, "Draining DVB Event failed. " + ENO);
01166 }
01167 }
01168
01192 static bool wait_for_backend(int fd, int timeout_ms)
01193 {
01194 struct timeval select_timeout = { 0, (timeout_ms % 1000) * 1000 };
01195 fd_set fd_select_set;
01196 FD_ZERO( &fd_select_set);
01197 FD_SET (fd, &fd_select_set);
01198
01199
01200
01201 int ret = 0;
01202 do ret = select(fd+1, &fd_select_set, NULL, NULL, &select_timeout);
01203 while ((-1 == ret) && (EINTR == errno));
01204
01205 if (-1 == ret)
01206 {
01207 LOG(VB_GENERAL, LOG_ERR,
01208 "DVBChan: wait_for_backend: Failed to wait on output" + ENO);
01209
01210 return false;
01211 }
01212
01213
01214 fe_status_t status;
01215 if (ioctl(fd, FE_READ_STATUS, &status) < 0)
01216 {
01217 LOG(VB_GENERAL, LOG_ERR,
01218 "DVBChan: wait_for_backend: Failed to get status" + ENO);
01219
01220 return false;
01221 }
01222
01223 LOG(VB_CHANNEL, LOG_INFO, QString("DVBChan: wait_for_backend: Status: %1")
01224 .arg(toString(status)));
01225
01226 return true;
01227 }
01228
01229 static struct dvb_frontend_parameters dtvmultiplex_to_dvbparams(
01230 DTVTunerType tuner_type, const DTVMultiplex &tuning,
01231 int intermediate_freq, bool can_fec_auto)
01232 {
01233 dvb_frontend_parameters params;
01234 memset(¶ms, 0, sizeof(params));
01235
01236 params.frequency = tuning.frequency;
01237 params.inversion = (fe_spectral_inversion_t) (int) tuning.inversion;
01238
01239 if (DTVTunerType::kTunerTypeDVBS1 == tuner_type)
01240 {
01241 if (tuning.mod_sys == DTVModulationSystem::kModulationSystem_DVBS2)
01242 LOG(VB_GENERAL, LOG_ERR,
01243 "DVBChan: Error, Tuning of a DVB-S2 transport "
01244 "with a DVB-S card will fail.");
01245
01246 params.frequency = intermediate_freq;
01247 params.u.qpsk.symbol_rate = tuning.symbolrate;
01248 params.u.qpsk.fec_inner = can_fec_auto ? FEC_AUTO
01249 : (fe_code_rate_t) (int) tuning.fec;
01250 }
01251
01252 if (DTVTunerType::kTunerTypeDVBS2 == tuner_type)
01253 {
01254 LOG(VB_GENERAL, LOG_ERR,
01255 "DVBChan: Error, MythTV was compiled without "
01256 "DVB-S2 headers being present so DVB-S2 tuning will fail.");
01257 }
01258
01259 if (DTVTunerType::kTunerTypeDVBC == tuner_type)
01260 {
01261 params.u.qam.symbol_rate = tuning.symbolrate;
01262 params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.fec;
01263 params.u.qam.modulation = (fe_modulation_t) (int) tuning.modulation;
01264 }
01265
01266 if (DTVTunerType::kTunerTypeDVBT == tuner_type)
01267 {
01268 params.u.ofdm.bandwidth =
01269 (fe_bandwidth_t) (int) tuning.bandwidth;
01270 params.u.ofdm.code_rate_HP =
01271 (fe_code_rate_t) (int) tuning.hp_code_rate;
01272 params.u.ofdm.code_rate_LP =
01273 (fe_code_rate_t) (int) tuning.lp_code_rate;
01274 params.u.ofdm.constellation =
01275 (fe_modulation_t) (int) tuning.modulation;
01276 params.u.ofdm.transmission_mode =
01277 (fe_transmit_mode_t) (int) tuning.trans_mode;
01278 params.u.ofdm.guard_interval =
01279 (fe_guard_interval_t) (int) tuning.guard_interval;
01280 params.u.ofdm.hierarchy_information =
01281 (fe_hierarchy_t) (int) tuning.hierarchy;
01282 }
01283
01284 if (DTVTunerType::kTunerTypeATSC == tuner_type)
01285 {
01286 params.u.vsb.modulation =
01287 (fe_modulation_t) (int) tuning.modulation;
01288 }
01289
01290 return params;
01291 }
01292
01293 static DTVMultiplex dvbparams_to_dtvmultiplex(
01294 DTVTunerType tuner_type, const dvb_frontend_parameters ¶ms)
01295 {
01296 DTVMultiplex tuning;
01297
01298 tuning.frequency = params.frequency;
01299 tuning.inversion = params.inversion;
01300
01301 if ((DTVTunerType::kTunerTypeDVBS1 == tuner_type) ||
01302 (DTVTunerType::kTunerTypeDVBS2 == tuner_type))
01303 {
01304 tuning.symbolrate = params.u.qpsk.symbol_rate;
01305 tuning.fec = params.u.qpsk.fec_inner;
01306 }
01307
01308 if (DTVTunerType::kTunerTypeDVBC == tuner_type)
01309 {
01310 tuning.symbolrate = params.u.qam.symbol_rate;
01311 tuning.fec = params.u.qam.fec_inner;
01312 tuning.modulation = params.u.qam.modulation;
01313 }
01314
01315 if (DTVTunerType::kTunerTypeDVBT == tuner_type)
01316 {
01317 tuning.bandwidth = params.u.ofdm.bandwidth;
01318 tuning.hp_code_rate = params.u.ofdm.code_rate_HP;
01319 tuning.lp_code_rate = params.u.ofdm.code_rate_LP;
01320 tuning.modulation = params.u.ofdm.constellation;
01321 tuning.trans_mode = params.u.ofdm.transmission_mode;
01322 tuning.guard_interval = params.u.ofdm.guard_interval;
01323 tuning.hierarchy = params.u.ofdm.hierarchy_information;
01324 }
01325
01326 if (DTVTunerType::kTunerTypeATSC == tuner_type)
01327 {
01328 tuning.modulation = params.u.vsb.modulation;
01329 }
01330
01331 return tuning;
01332 }