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 "mythcontext.h"
00044 #include "mythdbcon.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_fe_params dtvmultiplex_to_dvbparams(
00054 DTVTunerType, const DTVMultiplex&);
00055 static DTVMultiplex dvbparams_to_dtvmultiplex(
00056 DTVTunerType, const dvb_fe_params&);
00057
00058 #define LOC QString("DVBChan(%1:%2): ").arg(GetCardID()).arg(cardnum)
00059 #define LOC_WARN QString("DVBChan(%1:%2) Warning: ") \
00060 .arg(GetCardID()).arg(cardnum)
00061 #define LOC_ERR QString("DVBChan(%1:%2) Error: ").arg(GetCardID()).arg(cardnum)
00062
00068 DVBChannel::DVBChannel(int aCardNum, TVRec *parent)
00069 : DTVChannel(parent), master(NULL),
00070
00071 diseqc_tree(NULL), dvbcam(NULL),
00072
00073 frontend_name(QString::null), card_type(DTVTunerType::kTunerTypeUnknown),
00074
00075 tune_lock(false), hw_lock(false),
00076 last_lnb_dev_id(-1),
00077 tuning_delay(0), sigmon_delay(25),
00078 first_tune(true),
00079
00080 fd_frontend(-1), cardnum(aCardNum),
00081 has_crc_bug(false)
00082 {
00083 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, cardnum);
00084 master = dynamic_cast<DVBChannel*>(GetMaster(devname));
00085 master = (master == this) ? NULL : master;
00086
00087 if (!master)
00088 {
00089 dvbcam = new DVBCam(cardnum);
00090 has_crc_bug = CardUtil::HasDVBCRCBug(aCardNum);
00091 }
00092 else
00093 {
00094 dvbcam = master->dvbcam;
00095 has_crc_bug = master->has_crc_bug;
00096 }
00097
00098 sigmon_delay = CardUtil::GetMinSignalMonitoringDelay(aCardNum);
00099 }
00100
00101 DVBChannel::~DVBChannel()
00102 {
00103 Close();
00104
00105 if (dvbcam && !master)
00106 {
00107 delete dvbcam;
00108 dvbcam = NULL;
00109 }
00110
00111
00112 }
00113
00114 void DVBChannel::Close(DVBChannel *who)
00115 {
00116 VERBOSE(VB_CHANNEL, LOC + "Closing DVB channel");
00117
00118 IsOpenMap::iterator it = is_open.find(who);
00119 if (it == is_open.end())
00120 return;
00121
00122 is_open.remove(it);
00123
00124 if (master)
00125 {
00126 QMutexLocker locker(&hw_lock);
00127 if (dvbcam->IsRunning())
00128 dvbcam->SetPMT(this, NULL);
00129 master->Close(this);
00130 fd_frontend = -1;
00131 return;
00132 }
00133
00134 if (!is_open.empty())
00135 return;
00136
00137 if (diseqc_tree)
00138 diseqc_tree->Close();
00139
00140 QMutexLocker locker(&hw_lock);
00141 if (fd_frontend >= 0)
00142 {
00143 close(fd_frontend);
00144 fd_frontend = -1;
00145
00146 dvbcam->Stop();
00147 }
00148 }
00149
00150 bool DVBChannel::Open(DVBChannel *who)
00151 {
00152 VERBOSE(VB_CHANNEL, LOC + "Opening DVB channel");
00153
00154 QMutexLocker locker(&hw_lock);
00155
00156 if (fd_frontend >= 0)
00157 {
00158 is_open[who] = true;
00159 return true;
00160 }
00161
00162 if (master)
00163 {
00164 if (!master->Open(who))
00165 return false;
00166
00167 fd_frontend = master->fd_frontend;
00168 frontend_name = master->frontend_name;
00169 card_type = master->card_type;
00170 capabilities = master->capabilities;
00171 ext_modulations = master->ext_modulations;
00172 frequency_minimum = master->frequency_minimum;
00173 frequency_maximum = master->frequency_maximum;
00174 symbol_rate_minimum = master->symbol_rate_minimum;
00175 symbol_rate_maximum = master->symbol_rate_maximum;
00176
00177 is_open[who] = true;
00178
00179 if (!InitializeInputs())
00180 {
00181 Close();
00182 return false;
00183 }
00184
00185 nextInputID = currentInputID;
00186
00187 return true;
00188 }
00189
00190 QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, cardnum);
00191 fd_frontend = open(devname.ascii(), O_RDWR | O_NONBLOCK);
00192
00193 if (fd_frontend < 0)
00194 {
00195 VERBOSE(VB_IMPORTANT, LOC_ERR +
00196 "Opening DVB frontend device failed." + ENO);
00197
00198 return false;
00199 }
00200
00201 dvb_frontend_info info;
00202 bzero(&info, sizeof(info));
00203 if (ioctl(fd_frontend, FE_GET_INFO, &info) < 0)
00204 {
00205 VERBOSE(VB_IMPORTANT, LOC_ERR +
00206 "Failed to get frontend information." + ENO);
00207
00208 close(fd_frontend);
00209 fd_frontend = -1;
00210 return false;
00211 }
00212
00213 #ifdef FE_GET_EXTENDED_INFO
00214 if (info.caps & FE_HAS_EXTENDED_INFO)
00215 {
00216 bool ok = true;
00217 dvb_fe_caps_extended extinfo;
00218 bzero(&extinfo, sizeof(extinfo));
00219 if (ioctl(fd_frontend, FE_GET_EXTENDED_INFO, &extinfo) < 0)
00220 {
00221 VERBOSE(VB_IMPORTANT, LOC_ERR +
00222 "Failed to get frontend extended information." + ENO);
00223
00224 ok = false;
00225 }
00226
00227 if (ok && (extinfo.modulations & MOD_8PSK))
00228 {
00229 if (ioctl(fd_frontend, FE_SET_STANDARD, FE_DVB_S2) < 0)
00230 {
00231 VERBOSE(VB_IMPORTANT, LOC_ERR +
00232 "Failed to set frontend standard to DVB-S2." + ENO);
00233
00234 ok = false;
00235 }
00236 else if (ioctl(fd_frontend, FE_GET_INFO, &info) < 0)
00237 {
00238 VERBOSE(VB_IMPORTANT, LOC_ERR +
00239 "Failed to get frontend information." + ENO);
00240
00241 ok = false;
00242 }
00243 }
00244
00245 if (!ok)
00246 {
00247 close(fd_frontend);
00248 fd_frontend = -1;
00249 return false;
00250 }
00251
00252 ext_modulations = extinfo.modulations;
00253 }
00254 #endif
00255
00256 frontend_name = info.name;
00257 card_type = info.type;
00258 capabilities = info.caps;
00259 frequency_minimum = info.frequency_min;
00260 frequency_maximum = info.frequency_max;
00261 symbol_rate_minimum = info.symbol_rate_min;
00262 symbol_rate_maximum = info.symbol_rate_max;
00263
00264 VERBOSE(VB_RECORD, LOC + QString("Using DVB card %1, with frontend '%2'.")
00265 .arg(cardnum).arg(frontend_name));
00266
00267
00268 if (card_type == DTVTunerType::kTunerTypeQPSK ||
00269 card_type == DTVTunerType::kTunerTypeDVB_S2)
00270 {
00271 diseqc_tree = diseqc_dev.FindTree(GetCardID());
00272 if (diseqc_tree)
00273 diseqc_tree->Open(fd_frontend);
00274 }
00275
00276 dvbcam->Start();
00277
00278 first_tune = true;
00279
00280 if (!InitializeInputs())
00281 {
00282 Close();
00283 return false;
00284 }
00285
00286 nextInputID = currentInputID;
00287
00288 if (fd_frontend >= 0)
00289 is_open[who] = true;
00290
00291 return (fd_frontend >= 0);
00292 }
00293
00294 bool DVBChannel::IsOpen(void) const
00295 {
00296 IsOpenMap::const_iterator it = is_open.find(this);
00297 return it != is_open.end();
00298 }
00299
00300 bool DVBChannel::Init(QString &inputname, QString &startchannel, bool setchan)
00301 {
00302 if (setchan && !IsOpen())
00303 Open(this);
00304
00305 return ChannelBase::Init(inputname, startchannel, setchan);
00306 }
00307
00308
00309 bool DVBChannel::TuneMultiplex(uint mplexid, QString inputname)
00310 {
00311 DTVMultiplex tuning;
00312 if (!tuning.FillFromDB(card_type, mplexid))
00313 return false;
00314
00315 CheckOptions(tuning);
00316
00317 return Tune(tuning, inputname);
00318 }
00319
00320 bool DVBChannel::SetChannelByString(const QString &channum)
00321 {
00322 QString tmp = QString("SetChannelByString(%1): ").arg(channum);
00323 QString loc = LOC + tmp;
00324 QString loc_err = LOC_ERR + tmp;
00325
00326 VERBOSE(VB_CHANNEL, loc);
00327
00328 if (!IsOpen())
00329 {
00330 VERBOSE(VB_IMPORTANT, loc_err + "Channel object "
00331 "will not open, can not change channels.");
00332
00333 ClearDTVInfo();
00334 return false;
00335 }
00336
00337 ClearDTVInfo();
00338
00339 QString inputName;
00340 if (!CheckChannel(channum, inputName))
00341 {
00342 VERBOSE(VB_IMPORTANT, loc_err +
00343 "CheckChannel failed.\n\t\t\tPlease verify the channel "
00344 "in the 'mythtv-setup' Channel Editor.");
00345
00346 return false;
00347 }
00348
00349
00350 if (!inputName.isEmpty() && (nextInputID == currentInputID))
00351 nextInputID = GetInputByName(inputName);
00352
00353
00354 int inputid = (nextInputID >= 0) ? nextInputID : currentInputID;
00355 InputMap::const_iterator it = inputs.find(inputid);
00356 if (it == inputs.end())
00357 return false;
00358
00359 uint mplexid_restriction;
00360 if (!IsInputAvailable(inputid, mplexid_restriction))
00361 {
00362 VERBOSE(VB_IMPORTANT, loc_err + "Input is not available");
00363 return false;
00364 }
00365
00366
00367 QString tvformat, modulation, freqtable, freqid, si_std;
00368 int finetune;
00369 uint64_t frequency;
00370 int mpeg_prog_num;
00371 uint atsc_major, atsc_minor, mplexid, tsid, netid;
00372
00373 if (!ChannelUtil::GetChannelData(
00374 (*it)->sourceid, channum,
00375 tvformat, modulation, freqtable, freqid,
00376 finetune, frequency,
00377 si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
00378 mplexid, commfree))
00379 {
00380 VERBOSE(VB_IMPORTANT, loc_err +
00381 "Unable to find channel in database.");
00382
00383 return false;
00384 }
00385
00386 if (mplexid_restriction && (mplexid != mplexid_restriction))
00387 {
00388 VERBOSE(VB_IMPORTANT, loc_err + "Multiplex is not available");
00389 return false;
00390 }
00391
00392
00393 DTVMultiplex tuning;
00394 if (!mplexid || !tuning.FillFromDB(card_type, mplexid))
00395 {
00396 VERBOSE(VB_IMPORTANT, loc_err +
00397 "Failed to initialize multiplex options");
00398
00399 return false;
00400 }
00401
00402 SetDTVInfo(atsc_major, atsc_minor, netid, tsid, mpeg_prog_num);
00403
00404
00405 CheckOptions(tuning);
00406
00407 if (!Tune(tuning, inputid))
00408 {
00409 VERBOSE(VB_IMPORTANT, loc_err + "Tuning to frequency.");
00410
00411 ClearDTVInfo();
00412 return false;
00413 }
00414
00415 curchannelname = QDeepCopy<QString>(channum);
00416
00417 VERBOSE(VB_CHANNEL, loc + "Tuned to frequency.");
00418
00419 currentInputID = nextInputID;
00420 inputs[currentInputID]->startChanNum = QDeepCopy<QString>(curchannelname);
00421
00422 return true;
00423 }
00424
00425 bool DVBChannel::SwitchToInput(const QString &inputname, const QString &chan)
00426 {
00427 int input = GetInputByName(inputname);
00428
00429 bool ok = false;
00430 if (input >= 0)
00431 {
00432 nextInputID = input;
00433 ok = SetChannelByString(chan);
00434 }
00435 else
00436 {
00437 VERBOSE(VB_IMPORTANT,
00438 QString("DVBChannel: Could not find input: %1 on card when "
00439 "setting channel %2\n").arg(inputname).arg(chan));
00440 }
00441 return ok;
00442 }
00443
00444 bool DVBChannel::SwitchToInput(int newInputNum, bool setstarting)
00445 {
00446 (void)setstarting;
00447
00448 InputMap::const_iterator it = inputs.find(newInputNum);
00449 if (it == inputs.end() || (*it)->startChanNum.isEmpty())
00450 return false;
00451
00452 uint mplexid_restriction;
00453 if (!IsInputAvailable(currentInputID, mplexid_restriction))
00454 return false;
00455
00456 nextInputID = newInputNum;
00457
00458 return SetChannelByString((*it)->startChanNum);
00459 }
00460
00464 void DVBChannel::CheckOptions(DTVMultiplex &tuning) const
00465 {
00466 if ((tuning.inversion == DTVInversion::kInversionAuto) &&
00467 !(capabilities & FE_CAN_INVERSION_AUTO))
00468 {
00469 VERBOSE(VB_GENERAL, LOC_WARN +
00470 "Unsupported inversion option 'auto', "
00471 "falling back to 'off'");
00472
00473 tuning.inversion = DTVInversion::kInversionAuto;
00474 }
00475
00476 uint64_t frequency = tuning.frequency;
00477 if (diseqc_tree)
00478 {
00479 DiSEqCDevLNB* lnb = diseqc_tree->FindLNB(diseqc_settings);
00480 if (lnb)
00481 frequency = lnb->GetIntermediateFrequency(diseqc_settings, tuning);
00482 }
00483
00484 if (frequency_minimum && frequency_maximum &&
00485 (frequency_minimum <= frequency_maximum) &&
00486 (frequency < frequency_minimum || frequency > frequency_maximum))
00487 {
00488 VERBOSE(VB_GENERAL, LOC_WARN +
00489 QString("Your frequency setting (%1) is "
00490 "out of range. (min/max:%2/%3)")
00491 .arg(frequency)
00492 .arg(frequency_minimum).arg(frequency_maximum));
00493 }
00494
00495 if (card_type.IsFECVariable() &&
00496 symbol_rate_minimum && symbol_rate_maximum &&
00497 (symbol_rate_minimum <= symbol_rate_maximum) &&
00498 (tuning.symbolrate < symbol_rate_minimum ||
00499 tuning.symbolrate > symbol_rate_maximum))
00500 {
00501 VERBOSE(VB_GENERAL, LOC_WARN +
00502 QString("Symbol Rate setting (%1) is "
00503 "out of range (min/max:%2/%3)")
00504 .arg(tuning.symbolrate)
00505 .arg(symbol_rate_minimum).arg(symbol_rate_maximum));
00506 }
00507
00508 if (card_type.IsFECVariable() && !CheckCodeRate(tuning.fec))
00509 {
00510 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported fec_inner parameter.");
00511 }
00512
00513 if (card_type.IsModulationVariable() && !CheckModulation(tuning.modulation))
00514 {
00515 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported modulation parameter.");
00516 }
00517
00518 if (DTVTunerType::kTunerTypeOFDM != card_type)
00519 {
00520 VERBOSE(VB_CHANNEL, LOC + tuning.toString());
00521 return;
00522 }
00523
00524
00525
00526 if (!CheckCodeRate(tuning.hp_code_rate))
00527 {
00528 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported code_rate_hp parameter.");
00529 }
00530
00531 if (!CheckCodeRate(tuning.lp_code_rate))
00532 {
00533 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported code_rate_lp parameter.");
00534 }
00535
00536 if ((tuning.bandwidth == DTVBandwidth::kBandwidthAuto) &&
00537 !(capabilities & FE_CAN_BANDWIDTH_AUTO))
00538 {
00539 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported bandwidth parameter.");
00540 }
00541
00542 if ((tuning.trans_mode == DTVTransmitMode::kTransmissionModeAuto) &&
00543 !(capabilities & FE_CAN_TRANSMISSION_MODE_AUTO))
00544 {
00545 VERBOSE(VB_GENERAL, LOC_WARN +
00546 "Unsupported transmission_mode parameter.");
00547 }
00548
00549 if ((tuning.guard_interval == DTVGuardInterval::kGuardIntervalAuto) &&
00550 !(capabilities & FE_CAN_GUARD_INTERVAL_AUTO))
00551 {
00552 VERBOSE(VB_GENERAL, LOC_WARN +
00553 "Unsupported guard_interval parameter.");
00554 }
00555
00556 if ((tuning.hierarchy == DTVHierarchy::kHierarchyAuto) &&
00557 !(capabilities & FE_CAN_HIERARCHY_AUTO))
00558 {
00559 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported hierarchy parameter.");
00560 }
00561
00562 if (!CheckModulation(tuning.modulation))
00563 {
00564 VERBOSE(VB_GENERAL, LOC_WARN + "Unsupported constellation parameter.");
00565 }
00566
00567 VERBOSE(VB_CHANNEL, LOC + tuning.toString());
00568 }
00569
00573 bool DVBChannel::CheckCodeRate(DTVCodeRate rate) const
00574 {
00575 const uint64_t caps = capabilities;
00576 return
00577 ((DTVCodeRate::kFECNone == rate)) ||
00578 ((DTVCodeRate::kFEC_1_2 == rate) && (caps & FE_CAN_FEC_1_2)) ||
00579 ((DTVCodeRate::kFEC_2_3 == rate) && (caps & FE_CAN_FEC_2_3)) ||
00580 ((DTVCodeRate::kFEC_3_4 == rate) && (caps & FE_CAN_FEC_3_4)) ||
00581 ((DTVCodeRate::kFEC_4_5 == rate) && (caps & FE_CAN_FEC_4_5)) ||
00582 ((DTVCodeRate::kFEC_5_6 == rate) && (caps & FE_CAN_FEC_5_6)) ||
00583 ((DTVCodeRate::kFEC_6_7 == rate) && (caps & FE_CAN_FEC_6_7)) ||
00584 ((DTVCodeRate::kFEC_7_8 == rate) && (caps & FE_CAN_FEC_7_8)) ||
00585 ((DTVCodeRate::kFEC_8_9 == rate) && (caps & FE_CAN_FEC_8_9)) ||
00586 ((DTVCodeRate::kFECAuto == rate) && (caps & FE_CAN_FEC_AUTO));
00587 }
00588
00592 bool DVBChannel::CheckModulation(DTVModulation modulation) const
00593 {
00594 const DTVModulation m = modulation;
00595 const uint64_t c = capabilities;
00596
00597 #ifdef FE_GET_EXTENDED_INFO
00598 if ((c & FE_HAS_EXTENDED_INFO) &&
00599 (DTVModulation::kModulation8PSK == m) &&
00600 (ext_modulations & DTVModulation::kModulation8PSK))
00601 {
00602 return true;
00603 }
00604 #endif // FE_GET_EXTENDED_INFO
00605
00606 return
00607 ((DTVModulation::kModulationQPSK == m) && (c & FE_CAN_QPSK)) ||
00608 ((DTVModulation::kModulationQAM16 == m) && (c & FE_CAN_QAM_16)) ||
00609 ((DTVModulation::kModulationQAM32 == m) && (c & FE_CAN_QAM_32)) ||
00610 ((DTVModulation::kModulationQAM64 == m) && (c & FE_CAN_QAM_64)) ||
00611 ((DTVModulation::kModulationQAM128 == m) && (c & FE_CAN_QAM_128)) ||
00612 ((DTVModulation::kModulationQAM256 == m) && (c & FE_CAN_QAM_256)) ||
00613 ((DTVModulation::kModulationQAMAuto == m) && (c & FE_CAN_QAM_AUTO)) ||
00614 ((DTVModulation::kModulation8VSB == m) && (c & FE_CAN_8VSB)) ||
00615 ((DTVModulation::kModulation16VSB == m) && (c & FE_CAN_16VSB));
00616 }
00617
00621 void DVBChannel::SetPMT(const ProgramMapTable *pmt)
00622 {
00623 if (pmt && dvbcam->IsRunning())
00624 dvbcam->SetPMT(this, pmt);
00625 }
00626
00631 void DVBChannel::SetTimeOffset(double offset)
00632 {
00633 if (dvbcam->IsRunning())
00634 dvbcam->SetTimeOffset(offset);
00635 }
00636
00637
00638 bool DVBChannel::Tune(const DTVMultiplex &tuning, QString inputname)
00639 {
00640 int inputid = inputname.isEmpty() ? currentInputID : GetInputByName(inputname);
00641 if (inputid < 0)
00642 {
00643 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Tune(): Invalid input '%1'.")
00644 .arg(inputname));
00645 return false;
00646 }
00647 return Tune(tuning, inputid, false, false);
00648 }
00649
00650
00651
00652
00653
00666 bool DVBChannel::Tune(const DTVMultiplex &tuning,
00667 uint inputid,
00668 bool force_reset,
00669 bool same_input)
00670 {
00671 QMutexLocker lock(&tune_lock);
00672
00673 if (master)
00674 {
00675 VERBOSE(VB_CHANNEL, LOC + "tuning on slave channel");
00676 SetSIStandard(tuning.sistandard);
00677 return master->Tune(tuning, inputid, force_reset, false);
00678 }
00679
00680 bool reset = (force_reset || first_tune);
00681 struct dvb_fe_params params = dtvmultiplex_to_dvbparams(card_type, tuning);
00682
00683 bool is_dvbs = (DTVTunerType::kTunerTypeQPSK == card_type ||
00684 DTVTunerType::kTunerTypeDVB_S2 == card_type);
00685
00686 bool has_diseqc = (diseqc_tree != NULL);
00687 if (is_dvbs && !has_diseqc)
00688 {
00689 VERBOSE(VB_IMPORTANT, LOC_ERR +
00690 "DVB-S needs device tree for LNB handling");
00691 return false;
00692 }
00693
00694 desired_tuning = tuning;
00695
00696 QMutexLocker locker(&hw_lock);
00697
00698 if (fd_frontend < 0)
00699 {
00700 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tune(): Card not open!");
00701
00702 return false;
00703 }
00704
00705
00706 drain_dvb_events(fd_frontend);
00707
00708
00709 if (is_dvbs)
00710 {
00711
00712 if (!same_input)
00713 diseqc_settings.Load(inputid);
00714
00715
00716 if (!diseqc_tree->Execute(diseqc_settings, tuning))
00717 {
00718 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tune(): "
00719 "Failed to setup DiSEqC devices");
00720 return false;
00721 }
00722
00723
00724 DiSEqCDevLNB *lnb = diseqc_tree->FindLNB(diseqc_settings);
00725 if (!lnb)
00726 {
00727 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tune(): "
00728 "No LNB for this configuration");
00729 return false;
00730 }
00731
00732 if (lnb->GetDeviceID() != last_lnb_dev_id)
00733 {
00734 last_lnb_dev_id = lnb->GetDeviceID();
00735
00736 reset = first_tune = true;
00737 }
00738
00739 params.frequency = lnb->GetIntermediateFrequency(
00740 diseqc_settings, tuning);
00741
00742
00743 if (capabilities & FE_CAN_FEC_AUTO)
00744 params.u.qpsk.fec_inner = FEC_AUTO;
00745 }
00746
00747 VERBOSE(VB_CHANNEL, LOC + "Old Params: " +
00748 prev_tuning.toString() +
00749 "\n\t\t\t" + LOC + "New Params: " +
00750 tuning.toString());
00751
00752
00753 int freq_mult = (is_dvbs) ? 1 : 1000;
00754 QString suffix = (is_dvbs) ? "kHz" : "Hz";
00755
00756 if (reset || !prev_tuning.IsEqual(card_type, tuning, 500 * freq_mult))
00757 {
00758 VERBOSE(VB_CHANNEL, LOC + QString("Tune(): Tuning to %1%2")
00759 .arg(params.frequency).arg(suffix));
00760
00761 #ifdef FE_GET_EXTENDED_INFO
00762 if (card_type == DTVTunerType::kTunerTypeDVB_S2)
00763 {
00764 if (ioctl(fd_frontend, FE_SET_FRONTEND2, ¶ms) < 0)
00765 {
00766 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tune(): " +
00767 "Setting Frontend(2) tuning parameters failed." + ENO);
00768 return false;
00769 }
00770 }
00771 else
00772 #endif // FE_GET_EXTENDED_INFO
00773 {
00774 if (ioctl(fd_frontend, FE_SET_FRONTEND, ¶ms) < 0)
00775 {
00776 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tune(): " +
00777 "Setting Frontend tuning parameters failed." + ENO);
00778 return false;
00779 }
00780 }
00781
00782
00783 if (tuning_delay)
00784 usleep(tuning_delay * 1000);
00785
00786 wait_for_backend(fd_frontend, 5 );
00787
00788 prev_tuning = tuning;
00789 first_tune = false;
00790 }
00791
00792 SetSIStandard(tuning.sistandard);
00793
00794 VERBOSE(VB_CHANNEL, LOC + "Tune(): Frequency tuning successful.");
00795
00796 return true;
00797 }
00798
00799 bool DVBChannel::Retune(void)
00800 {
00801 return Tune(desired_tuning, currentInputID, true, true);
00802 }
00803
00804 QString DVBChannel::GetFrontendName(void) const
00805 {
00806 return QDeepCopy<QString>(frontend_name);
00807 }
00808
00812 bool DVBChannel::IsTuningParamsProbeSupported(void) const
00813 {
00814 QMutexLocker locker(&hw_lock);
00815
00816 if (fd_frontend < 0)
00817 {
00818 VERBOSE(VB_IMPORTANT, LOC_ERR + "Card not open!");
00819
00820 return false;
00821 }
00822
00823 if (master)
00824 return master->IsTuningParamsProbeSupported();
00825
00826 if (diseqc_tree)
00827 {
00828
00829
00830
00831 return false;
00832 }
00833
00834 dvb_fe_params params;
00835 return ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms) >= 0;
00836 }
00837
00845 bool DVBChannel::ProbeTuningParams(DTVMultiplex &tuning) const
00846 {
00847 QMutexLocker locker(&hw_lock);
00848
00849 if (fd_frontend < 0)
00850 {
00851 VERBOSE(VB_IMPORTANT, LOC_ERR + "Card not open!");
00852
00853 return false;
00854 }
00855
00856 if (master)
00857 return master->ProbeTuningParams(tuning);
00858
00859 if (diseqc_tree)
00860 {
00861
00862
00863
00864 return false;
00865 }
00866
00867 dvb_fe_params params;
00868 if (ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms) < 0)
00869 {
00870 VERBOSE(VB_IMPORTANT, LOC_ERR +
00871 "Getting Frontend tuning parameters failed." + ENO);
00872
00873 return false;
00874 }
00875
00876 uint mplex = tuning.mplex;
00877 QString sistandard = QDeepCopy<QString>(tuning.sistandard);
00878
00879 tuning = dvbparams_to_dtvmultiplex(card_type, params);
00880
00881 tuning.mplex = mplex;
00882 tuning.sistandard = sistandard;
00883
00884 return true;
00885 }
00886
00891 int DVBChannel::GetChanID() const
00892 {
00893 int cardid = GetCardID();
00894
00895 MSqlQuery query(MSqlQuery::InitCon());
00896
00897 query.prepare("SELECT chanid "
00898 "FROM channel, cardinput "
00899 "WHERE cardinput.sourceid = channel.sourceid AND "
00900 " channel.channum = :CHANNUM AND "
00901 " cardinput.cardid = :CARDID");
00902
00903 query.bindValue(":CHANNUM", curchannelname);
00904 query.bindValue(":CARDID", cardid);
00905
00906 if (!query.exec() || !query.isActive())
00907 {
00908 MythContext::DBError("fetching chanid", query);
00909 return -1;
00910 }
00911
00912 if (query.size() <= 0)
00913 return -1;
00914
00915 query.next();
00916 return query.value(0).toInt();
00917 }
00918
00919 void DVBChannel::SaveCachedPids(const pid_cache_t &pid_cache) const
00920 {
00921 int chanid = GetChanID();
00922 if (chanid > 0)
00923 DTVChannel::SaveCachedPids(chanid, pid_cache);
00924 }
00925
00926 void DVBChannel::GetCachedPids(pid_cache_t &pid_cache) const
00927 {
00928 int chanid = GetChanID();
00929 if (chanid > 0)
00930 DTVChannel::GetCachedPids(chanid, pid_cache);
00931 }
00932
00933 const DiSEqCDevRotor *DVBChannel::GetRotor(void) const
00934 {
00935 if (diseqc_tree)
00936 return diseqc_tree->FindRotor(diseqc_settings);
00937
00938 return NULL;
00939 }
00940
00941
00942 bool DVBChannel::HasLock(bool *ok) const
00943 {
00944 if (master)
00945 return master->HasLock(ok);
00946
00947 fe_status_t status;
00948 bzero(&status, sizeof(status));
00949
00950 int ret = ioctl(fd_frontend, FE_READ_STATUS, &status);
00951 if (ok)
00952 *ok = (0 == ret);
00953
00954 return status & FE_HAS_LOCK;
00955 }
00956
00957
00958 double DVBChannel::GetSignalStrength(bool *ok) const
00959 {
00960 if (master)
00961 return master->GetSignalStrength(ok);
00962
00963
00964
00965 uint16_t sig = 0;
00966
00967 int ret = ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig);
00968
00969 if (ok)
00970 *ok = (0 == ret);
00971
00972 return sig * (1.0 / 65535.0);
00973 }
00974
00975
00976 double DVBChannel::GetSNR(bool *ok) const
00977 {
00978 if (master)
00979 return master->GetSNR(ok);
00980
00981
00982
00983
00984 uint16_t snr = 0;
00985 int ret = ioctl(fd_frontend, FE_READ_SNR, &snr);
00986
00987 if (ok)
00988 *ok = (0 == ret);
00989
00990 return snr * (1.0 / 65535.0);
00991 }
00992
00993
00994 double DVBChannel::GetBitErrorRate(bool *ok) const
00995 {
00996 if (master)
00997 return master->GetBitErrorRate(ok);
00998
00999 uint32_t ber = 0;
01000 int ret = ioctl(fd_frontend, FE_READ_BER, &ber);
01001
01002 if (ok)
01003 *ok = (0 == ret);
01004
01005 return (double) ber;
01006 }
01007
01008
01009 double DVBChannel::GetUncorrectedBlockCount(bool *ok) const
01010 {
01011 if (master)
01012 return master->GetUncorrectedBlockCount(ok);
01013
01014 uint32_t ublocks = 0;
01015 int ret = ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks);
01016
01017 if (ok)
01018 *ok = (0 == ret);
01019
01020 return (double) ublocks;
01021 }
01022
01027 static void drain_dvb_events(int fd)
01028 {
01029 struct dvb_frontend_event event;
01030 while (ioctl(fd, FE_GET_EVENT, &event) == 0);
01031 }
01032
01056 static bool wait_for_backend(int fd, int timeout_ms)
01057 {
01058 struct timeval select_timeout = { 0, (timeout_ms % 1000) * 1000 };
01059 fd_set fd_select_set;
01060 FD_ZERO( &fd_select_set);
01061 FD_SET (fd, &fd_select_set);
01062
01063
01064
01065 select(fd+1, &fd_select_set, NULL, NULL, &select_timeout);
01066
01067
01068 fe_status_t status;
01069 if (ioctl(fd, FE_READ_STATUS, &status) < 0)
01070 {
01071 VERBOSE(VB_IMPORTANT, QString("dvbchannel.cpp:wait_for_backend: "
01072 "Failed to get status, error: %1")
01073 .arg(strerror(errno)));
01074 return false;
01075 }
01076
01077 VERBOSE(VB_CHANNEL, QString("dvbchannel.cpp:wait_for_backend: Status: %1")
01078 .arg(toString(status)));
01079 return true;
01080 }
01081
01082 static struct dvb_fe_params dtvmultiplex_to_dvbparams(
01083 DTVTunerType tuner_type, const DTVMultiplex &tuning)
01084 {
01085 dvb_fe_params params;
01086 bzero(¶ms, sizeof(params));
01087
01088 params.frequency = tuning.frequency;
01089 params.inversion = (fe_spectral_inversion_t) (int) tuning.inversion;
01090
01091 if (DTVTunerType::kTunerTypeQPSK == tuner_type)
01092 {
01093 params.u.qpsk.symbol_rate = tuning.symbolrate;
01094 params.u.qpsk.fec_inner = (fe_code_rate_t) (int) tuning.fec;
01095 }
01096
01097 if (DTVTunerType::kTunerTypeDVB_S2 == tuner_type)
01098 {
01099 #ifdef FE_GET_EXTENDED_INFO
01100 params.u.qpsk2.symbol_rate = tuning.symbolrate;
01101 params.u.qpsk2.fec_inner = (fe_code_rate_t) (int) tuning.fec;
01102 params.u.qpsk2.modulation = (fe_modulation_t) (int) tuning.modulation;
01103 #else // if !FE_GET_EXTENDED_INFO
01104 VERBOSE(VB_IMPORTANT, "DVBChan Error, MythTV was compiled without "
01105 "DVB-S2 headers being present so DVB-S2 tuning will fail.");
01106 #endif // !FE_GET_EXTENDED_INFO
01107 }
01108
01109 if (DTVTunerType::kTunerTypeQAM == tuner_type)
01110 {
01111 params.u.qam.symbol_rate = tuning.symbolrate;
01112 params.u.qam.fec_inner = (fe_code_rate_t) (int) tuning.fec;
01113 params.u.qam.modulation = (fe_modulation_t) (int) tuning.modulation;
01114 }
01115
01116 if (DTVTunerType::kTunerTypeOFDM == tuner_type)
01117 {
01118 params.u.ofdm.bandwidth =
01119 (fe_bandwidth_t) (int) tuning.bandwidth;
01120 params.u.ofdm.code_rate_HP =
01121 (fe_code_rate_t) (int) tuning.hp_code_rate;
01122 params.u.ofdm.code_rate_LP =
01123 (fe_code_rate_t) (int) tuning.lp_code_rate;
01124 params.u.ofdm.constellation =
01125 (fe_modulation_t) (int) tuning.modulation;
01126 params.u.ofdm.transmission_mode =
01127 (fe_transmit_mode_t) (int) tuning.trans_mode;
01128 params.u.ofdm.guard_interval =
01129 (fe_guard_interval_t) (int) tuning.guard_interval;
01130 params.u.ofdm.hierarchy_information =
01131 (fe_hierarchy_t) (int) tuning.hierarchy;
01132 }
01133
01134 if (DTVTunerType::kTunerTypeATSC == tuner_type)
01135 {
01136 #ifdef USE_ATSC
01137 params.u.vsb.modulation =
01138 (fe_modulation_t) (int) tuning.modulation;
01139 #endif // USE_ATSC
01140 }
01141
01142 return params;
01143 }
01144
01145 static DTVMultiplex dvbparams_to_dtvmultiplex(
01146 DTVTunerType tuner_type, const dvb_fe_params ¶ms)
01147 {
01148 DTVMultiplex tuning;
01149
01150 tuning.frequency = params.frequency;
01151 tuning.inversion = params.inversion;
01152
01153 if ((DTVTunerType::kTunerTypeQPSK == tuner_type) ||
01154 (DTVTunerType::kTunerTypeDVB_S2 == tuner_type))
01155 {
01156 tuning.symbolrate = params.u.qpsk.symbol_rate;
01157 tuning.fec = params.u.qpsk.fec_inner;
01158 }
01159
01160 if (DTVTunerType::kTunerTypeQAM == tuner_type)
01161 {
01162 tuning.symbolrate = params.u.qam.symbol_rate;
01163 tuning.fec = params.u.qam.fec_inner;
01164 tuning.modulation = params.u.qam.modulation;
01165 }
01166
01167 if (DTVTunerType::kTunerTypeOFDM == tuner_type)
01168 {
01169 tuning.bandwidth = params.u.ofdm.bandwidth;
01170 tuning.hp_code_rate = params.u.ofdm.code_rate_HP;
01171 tuning.lp_code_rate = params.u.ofdm.code_rate_LP;
01172 tuning.modulation = params.u.ofdm.constellation;
01173 tuning.trans_mode = params.u.ofdm.transmission_mode;
01174 tuning.guard_interval = params.u.ofdm.guard_interval;
01175 tuning.hierarchy = params.u.ofdm.hierarchy_information;
01176 }
01177
01178 if (DTVTunerType::kTunerTypeATSC == tuner_type)
01179 {
01180 #ifdef USE_ATSC
01181 tuning.modulation = params.u.vsb.modulation;
01182 #endif // USE_ATSC
01183 }
01184
01185 return tuning;
01186 }