MythTV  0.26-pre
dvbchannel.cpp
Go to the documentation of this file.
00001 /*
00002  *  Class DVBChannel
00003  *
00004  * Copyright (C) Kenneth Aafloy 2003
00005  *
00006  *  Description:
00007  *      Has the responsibility of opening the Frontend device and
00008  *      setting the options to tune a channel. It also keeps other
00009  *      channel options used by the dvb hierarcy.
00010  *
00011  *  Author(s):
00012  *      Taylor Jacob (rtjacob at earthlink.net)
00013  *          - Changed tuning and DB structure
00014  *      Kenneth Aafloy (ke-aa at frisurf.no)
00015  *          - Rewritten for faster tuning.
00016  *      Ben Bucksch
00017  *          - Wrote the original implementation
00018  *
00019  *   This program is free software; you can redistribute it and/or modify
00020  *   it under the terms of the GNU General Public License as published by
00021  *   the Free Software Foundation; either version 2 of the License, or
00022  *   (at your option) any later version.
00023  *
00024  *   This program is distributed in the hope that it will be useful,
00025  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00026  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027  *   GNU General Public License for more details.
00028  *
00029  *   You should have received a copy of the GNU General Public License
00030  *   along with this program; if not, write to the Free Software
00031  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00032  */
00033 
00034 // POSIX headers
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 // MythTV headers
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       // Helper classes
00068       diseqc_tree(NULL),            dvbcam(NULL),
00069       // Device info
00070       frontend_name(QString::null),
00071       // Tuning
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       // Misc
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); // == RegisterForMaster
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     // set a new master if there are other instances and we're the master
00102     // whether we are the master or not remove us from the map..
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     // if we're the last one out delete dvbcam
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     // diseqc_tree is managed elsewhere
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; // this caller didn't have it open in the first place..
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); // if we're the master we don't need this lock..
00157 
00158     if (!is_open.empty())
00159         return; // not all callers have closed the DVB channel yet..
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); // if we're the master we don't need this lock..
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     // Turn on the power to the LNB
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     // DVB-S needs a fully initialized diseqc tree and is checked later in Tune
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     // Check OFDM Tuning params
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 //HAVE_FE_CAN_2G_MODULATION
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     // The cx24116 DVB-S2 demod anounce FE_CAN_FEC_AUTO but has apparently
00552     // trouble with FEC_AUTO on DVB-S2 transponders
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            Tuning functions for each of the five types of cards.
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); // if we're the master we don't need this lock..
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     // Remove any events in queue before tuning.
00679     drain_dvb_events(fd_frontend);
00680 
00681     // send DVB-S setup
00682     if (diseqc_tree)
00683     {
00684         // configure for new input
00685         if (!same_input)
00686             diseqc_settings.Load(inputid);
00687 
00688         // execute diseqc commands
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         // retrieve actual intermediate frequency
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             // make sure we tune to frequency, if the lnb has changed
00709             reset = first_tune = true;
00710         }
00711 
00712         intermediate_freq = lnb->GetIntermediateFrequency(
00713             diseqc_settings, tuning);
00714 
00715         // if card can auto-FEC, use it -- sometimes NITs are inaccurate
00716         if (capabilities & FE_CAN_FEC_AUTO)
00717             can_fec_auto = true;
00718 
00719         // Check DVB-S intermediate frequency here since it requires a fully
00720         // initialized diseqc tree
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     // DVB-S is in kHz, other DVB is in Hz
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, &params) < 0)
00795             {
00796                 LOG(VB_GENERAL, LOG_ERR, LOC +
00797                     "Tune(): Setting Frontend tuning parameters failed." + ENO);
00798                 return false;
00799             }
00800         }
00801 
00802         // Extra delay to add for broken DVB drivers
00803         if (tuning_delay)
00804             usleep(tuning_delay * 1000);
00805 
00806         wait_for_backend(fd_frontend, 5 /* msec */);
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); // if we're the master we don't need this lock..
00853 
00854     if (diseqc_tree)
00855     {
00856         // TODO We need to implement the inverse of
00857         // lnb->GetIntermediateFrequency() for ProbeTuningParams()
00858         // to accurately reflect the frequency before LNB transform.
00859         return false;
00860     }
00861 
00862     dvb_frontend_parameters params;
00863 
00864     int res = ioctl(fd_frontend, FE_GET_FRONTEND, &params);
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); // if we're the master we don't need this lock..
00899 
00900     if (diseqc_tree)
00901     {
00902         // TODO We need to implement the inverse of
00903         // lnb->GetIntermediateFrequency() for ProbeTuningParams()
00904         // to accurately reflect the frequency before LNB transform.
00905         return false;
00906     }
00907 
00908     if (tunerType == DTVTunerType::kTunerTypeDVBS2)
00909     {
00910         // TODO implement probing of tuning parameters with FE_GET_PROPERTY
00911         return false;
00912     }
00913 
00914     dvb_frontend_parameters params;
00915     if (ioctl(fd_frontend, FE_GET_FRONTEND, &params) < 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 // documented in dvbchannel.h
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); // if we're the master we don't need this lock..
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 // documented in dvbchannel.h
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); // if we're the master we don't need this lock..
01012 
01013     // We use uint16_t for sig because this is correct for DVB API 4.0,
01014     // and works better than the correct int16_t for the 3.x API
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 // documented in dvbchannel.h
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); // if we're the master we don't need this lock..
01041 
01042     // We use uint16_t for sig because this is correct for DVB API 4.0,
01043     // and works better than the correct int16_t for the 3.x API
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 // documented in dvbchannel.h
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); // if we're the master we don't need this lock..
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 // documented in dvbchannel.h
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); // if we're the master we don't need this lock..
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 /*usec*/};
01195     fd_set fd_select_set;
01196     FD_ZERO(    &fd_select_set);
01197     FD_SET (fd, &fd_select_set);
01198 
01199     // Try to wait for some output like an event, unfortunately
01200     // this fails on several DVB cards, so we have a timeout.
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     // This is supposed to work on all cards, post 2.6.12...
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(&params, 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 &params)
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends