Ticket #2695: 2695-merge-v1.patch

File 2695-merge-v1.patch, 172.8 KB (added by danielk, 17 years ago)

patch to merge channel-scan branch to trunk

  • libs/libmythtv/libmythtv.pro

     
    2525DEPENDPATH  += ../libmyth ../libavcodec ../libavformat ../libavutil ../libswscale
    2626DEPENDPATH  += ../libmythmpeg2 ../libmythdb ../libmythhdhomerun
    2727DEPENDPATH  += ../libmythdvdnav/
    28 DEPENDPATH  += ./dvbdev ./mpeg ./iptv
     28DEPENDPATH  += ./dvbdev ./mpeg ./iptv ./channelscan
    2929DEPENDPATH  += ../libmythlivemedia/BasicUsageEnvironment/include
    3030DEPENDPATH  += ../libmythlivemedia/BasicUsageEnvironment
    3131DEPENDPATH  += ../libmythlivemedia/groupsock/include
     
    247247SOURCES += dtvmultiplex.cpp
    248248SOURCES += dtvconfparser.cpp        dtvconfparserhelpers.cpp
    249249
     250HEADERS += channelscan/scaninfo.h   channelscan/channelimporter.h
     251SOURCES += channelscan/scaninfo.cpp channelscan/channelimporter.cpp
     252
    250253using_frontend {
    251254    # Recording profile stuff
    252255    HEADERS += profilegroup.h
     
    399402    SOURCES += inputinfo.cpp               inputgroupmap.cpp
    400403
    401404    # Channel scanner stuff
    402     HEADERS += scanwizard.h                scanwizardhelpers.h
    403     HEADERS += siscan.h
    404     HEADERS += scanwizardscanner.h
    405     SOURCES += scanwizard.cpp              scanwizardhelpers.cpp
    406     SOURCES += siscan.cpp
    407     SOURCES += scanwizardscanner.cpp
     405    HEADERS += scanwizard.h
     406    SOURCES += scanwizard.cpp
    408407
     408    HEADERS += channelscan/channelscan_sm.h
     409    HEADERS += channelscan/channelscanner.h
     410    HEADERS += channelscan/channelscanner_gui.h
     411    HEADERS += channelscan/channelscanner_cli.h
     412    HEADERS += channelscan/frequencytablesetting.h
     413    HEADERS += channelscan/inputselectorsetting.h
     414    HEADERS += channelscan/loglist.h
     415    HEADERS += channelscan/channelscanmiscsettings.h
     416    HEADERS += channelscan/modulationsetting.h
     417    HEADERS += channelscan/multiplexsetting.h
     418    HEADERS += channelscan/paneanalog.h
     419    HEADERS += channelscan/paneatsc.h
     420    HEADERS += channelscan/panedvbc.h
     421    HEADERS += channelscan/panedvbs.h
     422    HEADERS += channelscan/panedvbs2.h
     423    HEADERS += channelscan/panedvbt.h
     424    HEADERS += channelscan/panedvbutilsimport.h
     425    HEADERS += channelscan/panesingle.h
     426    HEADERS += channelscan/scanmonitor.h
     427    HEADERS += channelscan/scanprogresspopup.h
     428    HEADERS += channelscan/scanwizardconfig.h
     429
     430    SOURCES += channelscan/channelscan_sm.cpp
     431    SOURCES += channelscan/channelscanner.cpp
     432    SOURCES += channelscan/channelscanner_gui.cpp
     433    SOURCES += channelscan/channelscanner_cli.cpp
     434    SOURCES += channelscan/frequencytablesetting.cpp
     435    SOURCES += channelscan/inputselectorsetting.cpp
     436    SOURCES += channelscan/loglist.cpp
     437    SOURCES += channelscan/multiplexsetting.cpp
     438    SOURCES += channelscan/paneanalog.cpp
     439    SOURCES += channelscan/scanmonitor.cpp
     440    SOURCES += channelscan/scanprogresspopup.cpp
     441    SOURCES += channelscan/scanwizardconfig.cpp
     442
    409443    # EIT stuff
    410444    HEADERS += eithelper.h                 eitscanner.h
    411445    HEADERS += eitfixup.h                  eitcache.h
  • libs/libmythtv/scanwizardhelpers.h

     
    1 /* -*- Mode: c++ -*-
    2  * $Id$
    3  * vim: set expandtab tabstop=4 shiftwidth=4:
    4  *
    5  * Original Project
    6  *      MythTV      http://www.mythtv.org
    7  *
    8  * Author(s):
    9  *      John Pullan  (john@pullan.org)
    10  *
    11  * Description:
    12  *     Collection of classes to provide dvb channel scanning
    13  *     functionality
    14  *
    15  *
    16  * This program is free software; you can redistribute it and/or
    17  * modify it under the terms of the GNU General Public License
    18  * as published by the Free Software Foundation; either version 2
    19  * of the License, or (at your option) any later version.
    20  *
    21  * This program is distributed in the hope that it will be useful,
    22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    24  * GNU General Public License for more details.
    25  *
    26  * You should have received a copy of the GNU General Public License
    27  * along with this program; if not, write to the Free Software
    28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    29  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    30  *
    31  */
    32 
    33 #ifndef SCANWIZARDHELPERS_H
    34 #define SCANWIZARDHELPERS_H
    35 
    36 #include "compat.h"
    37 #include "settings.h"
    38 
    39 #include <qwaitcondition.h>
    40 #include <qevent.h>
    41 
    42 class TransFreqTableSelector;
    43 class TransLabelSetting;
    44 class ScanWizardScanner;
    45 class ScanWizard;
    46 class OptionalTypeSetting;
    47 class VideoSourceSelector;
    48 class OFDMPane;
    49 class QPSKPane;
    50 class DVBS2Pane;
    51 class ATSCPane;
    52 class QAMPane;
    53 class AnalogPane;
    54 class STPane;
    55 class DVBUtilsImportPane;
    56 
    57 class ScanSignalMeter: public ProgressSetting, public TransientStorage
    58 {
    59   public:
    60     ScanSignalMeter(int steps): ProgressSetting(this, steps) {};
    61 };
    62 
    63 class ScanProgressPopup : public ConfigurationPopupDialog
    64 {
    65     Q_OBJECT
    66 
    67     friend class QObject; // quiet OSX gcc warning
    68 
    69   public:
    70     ScanProgressPopup(bool lock, bool strength, bool snr);
    71     virtual void deleteLater(void);
    72 
    73     void CreateDialog(void);
    74     virtual DialogCode exec(void);
    75     void DeleteDialog(void);
    76 
    77     void SetStatusSignalToNoise(int value);
    78     void SetStatusSignalStrength(int value);
    79     void SetStatusLock(int value);
    80     void SetScanProgress(double value);
    81 
    82     void SetStatusText(const QString &value);
    83     void SetStatusTitleText(const QString &value);
    84 
    85   private slots:
    86     void Done(void);
    87 
    88   private:
    89     ~ScanProgressPopup();
    90 
    91     bool               done;
    92     QWaitCondition     wait;
    93 
    94     ScanSignalMeter   *ss;
    95     ScanSignalMeter   *sn;
    96     ScanSignalMeter   *progressBar;
    97 
    98     TransLabelSetting *sl;
    99     TransLabelSetting *sta;
    100 };
    101 
    102 class ScannerEvent : public QEvent
    103 {
    104     friend class QObject; // quiet OSX gcc warning
    105 
    106   public:
    107     enum TYPE
    108     {
    109         ScanComplete,
    110         ScanShutdown,
    111         AppendTextToLog,
    112         SetStatusText,
    113         SetStatusTitleText,
    114         SetPercentComplete,
    115         SetStatusRotorPosition,
    116         SetStatusSignalToNoise,
    117         SetStatusSignalStrength,
    118         SetStatusSignalLock,
    119     };
    120 
    121     ScannerEvent(TYPE t) :
    122         QEvent((QEvent::Type)(t + QEvent::User)),
    123         str(""), intvalue(0), spp_ptr(NULL) { ; }
    124 
    125     QString strValue()              const { return str; }
    126     void    strValue(const QString& _str) { str = _str; }
    127 
    128     int     intValue()        const { return intvalue; }
    129     void    intValue(int _intvalue) { intvalue = _intvalue; }
    130 
    131     ScanProgressPopup *ScanProgressPopupValue() const { return spp_ptr; }
    132     void    ScanProgressPopupValue(ScanProgressPopup *_spp_ptr)
    133         { spp_ptr = _spp_ptr; }
    134 
    135     TYPE    eventType()       const { return (TYPE)(type()-QEvent::User); }
    136 
    137   private:
    138     ~ScannerEvent() { }
    139 
    140   private:
    141     QString str;
    142     int     intvalue;
    143     ScanProgressPopup *spp_ptr;
    144 };
    145 
    146 void post_event(QObject *dest, ScannerEvent::TYPE type, int val);
    147 void post_event(QObject *dest, ScannerEvent::TYPE type, const QString &val);
    148 void post_event(QObject *dest, ScannerEvent::TYPE type, int val,
    149                 ScanProgressPopup *spp);
    150 
    151 // ///////////////////////////////
    152 // Settings Below Here
    153 // ///////////////////////////////
    154 
    155 class MultiplexSetting : public ComboBoxSetting, public TransientStorage
    156 {
    157     Q_OBJECT
    158 
    159   public:
    160     MultiplexSetting() : ComboBoxSetting(this), sourceid(0)
    161         { setLabel(tr("Transport")); }
    162 
    163     virtual void Load(void);
    164 
    165     void SetSourceID(uint _sourceid);
    166 
    167   protected:
    168     uint sourceid;
    169 };
    170 
    171 class IgnoreSignalTimeout : public CheckBoxSetting, public TransientStorage
    172 {
    173   public:
    174     IgnoreSignalTimeout() : CheckBoxSetting(this)
    175     {
    176         setLabel(QObject::tr("Ignore Signal Timeout"));
    177         setHelpText(
    178             QObject::tr("This option allows you to slow down the scan for "
    179                         "broken drivers, such as the DVB drivers for the "
    180                         "Leadtek LR6650 DVB card."));
    181     }
    182 };
    183 
    184 class InputSelector : public ComboBoxSetting, public TransientStorage
    185 {
    186     Q_OBJECT
    187 
    188   public:
    189     InputSelector(uint _default_cardid, const QString &_default_inputname);
    190 
    191     virtual void Load(void);
    192 
    193     uint GetCardID(void) const;
    194 
    195     QString GetInputName(void) const;
    196 
    197     static bool Parse(const QString &cardid_inputname,
    198                       uint          &cardid,
    199                       QString       &inputname);
    200 
    201   public slots:
    202     void SetSourceID(const QString &_sourceid);
    203 
    204   private:
    205     uint    sourceid;
    206     uint    default_cardid;
    207     QString default_inputname;
    208 };
    209 
    210 class ScanCountry : public ComboBoxSetting, public TransientStorage
    211 {
    212     Q_OBJECT
    213 
    214   public:
    215     enum Country
    216     {
    217         AU,
    218         FI,
    219         SE,
    220         UK,
    221         DE,
    222         ES,
    223         NZ,
    224         FR,
    225     };
    226 
    227     ScanCountry();
    228 };
    229 
    230 class ScanTypeSetting : public ComboBoxSetting, public TransientStorage
    231 {
    232     Q_OBJECT
    233   public:
    234     enum Type
    235     {
    236         Error_Open = 0,
    237         Error_Probe,
    238         // Scans that check each frequency in a predefined list
    239         FullScan_Analog,
    240         FullScan_ATSC,
    241         FullScan_OFDM,
    242         // Scans starting on one frequency that adds each transport
    243         // seen in the Network Information Tables to the scan.
    244         NITAddScan_OFDM,
    245         NITAddScan_QPSK,
    246         NITAddScan_QAM,
    247         // Scan of all transports already in the database
    248         FullTransportScan,
    249         // Scan of one transport already in the database
    250         TransportScan,
    251         // IPTV import of channels from M3U URL
    252         IPTVImport,
    253         // Imports lists from dvb-utils scanners
    254         DVBUtilsImport,
    255     };
    256 
    257     ScanTypeSetting() : ComboBoxSetting(this), hw_cardid(0)
    258         { setLabel(QObject::tr("Scan Type")); }
    259 
    260   protected slots:
    261     void SetInput(const QString &cardids_inputname);
    262 
    263   protected:
    264     uint    hw_cardid;
    265 };
    266 
    267 class ScanOptionalConfig : public TriggeredConfigurationGroup
    268 {
    269     Q_OBJECT
    270 
    271   public:
    272     ScanOptionalConfig(ScanTypeSetting *_scan_type);
    273 
    274     QString GetATSCFormat(const QString&)    const;
    275     QString GetFrequencyStandard(void)       const;
    276     QString GetModulation(void)              const;
    277     QString GetFrequencyTable(void)          const;
    278     bool    DoIgnoreSignalTimeout(void)      const;
    279     QString GetFilename(void)                const;
    280     uint    GetMultiplex(void)               const;
    281     bool    DoDeleteChannels(void)           const;
    282     bool    DoRenameChannels(void)           const;
    283     QMap<QString,QString> GetStartChan(void) const;
    284 
    285     void SetDefaultATSCFormat(const QString &atscFormat);
    286 
    287   public slots:
    288     void SetSourceID(const QString&);
    289     void triggerChanged(const QString&);
    290 
    291   private:
    292     ScanTypeSetting     *scanType;
    293     ScanCountry         *country;
    294     IgnoreSignalTimeout *ignoreSignalTimeoutAll;
    295     OFDMPane            *paneOFDM;
    296     QPSKPane            *paneQPSK;
    297     DVBS2Pane           *paneDVBS2;
    298     ATSCPane            *paneATSC;
    299     QAMPane             *paneQAM;
    300     AnalogPane          *paneAnalog;
    301     STPane              *paneSingle;
    302     DVBUtilsImportPane  *paneDVBUtilsImport;
    303 };
    304 
    305 class ScanWizardConfig: public VerticalConfigurationGroup
    306 {
    307     Q_OBJECT
    308 
    309   public:
    310     ScanWizardConfig(ScanWizard *_parent,
    311                      uint        default_sourceid,
    312                      uint        default_cardid,
    313                      QString     default_inputname);
    314 
    315     uint    GetSourceID(void)     const;
    316     QString GetATSCFormat(void)   const;
    317     QString GetModulation(void)   const { return scanConfig->GetModulation(); }
    318     int     GetScanType(void)     const { return scanType->getValue().toInt();}
    319     uint    GetCardID(void)       const { return input->GetCardID();          }
    320     QString GetInputName(void)    const { return input->GetInputName();       }
    321     QString GetFilename(void)     const { return scanConfig->GetFilename();   }
    322     uint    GetMultiplex(void)    const { return scanConfig->GetMultiplex();  }
    323     bool DoDeleteChannels(void) const { return scanConfig->DoDeleteChannels();}
    324     bool DoRenameChannels(void) const { return scanConfig->DoRenameChannels();}
    325     QString GetFrequencyStandard(void) const
    326         { return scanConfig->GetFrequencyStandard(); }
    327     QString GetFrequencyTable(void) const
    328         { return scanConfig->GetFrequencyTable(); }
    329     QMap<QString,QString> GetStartChan(void) const
    330         { return scanConfig->GetStartChan(); }
    331     bool    DoIgnoreSignalTimeout(void) const
    332         { return scanConfig->DoIgnoreSignalTimeout(); }
    333 
    334     void SetDefaultATSCFormat(const QString &atscFormat)
    335         { scanConfig->SetDefaultATSCFormat(atscFormat); }
    336 
    337   protected:
    338     VideoSourceSelector *videoSource;
    339     InputSelector       *input;
    340     ScanTypeSetting     *scanType;
    341     ScanOptionalConfig  *scanConfig;
    342 };
    343 
    344 class LogList: public ListBoxSetting, public TransientStorage
    345 {
    346   public:
    347     LogList();
    348 
    349     void updateText(const QString& status);
    350   protected:
    351     int n;
    352 };
    353 
    354 class ScanFrequencyTable: public ComboBoxSetting, public TransientStorage
    355 {
    356   public:
    357     ScanFrequencyTable() : ComboBoxSetting(this)
    358     {
    359         addSelection(QObject::tr("Broadcast"),        "us",          true);
    360         addSelection(QObject::tr("Cable")     + " " +
    361                      QObject::tr("High"),             "uscablehigh", false);
    362         addSelection(QObject::tr("Cable HRC") + " " +
    363                      QObject::tr("High"),             "ushrchigh",   false);
    364         addSelection(QObject::tr("Cable IRC") + " " +
    365                      QObject::tr("High"),             "usirchigh",   false);
    366         addSelection(QObject::tr("Cable"),            "uscable",     false);
    367         addSelection(QObject::tr("Cable HRC"),        "ushrc",       false);
    368         addSelection(QObject::tr("Cable IRC"),        "usirc",       false);
    369 
    370         setLabel(QObject::tr("Frequency Table"));
    371         setHelpText(QObject::tr("Frequency table to use.") + " " +
    372                     QObject::tr(
    373                         "The option of scanning only \"High\" "
    374                         "frequency channels is useful because most "
    375                         "digital channels are on the higher frequencies."));
    376     }
    377 };
    378 
    379 class ScanATSCModulation: public ComboBoxSetting, public TransientStorage
    380 {
    381   public:
    382     ScanATSCModulation() : ComboBoxSetting(this)
    383     {
    384         addSelection(QObject::tr("Terrestrial")+" (8-VSB)","vsb8",  true);
    385         addSelection(QObject::tr("Cable") + " (QAM-256)", "qam256", false);
    386         addSelection(QObject::tr("Cable") + " (QAM-128)", "qam128", false);
    387         addSelection(QObject::tr("Cable") + " (QAM-64)",  "qam64",  false);
    388 
    389         setLabel(QObject::tr("Modulation"));
    390         setHelpText(
    391             QObject::tr("Modulation, 8-VSB, QAM-256, etc.") + " " +
    392             QObject::tr("Most cable systems in the United States use "
    393                         "QAM-256 or QAM-64, but some mixed systems "
    394                         "may use 8-VSB for over-the-air channels."));
    395     }
    396 };
    397 
    398 class ScanATSCChannelFormat: public ComboBoxSetting, public TransientStorage
    399 {
    400   public:
    401     ScanATSCChannelFormat() : ComboBoxSetting(this)
    402     {
    403         addSelection(QObject::tr("(5_1) Underscore"), "%1_%2", true);
    404         addSelection(QObject::tr("(5-1) Minus"),      "%1-%2", false);
    405         addSelection(QObject::tr("(5.1) Period"),     "%1.%2", false);
    406         addSelection(QObject::tr("(501) Zero"),       "%10%2", false);
    407         addSelection(QObject::tr("(51) None"),        "%1%2",  false);
    408         setLabel(QObject::tr("ATSC Channel Separator"));
    409         setHelpText(QObject::tr("What to use to separate ATSC major "
    410                                 "and minor channels."));
    411     }
    412 };
    413 
    414 class ScanOldChannelTreatment: public ComboBoxSetting, public TransientStorage
    415 {
    416   public:
    417     ScanOldChannelTreatment(bool rename = true) : ComboBoxSetting(this)
    418     {
    419         addSelection(QObject::tr("Minimal Updates"),    "minimal");
    420         if (rename)
    421             addSelection(QObject::tr("Rename to Match"),    "rename");
    422         addSelection(QObject::tr("Delete"),             "delete");
    423         setLabel(QObject::tr("Existing Channel Treatment"));
    424         setHelpText(QObject::tr("How to treat existing channels."));
    425     }
    426 };
    427 
    428 class ScanFrequency: public LineEditSetting, public TransientStorage
    429 {
    430   public:
    431     ScanFrequency(bool in_kHz = false) : LineEditSetting(this)
    432     {
    433         QString units = (in_kHz) ? "kHz" : "Hz";
    434         setLabel(QObject::tr("Frequency (%1)").arg(units));
    435         setHelpText(
    436             QObject::tr(
    437                 "Frequency (Option has no default).\n"
    438                 "The frequency for this channel in %1.").arg(units));
    439     };
    440 };
    441 
    442 class ScanSymbolRate: public ComboBoxSetting, public TransientStorage
    443 {
    444   public:
    445     ScanSymbolRate() : ComboBoxSetting(this, true)
    446     {
    447         setLabel(QObject::tr("Symbol Rate"));
    448         setHelpText(
    449              QObject::tr(
    450                 "Symbol Rate (symbols/second).\n"
    451                 "Most dvb-s transponders transmit at 27.5 "
    452                 "million symbols per second."));
    453         addSelection("3333000");
    454         addSelection("22000000");
    455         addSelection("27500000", "27500000", true);
    456         addSelection("28000000");
    457         addSelection("28500000");
    458         addSelection("29900000");
    459     };
    460 };
    461 
    462 class ScanPolarity: public ComboBoxSetting, public TransientStorage
    463 {
    464   public:
    465     ScanPolarity() : ComboBoxSetting(this)
    466     {
    467         setLabel(QObject::tr("Polarity"));
    468         setHelpText(QObject::tr("Polarity (Option has no default)"));
    469         addSelection(QObject::tr("Horizontal"), "h",true);
    470         addSelection(QObject::tr("Vertical"), "v");
    471         addSelection(QObject::tr("Right Circular"), "r");
    472         addSelection(QObject::tr("Left Circular"), "l");
    473     };
    474 };
    475 
    476 class ScanInversion: public ComboBoxSetting, public TransientStorage
    477 {
    478   public:
    479     ScanInversion() : ComboBoxSetting(this)
    480     {
    481         setLabel(QObject::tr("Inversion"));
    482         setHelpText(QObject::tr(
    483                         "Inversion (Default: Auto):\n"
    484                         "Most cards can autodetect this now, so "
    485                         "leave it at Auto unless it won't work."));
    486         addSelection(QObject::tr("Auto"), "a",true);
    487         addSelection(QObject::tr("On"), "1");
    488         addSelection(QObject::tr("Off"), "0");
    489     };
    490 };
    491 
    492 class ScanBandwidth: public ComboBoxSetting, public TransientStorage
    493 {
    494   public:
    495     ScanBandwidth() : ComboBoxSetting(this)
    496     {
    497         setLabel(QObject::tr("Bandwidth"));
    498         setHelpText(QObject::tr("Bandwidth (Default: Auto)\n"));
    499         addSelection(QObject::tr("Auto"),"a",true);
    500         addSelection(QObject::tr("6 MHz"),"6");
    501         addSelection(QObject::tr("7 MHz"),"7");
    502         addSelection(QObject::tr("8 MHz"),"8");
    503     };
    504 };
    505 
    506 class ScanModulationSetting: public ComboBoxSetting
    507 {
    508   public:
    509     ScanModulationSetting(Storage *_storage) : ComboBoxSetting(_storage)
    510     {
    511         addSelection(QObject::tr("Auto"),"auto",true);
    512         addSelection("QPSK","qpsk");
    513 #ifdef FE_GET_EXTENDED_INFO
    514         addSelection("8PSK","8psk");
    515 #endif
    516         addSelection("QAM 16","qam_16");
    517         addSelection("QAM 32","qam_32");
    518         addSelection("QAM 64","qam_64");
    519         addSelection("QAM 128","qam_128");
    520         addSelection("QAM 256","qam_256");
    521     };
    522 };
    523 
    524 class ScanModulation: public ScanModulationSetting, public TransientStorage
    525 {
    526   public:
    527     ScanModulation() : ScanModulationSetting(this)
    528     {
    529         setLabel(QObject::tr("Modulation"));
    530         setHelpText(QObject::tr("Modulation (Default: Auto)"));
    531     };
    532 };
    533 
    534 class ScanConstellation: public ScanModulationSetting,
    535                          public TransientStorage
    536 {
    537   public:
    538     ScanConstellation() : ScanModulationSetting(this)
    539     {
    540         setLabel(QObject::tr("Constellation"));
    541         setHelpText(QObject::tr("Constellation (Default: Auto)"));
    542     };
    543 };
    544 
    545 class ScanFecSetting: public ComboBoxSetting
    546 {
    547   public:
    548     ScanFecSetting(Storage *_storage) : ComboBoxSetting(_storage)
    549     {
    550         addSelection(QObject::tr("Auto"),"auto",true);
    551         addSelection(QObject::tr("None"),"none");
    552         addSelection("1/2");
    553         addSelection("2/3");
    554         addSelection("3/4");
    555         addSelection("4/5");
    556         addSelection("5/6");
    557         addSelection("6/7");
    558         addSelection("7/8");
    559         addSelection("8/9");
    560     }
    561 };
    562 
    563 class ScanFec: public ScanFecSetting, public TransientStorage
    564 {
    565   public:
    566     ScanFec() : ScanFecSetting(this)
    567     {
    568         setLabel(QObject::tr("FEC"));
    569         setHelpText(QObject::tr(
    570                         "Forward Error Correction (Default: Auto)"));
    571     }
    572 };
    573 
    574 class ScanCodeRateLP: public ScanFecSetting, public TransientStorage
    575 {
    576   public:
    577     ScanCodeRateLP() : ScanFecSetting(this)
    578     {
    579         setLabel(QObject::tr("LP Coderate"));
    580         setHelpText(QObject::tr("Low Priority Code Rate (Default: Auto)"));
    581     }
    582 };
    583 
    584 class ScanCodeRateHP: public ScanFecSetting, public TransientStorage
    585 {
    586   public:
    587     ScanCodeRateHP() : ScanFecSetting(this)
    588     {
    589         setLabel(QObject::tr("HP Coderate"));
    590         setHelpText(QObject::tr("High Priority Code Rate (Default: Auto)"));
    591     };
    592 };
    593 
    594 class ScanGuardInterval: public ComboBoxSetting, public TransientStorage
    595 {
    596   public:
    597     ScanGuardInterval() : ComboBoxSetting(this)
    598     {
    599         setLabel(QObject::tr("Guard Interval"));
    600         setHelpText(QObject::tr("Guard Interval (Default: Auto)"));
    601         addSelection(QObject::tr("Auto"),"auto");
    602         addSelection("1/4");
    603         addSelection("1/8");
    604         addSelection("1/16");
    605         addSelection("1/32");
    606     };
    607 };
    608 
    609 class ScanTransmissionMode: public ComboBoxSetting, public TransientStorage
    610 {
    611   public:
    612     ScanTransmissionMode() : ComboBoxSetting(this)
    613     {
    614         setLabel(QObject::tr("Trans. Mode"));
    615         setHelpText(QObject::tr("Transmission Mode (Default: Auto)"));
    616         addSelection(QObject::tr("Auto"),"a");
    617         addSelection("2K","2");
    618         addSelection("8K","8");
    619     };
    620 };
    621 
    622 class ScanHierarchy: public ComboBoxSetting, public TransientStorage
    623 {
    624     public:
    625     ScanHierarchy() : ComboBoxSetting(this)
    626     {
    627         setLabel(QObject::tr("Hierarchy"));
    628         setHelpText(QObject::tr("Hierarchy (Default: Auto)"));
    629         addSelection(QObject::tr("Auto"),"a");
    630         addSelection(QObject::tr("None"), "n");
    631         addSelection("1");
    632         addSelection("2");
    633         addSelection("4");
    634     };
    635 };
    636 
    637 class OFDMPane : public HorizontalConfigurationGroup
    638 {
    639   public:
    640     OFDMPane() : HorizontalConfigurationGroup(false, false, true, true)
    641     {
    642         setUseFrame(false);
    643         VerticalConfigurationGroup *left =
    644             new VerticalConfigurationGroup(false,true,true,false);
    645         VerticalConfigurationGroup *right =
    646             new VerticalConfigurationGroup(false,true,true,false);
    647         left->addChild(pfrequency       = new ScanFrequency());
    648         left->addChild(pbandwidth       = new ScanBandwidth());
    649         left->addChild(pinversion       = new ScanInversion());
    650         left->addChild(pconstellation   = new ScanConstellation());
    651         right->addChild(pcoderate_lp    = new ScanCodeRateLP());
    652         right->addChild(pcoderate_hp    = new ScanCodeRateHP());
    653         right->addChild(ptrans_mode     = new ScanTransmissionMode());
    654         right->addChild(pguard_interval = new ScanGuardInterval());
    655         right->addChild(phierarchy      = new ScanHierarchy());
    656         addChild(left);
    657         addChild(right);
    658     }
    659 
    660     QString frequency(void)      const { return pfrequency->getValue();     }
    661     QString bandwidth(void)      const { return pbandwidth->getValue();     }
    662     QString inversion(void)      const { return pinversion->getValue();     }
    663     QString constellation(void)  const { return pconstellation->getValue(); }
    664     QString coderate_lp(void)    const { return pcoderate_lp->getValue();   }
    665     QString coderate_hp(void)    const { return pcoderate_hp->getValue();   }
    666     QString trans_mode(void)     const { return ptrans_mode->getValue();    }
    667     QString guard_interval(void) const { return pguard_interval->getValue(); }
    668     QString hierarchy(void)      const { return phierarchy->getValue();     }
    669 
    670   protected:
    671     ScanFrequency        *pfrequency;
    672     ScanInversion        *pinversion;
    673     ScanBandwidth        *pbandwidth;
    674     ScanConstellation    *pconstellation;
    675     ScanCodeRateLP       *pcoderate_lp;
    676     ScanCodeRateHP       *pcoderate_hp;
    677     ScanTransmissionMode *ptrans_mode;
    678     ScanGuardInterval    *pguard_interval;
    679     ScanHierarchy        *phierarchy;
    680 };
    681 
    682 class DVBS2Pane : public HorizontalConfigurationGroup
    683 {
    684   public:
    685     DVBS2Pane() : HorizontalConfigurationGroup(false,false,true,false)
    686     {
    687         setUseFrame(false);
    688         VerticalConfigurationGroup *left =
    689             new VerticalConfigurationGroup(false,true);
    690         VerticalConfigurationGroup *right =
    691             new VerticalConfigurationGroup(false,true);
    692         left->addChild( pfrequency  = new ScanFrequency());
    693         left->addChild( ppolarity   = new ScanPolarity());
    694         left->addChild( psymbolrate = new ScanSymbolRate());
    695         right->addChild(pfec        = new ScanFec());
    696         right->addChild(pmodulation = new ScanModulation());
    697         right->addChild(pinversion  = new ScanInversion());
    698         addChild(left);
    699         addChild(right);
    700     }
    701 
    702     QString frequency(void)  const { return pfrequency->getValue();  }
    703     QString symbolrate(void) const { return psymbolrate->getValue(); }
    704     QString inversion(void)  const { return pinversion->getValue();  }
    705     QString fec(void)        const { return pfec->getValue();        }
    706     QString polarity(void)   const { return ppolarity->getValue();   }
    707     QString modulation(void) const { return pmodulation->getValue(); }
    708 
    709   protected:
    710     ScanFrequency  *pfrequency;
    711     ScanSymbolRate *psymbolrate;
    712     ScanInversion  *pinversion;
    713     ScanFec        *pfec;
    714     ScanPolarity   *ppolarity;
    715     ScanModulation *pmodulation;
    716 };
    717 
    718 class QPSKPane : public HorizontalConfigurationGroup
    719 {
    720   public:
    721     QPSKPane() : HorizontalConfigurationGroup(false, false, true, false)
    722     {
    723         setUseFrame(false);
    724         VerticalConfigurationGroup *left =
    725             new VerticalConfigurationGroup(false,true);
    726         VerticalConfigurationGroup *right =
    727             new VerticalConfigurationGroup(false,true);
    728         left->addChild(pfrequency  = new ScanFrequency(true));
    729         left->addChild(ppolarity   = new ScanPolarity());
    730         left->addChild(psymbolrate = new ScanSymbolRate());
    731         right->addChild(pfec       = new ScanFec());
    732         right->addChild(pinversion = new ScanInversion());
    733         addChild(left);
    734         addChild(right);
    735     }
    736 
    737     QString frequency(void)  const { return pfrequency->getValue();  }
    738     QString symbolrate(void) const { return psymbolrate->getValue(); }
    739     QString inversion(void)  const { return pinversion->getValue();  }
    740     QString fec(void)        const { return pfec->getValue();        }
    741     QString polarity(void)   const { return ppolarity->getValue();   }
    742 
    743   protected:
    744     ScanFrequency  *pfrequency;
    745     ScanSymbolRate *psymbolrate;
    746     ScanInversion  *pinversion;
    747     ScanFec        *pfec;
    748     ScanPolarity   *ppolarity;
    749 };
    750 
    751 class QAMPane : public HorizontalConfigurationGroup
    752 {
    753   public:
    754     QAMPane() : HorizontalConfigurationGroup(false, false, true, false)
    755     {
    756         setUseFrame(false);
    757         VerticalConfigurationGroup *left =
    758             new VerticalConfigurationGroup(false,true);
    759         VerticalConfigurationGroup *right =
    760             new VerticalConfigurationGroup(false,true);
    761         left->addChild(pfrequency   = new ScanFrequency());
    762         left->addChild(psymbolrate  = new ScanSymbolRate());
    763         left->addChild(pinversion   = new ScanInversion());
    764         right->addChild(pmodulation = new ScanModulation());
    765         right->addChild(pfec        = new ScanFec());
    766         addChild(left);
    767         addChild(right);
    768     }
    769 
    770     QString frequency(void)  const { return pfrequency->getValue();  }
    771     QString symbolrate(void) const { return psymbolrate->getValue(); }
    772     QString inversion(void)  const { return pinversion->getValue();  }
    773     QString fec(void)        const { return pfec->getValue();        }
    774     QString modulation(void) const { return pmodulation->getValue(); }
    775 
    776   protected:
    777     ScanFrequency  *pfrequency;
    778     ScanSymbolRate *psymbolrate;
    779     ScanInversion  *pinversion;
    780     ScanModulation *pmodulation;
    781     ScanFec        *pfec;
    782 };
    783 
    784 class ATSCPane : public VerticalConfigurationGroup
    785 {
    786   public:
    787     ATSCPane() : VerticalConfigurationGroup(false, false, true, false)
    788     {
    789         addChild(atsc_table            = new ScanFrequencyTable());
    790         addChild(atsc_modulation       = new ScanATSCModulation());
    791         addChild(atsc_format           = new ScanATSCChannelFormat());
    792         addChild(old_channel_treatment = new ScanOldChannelTreatment());
    793     }
    794 
    795     QString atscFreqTable(void)  const { return atsc_table->getValue();      }
    796     QString atscModulation(void) const { return atsc_modulation->getValue(); }
    797     QString GetATSCFormat(void)  const { return atsc_format->getValue();     }
    798     bool DoDeleteChannels(void) const
    799         { return old_channel_treatment->getValue() == "delete"; }
    800     bool DoRenameChannels(void) const
    801         { return old_channel_treatment->getValue() == "rename"; }
    802 
    803     void SetDefaultATSCFormat(const QString &d)
    804     {
    805         int val = atsc_format->getValueIndex(d);
    806         atsc_format->setValue(val);
    807     }
    808 
    809   protected:
    810     ScanFrequencyTable      *atsc_table;
    811     ScanATSCModulation      *atsc_modulation;
    812     ScanATSCChannelFormat   *atsc_format;
    813     ScanOldChannelTreatment *old_channel_treatment;
    814 };
    815 
    816 class AnalogPane : public VerticalConfigurationGroup
    817 {
    818   public:
    819     AnalogPane();
    820 
    821     void SetSourceID(uint sourceid);
    822 
    823     QString GetFrequencyTable(void) const;
    824 
    825     bool DoDeleteChannels(void) const
    826         { return old_channel_treatment->getValue() == "delete"; }
    827     bool DoRenameChannels(void) const
    828         { return old_channel_treatment->getValue() == "rename"; }
    829 
    830   protected:
    831     TransFreqTableSelector  *freq_table;
    832     ScanOldChannelTreatment *old_channel_treatment;
    833 };
    834 
    835 class STPane : public VerticalConfigurationGroup
    836 {
    837   public:
    838     STPane() :
    839         VerticalConfigurationGroup(false, false, true, false),
    840         transport_setting(new MultiplexSetting()),
    841         atsc_format(new ScanATSCChannelFormat()),
    842         old_channel_treatment(new ScanOldChannelTreatment()),
    843         ignore_signal_timeout(new IgnoreSignalTimeout())
    844     {
    845         addChild(transport_setting);
    846         addChild(atsc_format);
    847         addChild(old_channel_treatment);
    848         addChild(ignore_signal_timeout);
    849     }
    850 
    851     QString GetATSCFormat(void) const { return atsc_format->getValue(); }
    852     bool DoDeleteChannels(void) const
    853         { return old_channel_treatment->getValue() == "delete"; }
    854     bool DoRenameChannels(void) const
    855         { return old_channel_treatment->getValue() == "rename"; }
    856     int  GetMultiplex(void) const
    857         { return transport_setting->getValue().toInt(); }
    858     bool ignoreSignalTimeout(void) const
    859         { return ignore_signal_timeout->getValue().toInt(); }
    860 
    861     void SetDefaultATSCFormat(const QString &d)
    862     {
    863         int val = atsc_format->getValueIndex(d);
    864         atsc_format->setValue(val);
    865     }
    866 
    867     void SetSourceID(uint sourceid)
    868         { transport_setting->SetSourceID(sourceid); }
    869 
    870   protected:
    871     MultiplexSetting        *transport_setting;
    872     ScanATSCChannelFormat   *atsc_format;
    873     ScanOldChannelTreatment *old_channel_treatment;
    874     IgnoreSignalTimeout     *ignore_signal_timeout;
    875 };
    876 
    877 class DVBUtilsImportPane : public VerticalConfigurationGroup
    878 {
    879     Q_OBJECT
    880 
    881   public:
    882     DVBUtilsImportPane() :
    883         VerticalConfigurationGroup(false,false,true,false),
    884         filename(new TransLineEditSetting()),
    885         atsc_format(new ScanATSCChannelFormat()),
    886         old_channel_treatment(new ScanOldChannelTreatment()),
    887         ignore_signal_timeout(new IgnoreSignalTimeout())
    888     {
    889         filename->setLabel(tr("File location"));
    890         filename->setHelpText(tr("Location of the channels.conf file."));
    891         addChild(filename);
    892 
    893         addChild(atsc_format);
    894         addChild(old_channel_treatment);
    895         addChild(ignore_signal_timeout);
    896     }
    897 
    898     QString GetFilename(void)   const { return filename->getValue();    }
    899     QString GetATSCFormat(void) const { return atsc_format->getValue(); }
    900 
    901     bool DoDeleteChannels(void) const
    902         { return old_channel_treatment->getValue() == "delete"; }
    903     bool DoRenameChannels(void) const
    904         { return old_channel_treatment->getValue() == "rename"; }
    905     bool DoIgnoreSignalTimeout(void) const
    906         { return ignore_signal_timeout->getValue().toInt(); }
    907 
    908     void SetDefaultATSCFormat(const QString &d)
    909     {
    910         int val = atsc_format->getValueIndex(d);
    911         atsc_format->setValue(val);
    912     }
    913 
    914   private:
    915     TransLineEditSetting    *filename;
    916     ScanATSCChannelFormat   *atsc_format;
    917     ScanOldChannelTreatment *old_channel_treatment;
    918     IgnoreSignalTimeout     *ignore_signal_timeout;
    919 };
    920 
    921 class ErrorPane : public HorizontalConfigurationGroup
    922 {
    923   public:
    924     ErrorPane(const QString &error) :
    925         HorizontalConfigurationGroup(false, false, true, false)
    926     {
    927         TransLabelSetting* label = new TransLabelSetting();
    928         label->setValue(error);
    929         addChild(label);
    930     }
    931 };
    932 
    933 class BlankSetting: public TransLabelSetting
    934 {
    935   public:
    936     BlankSetting() : TransLabelSetting()
    937     {
    938         setLabel("");
    939     }
    940 };
    941 
    942 #endif // SCANWIZARDHELPERS_H
  • libs/libmythtv/scanwizardscanner.cpp

     
    1 /* -*- Mode: c++ -*-
    2  * vim: set expandtab tabstop=4 shiftwidth=4:
    3  *
    4  * Original Project
    5  *      MythTV      http://www.mythtv.org
    6  *
    7  * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>
    8  * Copyright (c) 2005 - 2007 Daniel Kristjansson
    9  *
    10  * Description:
    11  *     Collection of classes to provide channel scanning functionallity
    12  *
    13  * This program is free software; you can redistribute it and/or
    14  * modify it under the terms of the GNU General Public License
    15  * as published by the Free Software Foundation; either version 2
    16  * of the License, or (at your option) any later version.
    17  *
    18  * This program is distributed in the hope that it will be useful,
    19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    21  * GNU General Public License for more details.
    22  *
    23  * You should have received a copy of the GNU General Public License
    24  * along with this program; if not, write to the Free Software
    25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    26  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    27  *
    28  */
    29 
    30 // System headers
    31 #include <unistd.h>
    32 
    33 // Qt headers
    34 #include <QApplication>
    35 #include <QEvent>
    36 
    37 // MythTV headers
    38 #include "mythcontext.h"
    39 #include "mythverbose.h"
    40 #include "scanwizard.h"
    41 #include "scanwizardhelpers.h"
    42 #include "scanwizardscanner.h"
    43 #include "channelbase.h"
    44 #include "dtvsignalmonitor.h"
    45 #include "siscan.h"
    46 #include "dtvconfparser.h"
    47 
    48 #ifdef USING_V4L
    49 #include "v4lchannel.h"
    50 #include "analogsignalmonitor.h"
    51 #endif
    52 
    53 #ifdef USING_DVB
    54 #include "dvbchannel.h"
    55 #include "dvbsignalmonitor.h"
    56 #endif
    57 
    58 #ifdef USING_HDHOMERUN
    59 #include "hdhrchannel.h"
    60 #include "hdhrsignalmonitor.h"
    61 #endif
    62 
    63 #ifdef USING_IPTV
    64 #include "iptvchannelfetcher.h"
    65 #endif
    66 
    67 #define LOC QString("SWizScan: ")
    68 #define LOC_ERR QString("SWizScan, Error: ")
    69 
    70 /// Percentage to set to after the transports have been scanned
    71 #define TRANSPORT_PCT 6
    72 /// Percentage to set to after the first tune
    73 #define TUNED_PCT     3
    74 
    75 QString ScanWizardScanner::kTitle = QString::null;
    76 
    77 // kTitel must be initialized after the Qt translation system is initialized...
    78 static void init_statics(void)
    79 {
    80     static QMutex lock;
    81     static bool do_init = true;
    82     QMutexLocker locker(&lock);
    83     if (do_init)
    84     {
    85         ScanWizardScanner::kTitle = ScanWizardScanner::tr("Scanning");
    86         do_init = false;
    87     }
    88 }
    89 
    90 ScanWizardScanner::ScanWizardScanner(void)
    91     : VerticalConfigurationGroup(false, true, false, false),
    92       log(new LogList()), channel(NULL), popupProgress(NULL),
    93       scanner(NULL), freeboxScanner(NULL), nVideoSource(0)
    94 {
    95     init_statics();
    96 
    97     setLabel(kTitle);
    98     addChild(log);
    99 }
    100 
    101 ScanWizardScanner::~ScanWizardScanner()
    102 {
    103     Teardown();
    104 
    105     QMutexLocker locker(&popupLock);
    106     StopPopup();
    107 }
    108 
    109 void ScanWizardScanner::Teardown()
    110 {
    111     // Join the thread and close the channel
    112     if (scanner)
    113     {
    114         scanner->deleteLater();
    115         scanner = NULL;
    116     }
    117 
    118     if (channel)
    119     {
    120         delete channel;
    121         channel = NULL;
    122     }
    123 
    124 #ifdef USING_IPTV
    125     if (freeboxScanner)
    126     {
    127         freeboxScanner->Stop();
    128         freeboxScanner->deleteLater();
    129         freeboxScanner = NULL;
    130     }
    131 #endif
    132 }
    133 
    134 void ScanWizardScanner::customEvent(QEvent *e)
    135 {
    136     ScannerEvent *scanEvent = (ScannerEvent*) e;
    137 
    138     switch (scanEvent->eventType())
    139     {
    140         case ScannerEvent::ScanComplete:
    141         {
    142             QMutexLocker locker(&popupLock);
    143             if (popupProgress)
    144             {
    145                 popupProgress->SetScanProgress(1.0);
    146                 popupProgress->accept();
    147             }
    148         }
    149         break;
    150 
    151         case ScannerEvent::ScanShutdown:
    152         {
    153             if (scanEvent->ScanProgressPopupValue())
    154             {
    155                 ScanProgressPopup *spp = scanEvent->ScanProgressPopupValue();
    156                 spp->DeleteDialog();
    157                 spp->deleteLater();
    158             }
    159 
    160             Teardown();
    161         }
    162         break;
    163 
    164         case ScannerEvent::AppendTextToLog:
    165         {
    166             log->updateText(scanEvent->strValue());
    167         }
    168         break;
    169 
    170         default:
    171             break;
    172     }
    173 
    174     QMutexLocker locker(&popupLock);
    175     if (!popupProgress)
    176         return;
    177 
    178     switch (scanEvent->eventType())
    179     {
    180         case ScannerEvent::SetStatusText:
    181             popupProgress->SetStatusText(scanEvent->strValue());
    182             break;
    183         case ScannerEvent::SetStatusTitleText:
    184             popupProgress->SetStatusTitleText(scanEvent->strValue());
    185             break;
    186         case ScannerEvent::SetPercentComplete:
    187             popupProgress->SetScanProgress(scanEvent->intValue() * 0.01);
    188             break;
    189         case ScannerEvent::SetStatusSignalLock:
    190             popupProgress->SetStatusLock(scanEvent->intValue());
    191             break;
    192         case ScannerEvent::SetStatusSignalToNoise:
    193             popupProgress->SetStatusSignalToNoise(scanEvent->intValue());
    194             break;
    195         case ScannerEvent::SetStatusSignalStrength:
    196             popupProgress->SetStatusSignalStrength(scanEvent->intValue());
    197             break;
    198         default:
    199             break;
    200     }
    201 }
    202 
    203 void ScanWizardScanner::scanComplete()
    204 {
    205     ScannerEvent::TYPE se = ScannerEvent::ScanComplete;
    206     QApplication::postEvent(this, new ScannerEvent(se));
    207 }
    208 
    209 void ScanWizardScanner::transportScanComplete()
    210 {
    211     scanner->ScanServicesSourceID(nVideoSource);
    212     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
    213     e->intValue(TRANSPORT_PCT);
    214     QApplication::postEvent(this, e);
    215 }
    216 
    217 void ScanWizardScanner::serviceScanPctComplete(int pct)
    218 {
    219     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
    220     int tmp = TRANSPORT_PCT + ((100 - TRANSPORT_PCT) * pct)/100;
    221     e->intValue(tmp);
    222     QApplication::postEvent(this, e);
    223 }
    224 
    225 void ScanWizardScanner::updateText(const QString &str)
    226 {
    227     if (str.isEmpty())
    228         return;
    229     ScannerEvent* e = new ScannerEvent(ScannerEvent::AppendTextToLog);
    230     e->strValue(str);
    231     QApplication::postEvent(this, e);
    232 }
    233 
    234 void ScanWizardScanner::updateStatusText(const QString &str)
    235 {
    236     QString msg = tr("Scanning");
    237     if (!str.isEmpty())
    238         msg = QString("%1 %2").arg(msg).arg(str);
    239 
    240     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusText);
    241     e->strValue(msg);
    242     QApplication::postEvent(this, e);
    243 }
    244 
    245 void ScanWizardScanner::StatusSignalLock(const SignalMonitorValue &val)
    246 {
    247     dvbLock(val.GetValue());
    248 }
    249 
    250 void ScanWizardScanner::StatusSignalToNoise(const SignalMonitorValue &val)
    251 {
    252     dvbSNR(val.GetNormalizedValue(0, 65535));
    253 }
    254 
    255 void ScanWizardScanner::StatusSignalStrength(const SignalMonitorValue &val)
    256 {
    257     dvbSignalStrength(val.GetNormalizedValue(0, 65535));
    258 }
    259 
    260 void ScanWizardScanner::dvbLock(int locked)
    261 {
    262     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalLock);
    263     e->intValue(locked);
    264     QApplication::postEvent(this, e);
    265 }
    266 
    267 void ScanWizardScanner::dvbSNR(int i)
    268 {
    269     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalToNoise);
    270     e->intValue(i);
    271     QApplication::postEvent(this, e);
    272 }
    273 
    274 void ScanWizardScanner::dvbSignalStrength(int i)
    275 {
    276     ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalStrength);
    277     e->intValue(i);
    278     QApplication::postEvent(this, e);
    279 }
    280 
    281 // full scan of existing transports broken
    282 // existing transport scan broken
    283 void ScanWizardScanner::Scan(
    284     int            scantype,
    285     uint           cardid,
    286     const QString &inputname,
    287     uint           sourceid,
    288     bool           do_delete_channels,
    289     bool           do_rename_channels,
    290     bool           do_ignore_signal_timeout,
    291     // stuff needed for particular scans
    292     uint           mplexid /* TransportScan */,
    293     const QMap<QString,QString> &startChan /* NITAddScan */,
    294     const QString &freq_std /* FullScan */,
    295     const QString &mod /* FullScan */,
    296     const QString &tbl /* FullScan */,
    297     const QString &atsc_format /* any ATSC scan */)
    298 {
    299     nVideoSource = sourceid;
    300     PreScanCommon(scantype, cardid, inputname,
    301                   sourceid, do_ignore_signal_timeout);
    302 
    303     VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete()");
    304 
    305     if (!scanner)
    306     {
    307         VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete(): "
    308                 "scanner does not exist...");
    309         return;
    310     }
    311 
    312     scanner->StartScanner();
    313     updateStatusText("");
    314 
    315     bool ok = false;
    316 
    317     if (do_delete_channels && (ScanTypeSetting::TransportScan == scantype))
    318     {
    319         MSqlQuery query(MSqlQuery::InitCon());
    320         query.prepare("DELETE FROM channel "
    321                       "WHERE sourceid = :SOURCEID AND "
    322                       "      mplexid  = :MPLEXID");
    323         query.bindValue(":SOURCEID", sourceid);
    324         query.bindValue(":MPLEXID",  mplexid);
    325         query.exec();
    326     }
    327     else if (do_delete_channels)
    328     {
    329         MSqlQuery query(MSqlQuery::InitCon());
    330         query.prepare("DELETE FROM channel "
    331                       "WHERE sourceid = :SOURCEID");
    332         query.bindValue(":SOURCEID", sourceid);
    333         query.exec();
    334 
    335         if (ScanTypeSetting::TransportScan != scantype)
    336         {
    337             query.prepare("DELETE FROM dtv_multiplex "
    338                           "WHERE sourceid = :SOURCEID");
    339             query.bindValue(":SOURCEID", sourceid);
    340             query.exec();
    341         }
    342     }
    343 
    344     scanner->SetChannelFormat(atsc_format);
    345     scanner->SetRenameChannels(do_rename_channels);
    346 
    347     if ((ScanTypeSetting::FullScan_ATSC   == scantype) ||
    348         (ScanTypeSetting::FullScan_OFDM   == scantype) ||
    349         (ScanTypeSetting::FullScan_Analog == scantype))
    350     {
    351         VERBOSE(VB_SIPARSER, LOC +
    352                 "ScanTransports("<<freq_std<<", "<<mod<<", "<<tbl<<")");
    353 
    354         // HACK HACK HACK -- begin
    355         // if using QAM we may need additional time... (at least with HD-3000)
    356         if ((mod.left(3).toLower() == "qam") &&
    357             (scanner->GetSignalTimeout() < 1000))
    358         {
    359             scanner->SetSignalTimeout(1000);
    360         }
    361         // HACK HACK HACK -- end
    362 
    363         scanner->SetAnalog(ScanTypeSetting::FullScan_Analog == scantype);
    364 
    365         ok = scanner->ScanTransports(sourceid, freq_std, mod, tbl);
    366     }
    367     else if ((ScanTypeSetting::NITAddScan_OFDM == scantype) ||
    368              (ScanTypeSetting::NITAddScan_QPSK == scantype) ||
    369              (ScanTypeSetting::NITAddScan_QAM  == scantype))
    370     {
    371         VERBOSE(VB_SIPARSER, LOC + "ScanTransports()");
    372 
    373         ok = scanner->ScanTransportsStartingOn(sourceid, startChan);
    374     }
    375     else if (ScanTypeSetting::FullTransportScan == scantype)
    376     {
    377         VERBOSE(VB_SIPARSER, LOC + "ScanServicesSourceID("<<sourceid<<")");
    378 
    379         ok = scanner->ScanServicesSourceID(sourceid);
    380         if (ok)
    381         {
    382             serviceScanPctComplete(0);
    383         }
    384         else
    385         {
    386             MythPopupBox::showOkPopup(gContext->GetMainWindow(),
    387                                       tr("ScanWizard"),
    388                                       tr("Error tuning to transport"));
    389             Teardown();
    390         }
    391     }
    392     else if ((ScanTypeSetting::DVBUtilsImport == scantype) && channels.size())
    393     {
    394         ok = true;
    395 
    396         VERBOSE(VB_SIPARSER, LOC + "ScanForChannels("<<sourceid<<")");
    397 
    398         QString card_type = CardUtil::GetRawCardType(cardid);
    399         QString sub_type  = card_type;
    400         if (card_type == "DVB")
    401         {
    402             QString device = CardUtil::GetVideoDevice(cardid);
    403 
    404             ok = !device.isEmpty();
    405             if (ok)
    406                 sub_type = CardUtil::ProbeDVBType(device).toUpper();
    407         }
    408 
    409         if (ok)
    410         {
    411             ok = scanner->ScanForChannels(sourceid, freq_std,
    412                                           sub_type, channels);
    413         }
    414         if (ok)
    415         {
    416             serviceScanPctComplete(0);
    417         }
    418         else
    419         {
    420             MythPopupBox::showOkPopup(gContext->GetMainWindow(),
    421                                       tr("ScanWizard"),
    422                                       tr("Error tuning to transport"));
    423             Teardown();
    424         }
    425     }
    426     else if (ScanTypeSetting::TransportScan == scantype)
    427     {
    428         VERBOSE(VB_SIPARSER, LOC + "ScanTransport("<<mplexid<<")");
    429 
    430         ok = scanner->ScanTransport(mplexid);
    431     }
    432 
    433     if (!ok)
    434     {
    435         VERBOSE(VB_IMPORTANT, "Failed to handle tune complete.");
    436     }
    437 }
    438 
    439 void ScanWizardScanner::ImportDVBUtils(uint sourceid, int cardtype,
    440                                        const QString &file)
    441 {
    442     channels.clear();
    443 
    444     DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN;
    445     type = (CardUtil::OFDM == cardtype) ? DTVConfParser::OFDM : type;
    446     type = (CardUtil::QPSK == cardtype) ? DTVConfParser::QPSK : type;
    447     type = (CardUtil::QAM  == cardtype) ? DTVConfParser::QAM  : type;
    448     type = ((CardUtil::ATSC == cardtype)||(CardUtil::HDHOMERUN == cardtype)) ?
    449         DTVConfParser::ATSC : type;
    450 
    451     if (type == DTVConfParser::UNKNOWN)
    452         return;
    453 
    454     DTVConfParser parser(type, sourceid, file);
    455 
    456     DTVConfParser::return_t ret = parser.Parse();
    457     if (DTVConfParser::OK != ret)
    458     {
    459         QString msg = (DTVConfParser::ERROR_PARSE == ret) ?
    460             tr("Failed to parse '%1'") : tr("Failed to open '%1'");
    461 
    462         MythPopupBox::showOkPopup(gContext->GetMainWindow(),
    463                                   tr("ScanWizard"), msg.arg(file));
    464     }
    465     else
    466     {
    467         channels = parser.GetChannels();
    468     }
    469 }
    470 
    471 void ScanWizardScanner::PreScanCommon(int scantype,
    472                                       uint cardid,
    473                                       const QString &inputname,
    474                                       uint sourceid,
    475                                       bool do_ignore_signal_timeout)
    476 {
    477     uint signal_timeout  = 1000;
    478     uint channel_timeout = 40000;
    479     CardUtil::GetTimeouts(cardid, signal_timeout, channel_timeout);
    480 
    481     QString device = CardUtil::GetVideoDevice(cardid);
    482     if (device.isEmpty())
    483     {
    484         VERBOSE(VB_IMPORTANT, "No Device");
    485         return;
    486     }
    487 
    488     QString card_type = CardUtil::GetRawCardType(cardid);
    489 
    490     if ("DVB" == card_type)
    491     {
    492         QString sub_type = CardUtil::ProbeDVBType(device).toUpper();
    493         bool need_nit = (("QAM"  == sub_type) ||
    494                          ("QPSK" == sub_type) ||
    495                          ("OFDM" == sub_type));
    496 
    497         // Ugh, Some DVB drivers don't fully support signal monitoring...
    498         if ((ScanTypeSetting::TransportScan     == scantype) ||
    499             (ScanTypeSetting::FullTransportScan == scantype))
    500         {
    501             signal_timeout = (do_ignore_signal_timeout) ?
    502                 channel_timeout * 10 : signal_timeout;
    503         }
    504 
    505         // Since we the NIT is only sent every 10 seconds, we add an
    506         // extra 20 + 2 seconds to the scan time for DVB countries.
    507         channel_timeout += (need_nit) ? 22 * 1000 : 0;
    508     }
    509 
    510 #ifdef USING_DVB
    511     if ("DVB" == card_type)
    512         channel = new DVBChannel(device);
    513 #endif
    514 
    515 #ifdef USING_V4L
    516     if (("V4L" == card_type) || ("MPEG" == card_type) ||
    517         ("HDPVR" == card_type))
    518     {
    519         channel = new V4LChannel(NULL, device);
    520     }
    521 #endif
    522 
    523 #ifdef USING_HDHOMERUN
    524     if ("HDHOMERUN" == card_type)
    525     {
    526         uint tuner = CardUtil::GetHDHRTuner(cardid);
    527         channel = new HDHRChannel(NULL, device, tuner);
    528     }
    529 #endif // USING_HDHOMERUN
    530 
    531     if (!channel)
    532     {
    533         VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel not created");
    534         return;
    535     }
    536 
    537     // explicitly set the cardid
    538     channel->SetCardID(cardid);
    539 
    540     // If the backend is running this may fail...
    541     if (!channel->Open())
    542     {
    543         VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel could not be opened");
    544         return;
    545     }
    546 
    547     scanner = new SIScan(card_type, channel, sourceid, signal_timeout,
    548                          channel_timeout, inputname);
    549 
    550     scanner->SetForceUpdate(true);
    551 
    552     bool ftao = CardUtil::IgnoreEncrypted(cardid, inputname);
    553     scanner->SetFTAOnly(ftao);
    554 
    555     bool tvo = CardUtil::TVOnly(cardid, inputname);
    556     scanner->SetTVOnly(tvo);
    557 
    558     connect(scanner, SIGNAL(ServiceScanComplete(void)),
    559             this,    SLOT(  scanComplete(void)));
    560     connect(scanner, SIGNAL(TransportScanComplete(void)),
    561             this,    SLOT(  transportScanComplete(void)));
    562     connect(scanner, SIGNAL(ServiceScanUpdateStatusText(const QString&)),
    563             this,    SLOT(  updateStatusText(const QString&)));
    564     connect(scanner, SIGNAL(ServiceScanUpdateText(const QString&)),
    565             this,    SLOT(  updateText(const QString&)));
    566     connect(scanner, SIGNAL(TransportScanUpdateText(const QString&)),
    567             this,    SLOT(  updateText(const QString&)));
    568     connect(scanner, SIGNAL(PctServiceScanComplete(int)),
    569             this,    SLOT(  serviceScanPctComplete(int)));
    570 
    571     // Signal Meters are connected here
    572     SignalMonitor *monitor = scanner->GetSignalMonitor();
    573     if (monitor)
    574         monitor->AddListener(this);
    575    
    576     DVBSignalMonitor *dvbm = NULL;
    577 #ifdef USING_DVB
    578     dvbm = scanner->GetDVBSignalMonitor();
    579 #endif // USING_DVB
    580 
    581     MonitorProgress(monitor, monitor, dvbm);
    582 }
    583 
    584 void ScanWizardScanner::ImportM3U(uint cardid, const QString &inputname,
    585                                   uint sourceid)
    586 {
    587     (void) cardid;
    588     (void) inputname;
    589     (void) sourceid;
    590 
    591 #ifdef USING_IPTV
    592     //Create an analog scan object
    593     freeboxScanner = new IPTVChannelFetcher(cardid, inputname, sourceid);
    594 
    595     connect(freeboxScanner, SIGNAL(ServiceScanComplete(void)),
    596             this,           SLOT(  scanComplete(void)));
    597     connect(freeboxScanner, SIGNAL(ServiceScanUpdateText(const QString&)),
    598             this,           SLOT(  updateText(const QString&)));
    599     connect(freeboxScanner, SIGNAL(ServiceScanPercentComplete(int)),
    600             this,           SLOT(  serviceScanPctComplete(int)));
    601 
    602     MonitorProgress(false, false, false);
    603 
    604     if (!freeboxScanner->Scan())
    605     {
    606         MythPopupBox::showOkPopup(gContext->GetMainWindow(),
    607                                   tr("ScanWizard"),
    608                                   tr("Error starting scan"));
    609     }
    610 #endif // USING_IPTV
    611 }
    612 
    613 void *spawn_popup(void *tmp)
    614 {
    615     ((ScanWizardScanner*)(tmp))->RunPopup();
    616     return NULL;
    617 }
    618 
    619 void ScanWizardScanner::RunPopup(void)
    620 {
    621     DialogCode ret = popupProgress->exec();
    622 
    623     post_event(this, ScannerEvent::ScanShutdown, ret, popupProgress);
    624     popupProgress = NULL;
    625 }
    626 
    627 void ScanWizardScanner::StopPopup(void)
    628 {
    629     if (popupProgress)
    630     {
    631         popupProgress->reject();
    632         popupLock.unlock();
    633         pthread_join(popup_thread, NULL);
    634         popupLock.lock();
    635     }
    636 }
    637 
    638 void ScanWizardScanner::MonitorProgress(bool lock, bool strength, bool snr)
    639 {
    640     QMutexLocker locker(&popupLock);
    641     StopPopup();
    642     popupProgress = new ScanProgressPopup(lock, strength, snr);
    643     popupProgress->CreateDialog();
    644     if (pthread_create(&popup_thread, NULL, spawn_popup, this) != 0)
    645     {
    646         VERBOSE(VB_IMPORTANT, "Failed to start MonitorProgress thread");
    647         popupProgress->DeleteDialog();
    648         popupProgress->deleteLater();
    649         popupProgress = NULL;
    650     }
    651 }
  • libs/libmythtv/siscan.cpp

     
    1 // -*- Mode: c++ -*-
    2 
    3 // C includes
    4 #include <cstdio>
    5 #include <pthread.h>
    6 #include <unistd.h>
    7 
    8 // Qt includes
    9 #include <qmutex.h>
    10 
    11 // MythTV includes - General
    12 #include "siscan.h"
    13 #include "scheduledrecording.h"
    14 #include "frequencies.h"
    15 #include "mythdb.h"
    16 #include "channelutil.h"
    17 #include "cardutil.h"
    18 
    19 // MythTV includes - DTV
    20 #include "dtvsignalmonitor.h"
    21 #include "scanstreamdata.h"
    22 
    23 // MythTV includes - ATSC
    24 #include "atsctables.h"
    25 
    26 // MythTV includes - DVB
    27 #include "dvbsignalmonitor.h"
    28 #include "dvbtables.h"
    29 
    30 #include "dvbchannel.h"
    31 #include "hdhrchannel.h"
    32 #include "v4lchannel.h"
    33 #include "compat.h"
    34 
    35 QString SIScan::loc(const SIScan *siscan)
    36 {
    37     if (siscan && siscan->channel)
    38         return QString("SIScan(%1)").arg(siscan->channel->GetDevice());
    39     return "SIScan(u)";
    40 }
    41 
    42 #define LOC     (SIScan::loc(this) + ": ")
    43 #define LOC_ERR (SIScan::loc(this) + ", Error: ")
    44 
    45 /** \class SIScan
    46  *  \brief Scanning class for cards that support a SignalMonitor class.
    47  *
    48  *   Currently both SIParser and ScanStreamData are being used in
    49  *   this class. The SIParser is being phased out, so that is not
    50  *   described here.
    51  *
    52  *   With ScanStreamData, we call ScanTransport() on each transport
    53  *   and frequency offset in the list of transports. This list is
    54  *   created from a FrequencyTable object.
    55  *
    56  *   Each ScanTransport() call resets the ScanStreamData and the
    57  *   SignalMonitor, then tunes to a new frequency and notes the tuning
    58  *   time in the "timer" QTime object.
    59  *
    60  *   HandleActiveScan is called every time through the event loop
    61  *   and is what calls ScanTransport(), as well as checking when
    62  *   the current time is "timeoutTune" or "channelTimeout" milliseconds
    63  *   ahead of "timer". When the "timeoutTune" is exceeded we check
    64  *   to see if we have a signal lock on the channel, if we don't we
    65  *   check the next transport. When the larger "channelTimeout" is
    66  *   exceeded we do nothing unless "waitingForTables" is still true,
    67  *   if so we check if we at least got a PAT and if so we insert
    68  *    a channel based on that by calling HandleMPEGDBInsertion().
    69  *
    70  *   Meanwhile the ScanStreamData() emits several signals. For
    71  *   the UI it emits signal quality signals. For SIScan it emits
    72  *   UpdateMGT, UpdateVCT, UpdateNIT, and UpdateSDT signals. We
    73  *   connect these to the HandleMGT, HandleVCT, etc. These in
    74  *   turn just call HandleATSCDBInsertion() or
    75  *   HandleDVBDBInsertion() depending on the type of table.
    76  *
    77  *   HandleATSCDBInsertion() first checks if we have all the VCTs
    78  *   described in the MGT. If we do we call UpdateVCTinDB() for each
    79  *   TVCT and CVCT in the stream. UpdateVCTinDB() inserts the actual
    80  *   channels. Then we set "waitingForTables" to false, set the
    81  *   scanOffsetIt to 99 and updates the UI to reflect the added channel.
    82  *   HandleDVBDBInsertion() and HandleMPEGDBInsertion() are similar.
    83  */
    84 
    85 SIScan::SIScan(const QString &_cardtype, ChannelBase *_channel, int _sourceID,
    86                uint signal_timeout, uint channel_timeout,
    87                const QString &_inputname)
    88     : // Set in constructor
    89       channel(_channel),
    90       signalMonitor(SignalMonitor::Init(_cardtype, -1, _channel)),
    91       sourceID(_sourceID),
    92       scanMode(IDLE),
    93       signalTimeout(signal_timeout),
    94       channelTimeout(channel_timeout),
    95       inputname(_inputname),
    96       // Settable
    97       isAnalog(false),
    98       ignoreAudioOnlyServices(false),
    99       ignoreDataServices(false),
    100       ignoreEncryptedServices(false),
    101       forceUpdate(false),
    102       renameChannels(false),
    103       channelFormat("%1_%2"),
    104       // State
    105       threadExit(false),
    106       waitingForTables(false),
    107       // Transports List
    108       transportsScanned(0),
    109       // Misc
    110       scanner_thread_running(false)
    111 {
    112     inputname.detach();
    113 
    114     // Initialize statics
    115     current = transport_scan_items_it_t( scanTransports.end());
    116 
    117     signalMonitor->AddListener(this);
    118 
    119     // Create a stream data for digital signal monitors
    120     DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
    121     if (dtvSigMon)
    122     {
    123         VERBOSE(VB_SIPARSER, LOC + "Connecting up DTVSignalMonitor");
    124         ScanStreamData *data = new ScanStreamData();
    125 
    126         dtvSigMon->SetStreamData(data);
    127         dtvSigMon->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT |
    128                             SignalMonitor::kDTVSigMon_WaitForVCT |
    129                             SignalMonitor::kDTVSigMon_WaitForNIT |
    130                             SignalMonitor::kDTVSigMon_WaitForSDT);
    131 
    132         data->AddMPEGListener(this);
    133         data->AddATSCMainListener(this);
    134         data->AddDVBMainListener(this);
    135     }
    136 }
    137 
    138 SIScan::~SIScan(void)
    139 {
    140     // Use deleteLater() instead
    141     StopScanner();
    142     VERBOSE(VB_SIPARSER, LOC + "SIScanner dtor");
    143 }
    144 
    145 void SIScan::deleteLater(void)
    146 {
    147     disconnect();
    148     StopScanner();
    149     VERBOSE(VB_SIPARSER, LOC + "SIScanner Stopped");
    150     channel = 0; // Deleted by caller
    151     teardown_frequency_tables();
    152     QObject::deleteLater();
    153 }
    154 
    155 void SIScan::AllGood(void)
    156 {
    157     if (!isAnalog)
    158         return;
    159 
    160     QString cur_chan = (*current).FriendlyName;
    161     QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
    162     QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
    163 
    164     bool ok = false;
    165 
    166     QString msg = tr("Updated Channel %1").arg(cur_chan);
    167 
    168     if (!ChannelUtil::FindChannel(sourceID, freqid))
    169     {
    170         int chanid = ChannelUtil::CreateChanID(sourceID, freqid);
    171 
    172         QString callsign = QString("%1%2")
    173             .arg(ChannelUtil::GetUnknownCallsign()).arg(freqid);
    174 
    175         ok = ChannelUtil::CreateChannel(
    176             0      /* mplexid */,
    177             sourceID,
    178             chanid,
    179             callsign,
    180             ""     /* service name       */,
    181             freqid /* channum            */,
    182             0      /* service id         */,
    183             0      /* ATSC major channel */,
    184             0      /* ATSC minor channel */,
    185             false  /* use on air guide   */,
    186             false  /* hidden             */,
    187             false  /* hidden in guide    */,
    188             freqid);
    189 
    190         msg = (ok) ?
    191             tr("Added Channel %1").arg(cur_chan) :
    192             tr("Failed to add channel %1").arg(cur_chan);
    193     }
    194     else
    195     {
    196         // nothing to do here, XMLTV & DataDirect have better info
    197     }
    198 
    199     emit ServiceScanUpdateText(msg);
    200 
    201     // tell UI we are done with these channels
    202     if (scanMode == TRANSPORT_LIST)
    203     {
    204         UpdateScanPercentCompleted();
    205         waitingForTables = false;
    206         nextIt = current.nextTransport();
    207     }
    208 }
    209 
    210 /** \fn SIScan::ScanServicesSourceID(int)
    211  *  \brief If we are not already scanning a frequency table, this creates
    212  *         a new frequency table from database and begins scanning it.
    213  *
    214  *   This is used by DVB to scan for channels we are told about from other
    215  *   channels.
    216  *
    217  *   Note: Something similar could be used with ATSC when EIT for other
    218  *   channels is available on another ATSC channel, as encouraged by the
    219  *   ATSC specification.
    220  */
    221 bool SIScan::ScanServicesSourceID(int SourceID)
    222 {
    223     if (scanMode == TRANSPORT_LIST)
    224         return false;
    225 
    226     nextIt = transport_scan_items_it_t( scanTransports.end() );
    227 
    228     MSqlQuery query(MSqlQuery::InitCon());
    229     // Run DB query to get transports on sourceid SourceID
    230     // connected to this card
    231     QString theQuery = QString(
    232         "SELECT sourceid, mplexid, sistandard, transportid "
    233         "FROM dtv_multiplex WHERE sourceid = %1").arg(SourceID);
    234     query.prepare(theQuery);
    235 
    236     if (!query.exec() || !query.isActive())
    237     {
    238         MythDB::DBError("Get Transports for SourceID", query);
    239         return false;
    240     }
    241 
    242     if (query.size() <= 0)
    243     {
    244         VERBOSE(VB_SIPARSER, LOC + "Unable to find any transports for " +
    245                 QString("sourceid %1").arg(sourceID));
    246 
    247         return false;
    248     }
    249 
    250     while (query.next())
    251     {
    252         int sourceid = query.value(0).toInt();
    253         int mplexid  = query.value(1).toInt();
    254         QString std  = query.value(2).toString();
    255         int tsid     = query.value(3).toInt();
    256 
    257         QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
    258             QString("Multiplex #%1").arg(mplexid);
    259 
    260         VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
    261 
    262         TransportScanItem item(sourceid, std, fn, mplexid, signalTimeout);
    263         scanTransports += item;
    264     }
    265 
    266     waitingForTables  = false;
    267     transportsScanned = 0;
    268     if (scanTransports.size())
    269     {
    270         nextIt        = transport_scan_items_it_t(scanTransports.begin());
    271         scanMode      = TRANSPORT_LIST;
    272         return true;
    273     }
    274 
    275     return false;
    276 }
    277 
    278 void SIScan::HandlePAT(const ProgramAssociationTable *pat)
    279 {
    280     VERBOSE(VB_SIPARSER, LOC +
    281             QString("Got a Program Association Table for %1")
    282             .arg((*current).FriendlyName));
    283 
    284     // Add pmts to list, so we can do MPEG scan properly.
    285     ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
    286     for (uint i = 0; i < pat->ProgramCount(); i++)
    287     {
    288         if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
    289             sd->AddListeningPID(pat->ProgramPID(i));
    290     }
    291 }
    292 
    293 void SIScan::HandleVCT(uint, const VirtualChannelTable*)
    294 {
    295     VERBOSE(VB_SIPARSER, LOC + QString("Got a Virtual Channel Table for %1")
    296             .arg((*current).FriendlyName));
    297 
    298     HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
    299 }
    300 
    301 void SIScan::HandleMGT(const MasterGuideTable*)
    302 {
    303     VERBOSE(VB_SIPARSER, LOC + QString("Got the Master Guide for %1")
    304             .arg((*current).FriendlyName));
    305 
    306     HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
    307 }
    308 
    309 void SIScan::HandleSDT(uint, const ServiceDescriptionTable* sdt)
    310 {
    311     VERBOSE(VB_SIPARSER, LOC +
    312             QString("Got a Service Description Table for %1")
    313             .arg((*current).FriendlyName));
    314     VERBOSE(VB_SIPARSER, LOC + sdt->toString());
    315 
    316     HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
    317 }
    318 
    319 void SIScan::HandleNIT(const NetworkInformationTable *nit)
    320 {
    321     VERBOSE(VB_SIPARSER, LOC +
    322             QString("Got a Network Information Table for %1")
    323             .arg((*current).FriendlyName));
    324     VERBOSE(VB_SIPARSER, LOC + nit->toString());
    325 
    326     if (nit->TransportStreamCount())
    327     {
    328         emit TransportScanUpdateText(
    329             tr("Network %1 Processing").arg(nit->NetworkName()));
    330 
    331         vector<uint> mp;
    332         mp = ChannelUtil::CreateMultiplexes(sourceID, nit);
    333         VERBOSE(VB_SIPARSER, QString("Created %1 multiplexes from NIT")
    334                 .arg(mp.size()));
    335 
    336         // Get channel numbers from UK Frequency List Descriptors
    337         for (uint i = 0; i < nit->TransportStreamCount(); i++)
    338         {
    339             const desc_list_t& list =
    340                 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
    341                                       nit->TransportDescriptorsLength(i));
    342 
    343             const unsigned char* desc =
    344                 MPEGDescriptor::Find(list, DescriptorID::dvb_uk_channel_list);
    345 
    346             if (desc)
    347             {
    348                 UKChannelListDescriptor uklist(desc);
    349                 for (uint j = 0; j < uklist.ChannelCount(); j++)
    350                     dvbChanNums[uklist.ServiceID(j)] = uklist.ChannelNumber(j);
    351             }
    352         }
    353     }
    354 
    355     const ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
    356     const DVBStreamData &dsd = *sd;
    357     if (dsd.HasAllNITSections())
    358     {
    359         emit TransportScanUpdateText(tr("Finished processing Transport List"));
    360         emit TransportScanComplete();
    361     }
    362 
    363     HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
    364 }
    365 
    366 void SIScan::HandleMPEGDBInsertion(const ScanStreamData *sd, bool)
    367 {
    368     // Try to determine if this might be "OpenCable" transport.
    369     QString sistandard = sd->GetSIStandard((*current).tuning.sistandard);
    370 
    371     if (!(*current).mplexid)
    372         (*current).mplexid = InsertMultiplex(current);
    373 
    374     if (!(*current).mplexid)
    375         return;
    376 
    377     int     mplexid = (*current).mplexid;
    378     int     freqid  = (*current).friendlyNum;
    379     QString fn      = (*current).FriendlyName;
    380 
    381     pat_vec_t pats = sd->GetCachedPATs();
    382     pmt_map_t pmt_map = sd->GetCachedPMTMap();
    383     for (uint i = 0; i < pats.size(); i++)
    384     {
    385         UpdatePATinDB(mplexid, fn, freqid, pats[i], pmt_map,
    386                       (*current).expectedChannels, sistandard, true);
    387     }
    388     sd->ReturnCachedPMTTables(pmt_map);
    389     sd->ReturnCachedPATTables(pats);
    390 
    391     // tell UI we are done with these channels
    392     if (scanMode == TRANSPORT_LIST)
    393     {
    394         UpdateScanPercentCompleted();
    395         waitingForTables = false;
    396         nextIt = current.nextTransport();
    397     }
    398 }
    399 
    400 void SIScan::HandleATSCDBInsertion(const ScanStreamData *sd,
    401                                    bool wait_until_complete)
    402 {
    403     if (wait_until_complete && !sd->HasCachedAllVCTs())
    404         return;
    405 
    406     if (!(*current).mplexid)
    407         (*current).mplexid = InsertMultiplex(current);
    408 
    409     if (!(*current).mplexid)
    410         return;
    411 
    412     int     mplexid = (*current).mplexid;
    413     int     freqid  = (*current).friendlyNum;
    414     QString fn      = (*current).FriendlyName;
    415 
    416     // Insert Terrestrial VCTs
    417     tvct_vec_t tvcts = sd->GetCachedTVCTs();
    418     for (uint i = 0; i < tvcts.size(); i++)
    419     {
    420         UpdateVCTinDB(mplexid, fn, freqid, tvcts[i],
    421                       (*current).expectedChannels, true);
    422     }
    423     sd->ReturnCachedTVCTTables(tvcts);
    424 
    425     // Insert Cable VCTs
    426     cvct_vec_t cvcts = sd->GetCachedCVCTs();
    427     for (uint i = 0; i < cvcts.size(); i++)
    428     {
    429         UpdateVCTinDB(mplexid, fn, freqid, cvcts[i],
    430                       (*current).expectedChannels, true);
    431     }
    432     sd->ReturnCachedCVCTTables(cvcts);
    433 
    434     // tell UI we are done with these channels
    435     if (scanMode == TRANSPORT_LIST)
    436     {
    437         UpdateScanPercentCompleted();
    438         waitingForTables = false;
    439         nextIt = current.nextTransport();
    440     }
    441 }
    442 
    443 void SIScan::HandleDVBDBInsertion(const ScanStreamData *sd,
    444                                   bool wait_until_complete)
    445 {
    446     const DVBStreamData &dsd = (const DVBStreamData &)(*sd);
    447     if (wait_until_complete && !(dsd.HasCachedSDT() && dsd.HasCachedAllNIT()))
    448         return;
    449 
    450     emit ServiceScanUpdateText(tr("Updating Services"));
    451 
    452     if (!(*current).mplexid)
    453         (*current).mplexid = InsertMultiplex(current);
    454 
    455     vector<const ServiceDescriptionTable*> sdts = sd->GetCachedSDTs();
    456     for (uint i = 0; i < sdts.size(); i++)
    457     {
    458         UpdateSDTinDB((*current).mplexid, sdts[i],
    459                       (*current).expectedChannels, forceUpdate);
    460     }
    461     sd->ReturnCachedSDTTables(sdts);
    462 
    463     emit ServiceScanUpdateText(tr("Finished processing Services"));
    464 
    465     if (scanMode == TRANSPORT_LIST)
    466     {
    467         UpdateScanPercentCompleted();
    468         waitingForTables = false;
    469         nextIt = current.nextTransport();
    470     }
    471     else
    472     {
    473         emit PctServiceScanComplete(100);
    474         emit ServiceScanComplete();
    475     }
    476 }
    477 
    478 /** \fn SIScan::HandlePostInsertion(void)
    479  *  \brief Insert channels based on any partial tables we do have.
    480  *  \return true if we saw any tables
    481  */
    482 bool SIScan::HandlePostInsertion(void)
    483 {
    484     DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
    485     if (!dtvSigMon)
    486         return false;
    487 
    488     const ScanStreamData *sd = dtvSigMon->GetScanStreamData();
    489 
    490     VERBOSE(VB_SIPARSER, LOC + "HandlePostInsertion() " +
    491             QString("pat(%1)").arg(sd->HasCachedAnyPAT()));
    492 
    493     const MasterGuideTable *mgt = sd->GetCachedMGT();
    494     if (mgt)
    495     {
    496         VERBOSE(VB_IMPORTANT, mgt->toString());
    497         HandleATSCDBInsertion(sd, false);
    498         sd->ReturnCachedTable(mgt);
    499         return true;
    500     }
    501 
    502     const NetworkInformationTable *nit = sd->GetCachedNIT(0, true);
    503     sdt_vec_t sdts = sd->GetCachedSDTs();
    504     if (nit || sdts.size())
    505     {
    506         if (nit)
    507             VERBOSE(VB_IMPORTANT, nit->toString());
    508         HandleDVBDBInsertion(sd, false);
    509         sd->ReturnCachedSDTTables(sdts);
    510         sd->ReturnCachedTable(nit);
    511         return true;
    512     }
    513 
    514     if (sd->HasCachedAnyPAT())
    515     {
    516         VERBOSE(VB_IMPORTANT, LOC + "Post insertion found PAT..");
    517         HandleMPEGDBInsertion(sd, false);
    518         return true;
    519     }
    520     return false;
    521 }
    522 
    523 DTVSignalMonitor* SIScan::GetDTVSignalMonitor(void)
    524 {
    525     return dynamic_cast<DTVSignalMonitor*>(signalMonitor);
    526 }
    527 
    528 DVBSignalMonitor* SIScan::GetDVBSignalMonitor(void)
    529 {
    530 #ifdef USING_DVB
    531     return dynamic_cast<DVBSignalMonitor*>(signalMonitor);
    532 #else
    533     return NULL;
    534 #endif
    535 }
    536 
    537 DTVChannel *SIScan::GetDTVChannel(void)
    538 {
    539     return dynamic_cast<DTVChannel*>(channel);
    540 }
    541 
    542 DVBChannel *SIScan::GetDVBChannel(void)
    543 {
    544 #ifdef USING_DVB
    545     return dynamic_cast<DVBChannel*>(channel);
    546 #else
    547     return NULL;
    548 #endif
    549 }
    550 
    551 V4LChannel *SIScan::GetV4LChannel(void)
    552 {
    553 #ifdef USING_V4L
    554     return dynamic_cast<V4LChannel*>(channel);
    555 #else
    556     return NULL;
    557 #endif
    558 }
    559 
    560 /** \fn SIScan::SpawnScanner(void*)
    561  *  \brief Thunk that allows scanner_thread pthread to
    562  *         call SIScan::RunScanner().
    563  */
    564 void *SIScan::SpawnScanner(void *param)
    565 {
    566     SIScan *scanner = (SIScan *)param;
    567     scanner->RunScanner();
    568     return NULL;
    569 }
    570 
    571 /** \fn SIScan::StartScanner(void)
    572  *  \brief Starts the SIScan event loop.
    573  */
    574 void SIScan::StartScanner(void)
    575 {
    576     pthread_create(&scanner_thread, NULL, SpawnScanner, this);
    577 }
    578 
    579 /** \fn SIScan::RunScanner(void)
    580  *  \brief This runs the event loop for SIScan until 'threadExit' is true.
    581  */
    582 void SIScan::RunScanner(void)
    583 {
    584     VERBOSE(VB_SIPARSER, LOC + "Starting SIScanner");
    585 
    586     scanner_thread_running = true;
    587     threadExit = false;
    588 
    589     while (!threadExit)
    590     {
    591         if (scanMode == TRANSPORT_LIST)
    592             HandleActiveScan();
    593 
    594         usleep(250);
    595     }
    596     scanner_thread_running = false;
    597 }
    598 
    599 // See if we have timed out
    600 bool SIScan::HasTimedOut(void)
    601 {
    602     if (!waitingForTables)
    603         return true;
    604 
    605     // have the tables have timed out?
    606     if (timer.elapsed() > (int)channelTimeout)
    607     {
    608         QString offset_str = current.offset() ?
    609             QObject::tr(" offset %2").arg(current.offset()) : "";
    610         QString cur_chan = QString("%1%2")
    611             .arg((*current).FriendlyName).arg(offset_str);
    612         QString time_out_table_str =
    613             QObject::tr("Timeout Scanning %1 -- no tables").arg(cur_chan);
    614 
    615         emit ServiceScanUpdateText(time_out_table_str);
    616         VERBOSE(VB_SIPARSER, LOC + time_out_table_str);
    617 
    618         return true;
    619     }
    620 
    621     // ok the tables haven't timed out, but have we hit the signal timeout?
    622     if (timer.elapsed() > (int)(*current).timeoutTune)
    623     {
    624         // If we don't have a signal in timeoutTune msec, continue..
    625         SignalMonitor *sm = GetSignalMonitor();
    626         if (NULL == sm || sm->HasSignalLock())
    627             return false;
    628 
    629         QString offset_str = current.offset() ?
    630             QObject::tr(" offset %2").arg(current.offset()) : "";
    631         QString cur_chan = QString("%1%2")
    632             .arg((*current).FriendlyName).arg(offset_str);
    633         QString time_out_sig_str =
    634             QObject::tr("Timeout Scanning %1 -- no signal").arg(cur_chan);
    635 
    636         emit ServiceScanUpdateText(time_out_sig_str);
    637         VERBOSE(VB_SIPARSER, LOC + time_out_sig_str);
    638 
    639         return true;
    640     }
    641     return false;
    642 }
    643 
    644 /** \fn SIScan::HandleActiveScan(void)
    645  *  \brief Handles the TRANSPORT_LIST SIScan mode.
    646  */
    647 void SIScan::HandleActiveScan(void)
    648 {
    649     bool do_post_insertion = waitingForTables;
    650 
    651     if (!HasTimedOut())
    652         return;
    653 
    654     if (0 == nextIt.offset() && nextIt != transport_scan_items_it_t(scanTransports.begin()))
    655     {
    656         // Stop signal monitor for previous transport
    657         signalMonitor->Stop();
    658 
    659         if (do_post_insertion)
    660             HandlePostInsertion();
    661 
    662         transportsScanned++;
    663         UpdateScanPercentCompleted();
    664     }
    665 
    666     current = nextIt; // Increment current
    667 
    668     if (current != transport_scan_items_it_t(scanTransports.end()))
    669     {
    670         ScanTransport(current);
    671 
    672         // Increment nextIt
    673         nextIt = current;
    674         ++nextIt;
    675     }
    676     else
    677     {
    678         emit ServiceScanComplete();
    679         scanMode = IDLE;
    680         scanTransports.clear();
    681         current = nextIt = transport_scan_items_it_t(scanTransports.end());
    682     }
    683 }
    684 
    685 bool SIScan::Tune(const transport_scan_items_it_t transport)
    686 {
    687     const TransportScanItem &item = *transport;
    688     const uint64_t freq = item.freq_offset(transport.offset());
    689 
    690 #ifdef USING_DVB
    691     if (GetDVBSignalMonitor() && GetDVBChannel())
    692     {
    693         if (GetDVBChannel()->GetRotor())
    694         {
    695             GetDVBSignalMonitor()->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);
    696             GetDVBSignalMonitor()->SetRotorTarget(1.0f);
    697         }
    698     }
    699 #endif // USING_DVB
    700 
    701     if (!GetDTVChannel())
    702         return false;
    703 
    704     if (item.mplexid > 0)
    705         return GetDTVChannel()->TuneMultiplex(item.mplexid, inputname);
    706 
    707     DTVMultiplex tuning = item.tuning;
    708     tuning.frequency = freq;
    709     return GetDTVChannel()->Tune(tuning, inputname);
    710 }
    711 
    712 void SIScan::ScanTransport(const transport_scan_items_it_t transport)
    713 {
    714     QString offset_str = (transport.offset()) ?
    715         QObject::tr(" offset %2").arg(transport.offset()) : "";
    716     QString cur_chan = QString("%1%2")
    717         .arg((*current).FriendlyName).arg(offset_str);
    718     QString tune_msg_str =
    719         QObject::tr("Tuning to %1 mplexid(%2)")
    720         .arg(cur_chan).arg((*current).mplexid);
    721 
    722     const TransportScanItem &item = *transport;
    723 
    724     if (transport.offset() &&
    725         (item.freq_offset(transport.offset()) == item.freq_offset(0)))
    726     {
    727         waitingForTables = false;
    728         return; // nothing to do
    729     }
    730 
    731     emit ServiceScanUpdateStatusText(cur_chan);
    732     VERBOSE(VB_SIPARSER, LOC + tune_msg_str);
    733 
    734     if (!Tune(transport))
    735     {   // If we did not tune successfully, bail with message
    736         UpdateScanPercentCompleted();
    737         VERBOSE(VB_SIPARSER, LOC +
    738                 QString("Failed to tune %1 mplexid(%2) at offset %3")
    739                 .arg(item.FriendlyName).arg(item.mplexid)
    740                 .arg(transport.offset()));
    741         return;
    742     }
    743 
    744     // If we have a DTV Signal Monitor, perform table scanner reset
    745     if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
    746     {
    747         GetDTVSignalMonitor()->GetScanStreamData()->Reset();
    748         GetDTVSignalMonitor()->SetChannel(-1,-1);
    749     }
    750 
    751     // Start signal monitor for this channel
    752     signalMonitor->Start();
    753 
    754     timer.start();
    755     waitingForTables = true;
    756 }
    757 
    758 /** \fn SIScan::StopScanner(void)
    759  *  \brief Stops the SIScan event loop and the signal monitor,
    760  *         blocking until both exit.
    761  */
    762 void SIScan::StopScanner(void)
    763 {
    764     VERBOSE(VB_SIPARSER, LOC + "Stopping SIScanner");
    765 
    766     threadExit = true;
    767 
    768     if (scanner_thread_running)
    769         pthread_join(scanner_thread, NULL);
    770 
    771     if (signalMonitor)
    772     {
    773         signalMonitor->Stop();
    774         delete signalMonitor;
    775         signalMonitor = NULL;
    776     }
    777 }
    778 
    779 /** \fn SIScan::ScanTransports(int,const QString,const QString,const QString)
    780  *  \brief Generates a list of frequencies to scan and adds it to the
    781  *   scanTransport list, and then sets the scanMode to TRANSPORT_LIST.
    782  */
    783 bool SIScan::ScanTransports(int SourceID,
    784                             const QString std,
    785                             const QString modulation,
    786                             const QString country)
    787 {
    788     QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
    789     QString name("");
    790     if (scanMode == TRANSPORT_LIST)
    791         return false;
    792 
    793     scanTransports.clear();
    794     nextIt = transport_scan_items_it_t( scanTransports.end());
    795 
    796     freq_table_list_t tables =
    797         get_matching_freq_tables(std, modulation, country);
    798 
    799     VERBOSE(VB_SIPARSER, LOC +
    800             QString("Looked up freq table (%1, %2, %3) w/%4 entries")
    801             .arg(std).arg(modulation).arg(country).arg(tables.size()));
    802 
    803     freq_table_list_t::iterator it = tables.begin();
    804     for (; it != tables.end(); ++it)
    805     {
    806         const FrequencyTable &ft = **it;
    807         int     name_num         = ft.name_offset;
    808         QString strNameFormat    = ft.name_format;
    809         uint    freq             = ft.frequencyStart;
    810         while (freq <= ft.frequencyEnd)
    811         {
    812             name = strNameFormat;
    813             if (strNameFormat.indexOf("%") >= 0)
    814                 name = strNameFormat.arg(name_num);
    815 
    816             TransportScanItem item(SourceID, si_std, name, name_num,
    817                                    freq, ft, signalTimeout);
    818             scanTransports += item;
    819 
    820             VERBOSE(VB_SIPARSER, LOC + item.toString());
    821 
    822             name_num++;
    823             freq += ft.frequencyStep;
    824         }
    825         delete *it;
    826     }
    827     tables.clear();
    828 
    829     timer.start();
    830     waitingForTables = false;
    831 
    832     nextIt            = transport_scan_items_it_t( scanTransports.begin() );
    833     transportsScanned = 0;
    834     scanMode          = TRANSPORT_LIST;
    835 
    836     return true;
    837 }
    838 
    839 bool SIScan::ScanForChannels(uint sourceid,
    840                              const QString &std,
    841                              const QString &cardtype,
    842                              const DTVChannelList &channels)
    843 {
    844     scanTransports.clear();
    845     nextIt = transport_scan_items_it_t( scanTransports.end());
    846 
    847     DTVTunerType tunertype;
    848     tunertype.Parse(cardtype);
    849 
    850     DTVChannelList::const_iterator it = channels.begin();
    851     for (uint i = 0; it != channels.end(); ++it, i++)
    852     {
    853         DTVTransport tmp = *it;
    854         tmp.sistandard = std;
    855         TransportScanItem item(sourceid, QString::number(i),
    856                                tunertype, tmp, signalTimeout);
    857 
    858         scanTransports += item;
    859 
    860         VERBOSE(VB_SIPARSER, LOC + item.toString());
    861     }
    862 
    863     if (scanTransports.empty())
    864     {
    865         VERBOSE(VB_IMPORTANT, LOC_ERR + "ScanForChannels() no transports");
    866         return false;
    867     }
    868 
    869     timer.start();
    870     waitingForTables = false;
    871 
    872     nextIt            = transport_scan_items_it_t( scanTransports.begin());
    873     transportsScanned = 0;
    874     scanMode          = TRANSPORT_LIST;
    875 
    876     return true;
    877 }
    878 
    879 /** \fn SIScan::ScanTransportsStartingOn(int,const QMap<QString,QString>&)
    880  *  \brief Generates a list of frequencies to scan and adds it to the
    881  *   scanTransport list, and then sets the scanMode to TRANSPORT_LIST.
    882  */
    883 bool SIScan::ScanTransportsStartingOn(int sourceid,
    884                                       const QMap<QString,QString> &startChan)
    885 {
    886     QMap<QString,QString>::const_iterator it;
    887 
    888     if (startChan.find("std")        == startChan.end() ||
    889         startChan.find("modulation") == startChan.end())
    890     {
    891         return false;
    892     }
    893 
    894     QString std    = *startChan.find("std");
    895     QString mod    = (*(startChan.find("modulation"))).toUpper();
    896     QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
    897     QString name   = "";
    898     bool    ok     = false;
    899 
    900     if (scanMode == TRANSPORT_LIST)
    901         return false;
    902 
    903     scanTransports.clear();
    904     nextIt = transport_scan_items_it_t( scanTransports.end() );
    905 
    906     DTVMultiplex tuning;
    907 
    908     DTVTunerType type;
    909 
    910     if (std == "dvb")
    911     {
    912         ok = type.Parse(mod);
    913     }
    914     else if (std == "atsc")
    915     {
    916         type = DTVTunerType::kTunerTypeATSC;
    917         ok = true;
    918     }
    919 
    920     if (ok)
    921     {
    922         ok = tuning.ParseTuningParams(
    923             type,
    924             startChan["frequency"],      startChan["inversion"],
    925             startChan["symbolrate"],     startChan["fec"],
    926             startChan["polarity"],
    927             startChan["coderate_hp"],    startChan["coderate_lp"],
    928             startChan["constellation"],  startChan["trans_mode"],
    929             startChan["guard_interval"], startChan["hierarchy"],
    930             startChan["modulation"],     startChan["bandwidth"]);
    931     }
    932 
    933     if (ok)
    934     {
    935         tuning.sistandard = si_std;
    936         scanTransports += TransportScanItem(
    937             sourceid, tr("Frequency %1").arg(startChan["frequency"]),
    938             tuning, signalTimeout);
    939     }
    940 
    941     if (!ok)
    942         return false;
    943 
    944     timer.start();
    945     waitingForTables = false;
    946 
    947     nextIt            = transport_scan_items_it_t(scanTransports.begin());
    948     transportsScanned = 0;
    949     scanMode          = TRANSPORT_LIST;
    950 
    951     return true;
    952 }
    953 
    954 bool SIScan::ScanTransport(int mplexid)
    955 {
    956     scanTransports.clear();
    957     nextIt = transport_scan_items_it_t(scanTransports.end());
    958 
    959     MSqlQuery query(MSqlQuery::InitCon());
    960     // Run DB query to get transports on sourceid SourceID
    961     // connected to this card
    962     QString theQuery = QString(
    963         "SELECT sourceid, mplexid, sistandard, transportid "
    964         "FROM dtv_multiplex WHERE mplexid = %2").arg(mplexid);
    965     query.prepare(theQuery);
    966 
    967     if (!query.exec() || !query.isActive())
    968     {
    969         MythDB::DBError("Get Transports for SourceID", query);
    970         return false;
    971     }
    972 
    973     if (query.size() <= 0)
    974     {
    975         VERBOSE(VB_SIPARSER, LOC + "Unable to find transport to scan.");
    976         return false;
    977     }
    978 
    979     while (query.next())
    980     {
    981         int sourceid = query.value(0).toInt();
    982         int queriedMplexid  = query.value(1).toInt();
    983         QString std  = query.value(2).toString();
    984         int tsid     = query.value(3).toInt();
    985 
    986         QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
    987             QString("Multiplex #%1").arg(queriedMplexid);
    988 
    989         VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
    990 
    991         TransportScanItem item(
    992             sourceid, std, fn, queriedMplexid, signalTimeout);
    993         scanTransports += item;
    994     }
    995 
    996     timer.start();
    997     waitingForTables  = false;
    998 
    999     transportsScanned = 0;
    1000     if (scanTransports.size())
    1001     {
    1002         nextIt        = transport_scan_items_it_t(scanTransports.begin());
    1003         scanMode      = TRANSPORT_LIST;
    1004         return true;
    1005     }
    1006 
    1007     return false;
    1008 }
    1009 
    1010 /** \fn SIScan::CheckImportedList(const DTVChannelInfoList&,uint,QString&,QString&,QString&)
    1011  *  \brief If we as scanning a dvb-utils import verify channel is in list..
    1012  */
    1013 bool SIScan::CheckImportedList(const DTVChannelInfoList &channels,
    1014                                uint mpeg_program_num,
    1015                                QString &service_name,
    1016                                QString &callsign,
    1017                                QString &common_status_info)
    1018 {
    1019     if (channels.empty())
    1020         return true;
    1021 
    1022     bool found = false;
    1023     for (uint i = 0; i < channels.size(); i++)
    1024     {
    1025         VERBOSE(VB_IMPORTANT,
    1026                 QString("comparing %1 %2 against %3 %4")
    1027                 .arg(channels[i].serviceid).arg(channels[i].name)
    1028                 .arg(mpeg_program_num).arg(common_status_info));
    1029 
    1030         if (channels[i].serviceid == mpeg_program_num)
    1031         {
    1032             found = true;
    1033             if (!channels[i].name.isEmpty())
    1034             {
    1035                 service_name = channels[i].name; service_name.detach();
    1036                 callsign     = channels[i].name; callsign.detach();
    1037             }
    1038         }
    1039     }
    1040 
    1041     if (found)
    1042     {
    1043         common_status_info += QString(" %1 %2")
    1044             .arg(tr("as")).arg(service_name);
    1045     }
    1046     else
    1047     {
    1048         emit ServiceScanUpdateText(
    1049             tr("Skipping %1, not in imported channel map")
    1050             .arg(common_status_info));
    1051     }
    1052 
    1053     return found;
    1054 }
    1055 
    1056 // ///////////////////// DB STUFF /////////////////////
    1057 // ///////////////////// DB STUFF /////////////////////
    1058 // ///////////////////// DB STUFF /////////////////////
    1059 // ///////////////////// DB STUFF /////////////////////
    1060 // ///////////////////// DB STUFF /////////////////////
    1061 
    1062 void SIScan::UpdatePMTinDB(
    1063     int db_source_id,
    1064     int db_mplexid, const QString &friendlyName, int freqid,
    1065     int pmt_indx, const ProgramMapTable *pmt,
    1066     const DTVChannelInfoList &channels, bool /*force_update*/)
    1067 {
    1068     VERBOSE(VB_IMPORTANT, LOC + pmt->toString());
    1069 
    1070     // See if service already in database based on program number
    1071     int chanid = ChannelUtil::GetChanID(
    1072         db_mplexid, -1, -1, -1, pmt->ProgramNumber());
    1073 
    1074     QString chan_num = ChannelUtil::GetChanNum(chanid);
    1075     if (chan_num.isEmpty() || renameChannels)
    1076     {
    1077         chan_num = QString("%1#%2")
    1078             .arg((freqid) ? freqid : db_mplexid).arg(pmt_indx);
    1079     }
    1080 
    1081     QString callsign = ChannelUtil::GetCallsign(chanid);
    1082     QString service_name = ChannelUtil::GetServiceName(chanid);
    1083 
    1084     if (callsign.isEmpty())
    1085     {
    1086         callsign = QString("%1%2")
    1087             .arg(ChannelUtil::GetUnknownCallsign())
    1088             .arg(chan_num);
    1089     }
    1090     else if (service_name.isEmpty())
    1091         service_name = callsign; // only do this for real callsigns
    1092 
    1093     QString common_status_info = tr("%1%2%3 on %4 (%5)")
    1094         .arg(service_name)
    1095         .arg(service_name.isEmpty() ? "" : QString(" %1 ").arg(tr("as")))
    1096         .arg(chan_num)
    1097         .arg(friendlyName).arg(freqid);
    1098 
    1099     if (!CheckImportedList(channels, pmt->ProgramNumber(),
    1100                            service_name, chan_num, common_status_info))
    1101     {
    1102         return;
    1103     }
    1104 
    1105     if (chanid < 0)
    1106     {   // The service is not in database, add it
    1107         emit ServiceScanUpdateText(
    1108             tr("Adding %1").arg(common_status_info));
    1109         chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
    1110         ChannelUtil::CreateChannel(
    1111             db_mplexid, db_source_id, chanid,
    1112             callsign,
    1113             service_name,
    1114             chan_num,
    1115             pmt->ProgramNumber(),
    1116             0, 0,
    1117             false, false, false, QString::number(freqid));
    1118     }
    1119     else
    1120     {   // The service is in database, update it
    1121         emit ServiceScanUpdateText(
    1122             tr("Updating %1").arg(common_status_info));
    1123 
    1124         bool useeit = false;
    1125         bool hidden = false;
    1126 
    1127         ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
    1128 
    1129         ChannelUtil::UpdateChannel(
    1130             db_mplexid, db_source_id, chanid,
    1131             callsign,
    1132             service_name,
    1133             chan_num,
    1134             pmt->ProgramNumber(),
    1135             0, 0,
    1136             useeit, hidden, false, QString::number(freqid));
    1137     }
    1138 }
    1139 
    1140 void SIScan::IgnoreDataOnlyMsg(const QString &name, int aux_num)
    1141 {
    1142     QString vmsg = QString("Ignoring Data Channel: %1").arg(name);
    1143     if (aux_num > 0)
    1144         vmsg += QString(" on %1").arg(aux_num);
    1145     VERBOSE(VB_SIPARSER, vmsg);
    1146 
    1147     //
    1148 
    1149     QString tmsg = tr("Skipping %1").arg(name);
    1150     if (aux_num > 0)
    1151         tmsg += " " + tr("on %1").arg(aux_num);
    1152     tmsg += " - " + tr("Data Only Channel (off-air?)");
    1153     emit ServiceScanUpdateText(tmsg);
    1154 }
    1155 
    1156 void SIScan::IgnoreEmptyChanMsg(const QString &name, int aux_num)
    1157 {
    1158     QString vmsg = QString("Ignoring Empty Channel: %1").arg(name);
    1159     if (aux_num > 0)
    1160         vmsg += QString(" on %1").arg(aux_num);
    1161     VERBOSE(VB_SIPARSER, vmsg);
    1162 
    1163     //
    1164 
    1165     QString tmsg = tr("Skipping %1").arg(name);
    1166     if (aux_num > 0)
    1167         tmsg += " " + tr("on %1").arg(aux_num);
    1168     tmsg += " - " + tr("Empty Channel (off-air?)");
    1169     emit ServiceScanUpdateText(tmsg);
    1170 }
    1171 
    1172 void SIScan::IgnoreAudioOnlyMsg(const QString &name, int aux_num)
    1173 {
    1174     QString vmsg = QString("Ignoring Audio Only Channel: %1").arg(name);
    1175     if (aux_num > 0)
    1176         vmsg += QString(" on %1").arg(aux_num);
    1177     VERBOSE(VB_SIPARSER, vmsg);
    1178 
    1179     //
    1180 
    1181     QString tmsg = tr("Skipping %1").arg(name);
    1182     if (aux_num > 0)
    1183         tmsg += " " + tr("on %1").arg(aux_num);
    1184     tmsg += " - " + tr("Audio Only Channel");
    1185     emit ServiceScanUpdateText(tmsg);
    1186 }
    1187 
    1188 void SIScan::IgnoreEncryptedMsg(const QString &name, int aux_num)
    1189 {
    1190     QString vmsg = QString("Ignoring Encrypted Channel: %1").arg(name);
    1191     if (aux_num > 0)
    1192         vmsg += QString(" on %1").arg(aux_num);
    1193     VERBOSE(VB_SIPARSER, vmsg);
    1194 
    1195     //
    1196 
    1197     QString tmsg = tr("Skipping %1").arg(name);
    1198     if (aux_num > 0)
    1199         tmsg += " " + tr("on %1").arg(aux_num);
    1200     tmsg += " - " + tr("Encrypted Channel");
    1201     emit ServiceScanUpdateText(tmsg);
    1202 }
    1203 
    1204 void SIScan::UpdatePATinDB(
    1205     int db_mplexid, const QString &friendlyName, int freqid,
    1206     const ProgramAssociationTable *pat, const pmt_map_t &pmt_map,
    1207     const DTVChannelInfoList &channels, const QString &si_standard,
    1208     bool force_update)
    1209 {
    1210     VERBOSE(VB_SIPARSER, LOC +
    1211             QString("UpdatePATinDB(): tsid: 0x%1  mplex: %2")
    1212             .arg(pat->TransportStreamID(),0,16).arg(db_mplexid));
    1213 
    1214     VERBOSE(VB_IMPORTANT, LOC + pat->toString());
    1215 
    1216     int db_source_id   = ChannelUtil::GetSourceID(db_mplexid);
    1217 
    1218     for (uint i = 0; i < pat->ProgramCount(); i++)
    1219     {
    1220         pmt_map_t::const_iterator it = pmt_map.find(pat->ProgramNumber(i));
    1221         if (it == pmt_map.end())
    1222         {
    1223             VERBOSE(VB_SIPARSER,
    1224                    QString("UpdatePATinDB(): PMT for Program #%1 is missing")
    1225                    .arg(pat->ProgramNumber(i)));
    1226             continue;
    1227         }
    1228         pmt_vec_t::const_iterator vit = (*it).begin();
    1229         for (; vit != (*it).end(); ++vit)
    1230         {
    1231             VERBOSE(VB_SIPARSER,
    1232                     QString("UpdatePATinDB(): Prog %1 PID %2: PMT @")
    1233                     .arg(pat->ProgramNumber(i))
    1234                     .arg(pat->ProgramPID(i)) << *vit);
    1235 
    1236             // ignore all services without PMT, and
    1237             // ignore services we have decided to ignore
    1238             if (!(*vit))
    1239                 continue;
    1240             else if ((*vit)->StreamCount() <= 0)
    1241             {
    1242                 IgnoreEmptyChanMsg(friendlyName, pat->ProgramNumber(i));
    1243                 continue;
    1244             }
    1245             else if (ignoreAudioOnlyServices &&
    1246                      (*vit)->IsStillPicture(si_standard))
    1247             {
    1248                 IgnoreAudioOnlyMsg(friendlyName, pat->ProgramNumber(i));
    1249                 continue;
    1250             }
    1251             else if (ignoreEncryptedServices && (*vit)->IsEncrypted())
    1252             {
    1253                 IgnoreEncryptedMsg(friendlyName, pat->ProgramNumber(i));
    1254                 continue;
    1255             }
    1256 
    1257             UpdatePMTinDB(db_source_id, db_mplexid, friendlyName, freqid,
    1258                           i, *vit, channels, force_update);
    1259         }
    1260     }
    1261 }
    1262 
    1263 void SIScan::UpdateVCTinDB(int db_mplexid,
    1264                            const QString &friendlyName, int freqid,
    1265                            const VirtualChannelTable *vct,
    1266                            const DTVChannelInfoList &channels,
    1267                            bool force_update)
    1268 {
    1269     (void) force_update;
    1270 
    1271     VERBOSE(VB_SIPARSER, LOC +
    1272             QString("UpdateVCTinDB(): tsid: 0x%1  mplex: %2")
    1273             .arg(vct->TransportStreamID(),0,16).arg(db_mplexid));
    1274 
    1275     int db_source_id   = ChannelUtil::GetSourceID(db_mplexid);
    1276 
    1277     for (uint i = 0; i < vct->ChannelCount(); i++)
    1278     {
    1279         if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
    1280             vct->ServiceType(i)    == 0x01 /* Analog TV */)
    1281         {
    1282             continue;
    1283         }
    1284 
    1285         QString basic_status_info = QString("%1 %2-%3")
    1286             .arg(vct->ShortChannelName(i))
    1287             .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i));
    1288 
    1289         if (vct->ServiceType(i) == 0x04 && ignoreDataServices)
    1290         {
    1291             IgnoreEmptyChanMsg(basic_status_info, vct->ProgramNumber(i));
    1292             continue;
    1293         }
    1294 
    1295         if (vct->ServiceType(i) == 0x03 && ignoreAudioOnlyServices)
    1296         {
    1297             IgnoreAudioOnlyMsg(basic_status_info, vct->ProgramNumber(i));
    1298             continue;
    1299         }
    1300 
    1301         if (vct->IsAccessControlled(i) && ignoreEncryptedServices)
    1302         {
    1303             IgnoreEncryptedMsg(basic_status_info, vct->ProgramNumber(i));
    1304             continue;
    1305         }
    1306 
    1307         // See if service already in database
    1308         int chanid = ChannelUtil::GetChanID(
    1309             db_mplexid, vct->ChannelTransportStreamID(i),
    1310             vct->MajorChannel(i), vct->MinorChannel(i),
    1311             vct->ProgramNumber(i));
    1312 
    1313         QString chan_num = ChannelUtil::GetChanNum(chanid);
    1314         if (chan_num.isEmpty() || renameChannels)
    1315         {
    1316             chan_num = channelFormat
    1317                 .arg(vct->MajorChannel(i))
    1318                 .arg(vct->MinorChannel(i));
    1319         }
    1320 
    1321         QString callsign = ChannelUtil::GetCallsign(chanid);
    1322         if (callsign.isEmpty() || renameChannels)
    1323             callsign = vct->ShortChannelName(i);
    1324 
    1325         // try to find an extended channel name, fallback to short name.
    1326         QString longName = vct->GetExtendedChannelName(i);
    1327         if (longName.isEmpty())
    1328             longName = vct->ShortChannelName(i);
    1329 
    1330         QString common_status_info = tr("%1 %2-%3 as %4 on %5 (%6)")
    1331             .arg(vct->ShortChannelName(i))
    1332             .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i))
    1333             .arg(chan_num).arg(friendlyName).arg(freqid);
    1334 
    1335         bool use_eit = !vct->IsHidden(i) ||
    1336             (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
    1337 
    1338 
    1339         if (!CheckImportedList(channels, vct->ProgramNumber(i),
    1340                                longName, callsign, common_status_info))
    1341         {
    1342             continue;
    1343         }
    1344 
    1345         QString msg = "";
    1346         if (chanid < 0)
    1347         {   // The service is not in database, add it
    1348             msg = tr("Adding %1").arg(common_status_info);
    1349             chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
    1350             if (chanid > 0)
    1351             {
    1352                 bool use_eit = !vct->IsHidden(i) ||
    1353                     (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
    1354 
    1355                 ChannelUtil::CreateChannel(
    1356                     db_mplexid,
    1357                     db_source_id,
    1358                     chanid,
    1359                     callsign,
    1360                     longName,
    1361                     chan_num,
    1362                     vct->ProgramNumber(i),
    1363                     vct->MajorChannel(i), vct->MinorChannel(i),
    1364                     use_eit,
    1365                     vct->IsHidden(i), vct->IsHiddenInGuide(i),
    1366                     QString::number(freqid));
    1367             }
    1368         }
    1369         else
    1370         {   // The service is in database, update it
    1371             msg = tr("Updating %1").arg(common_status_info);
    1372             ChannelUtil::UpdateChannel(
    1373                 db_mplexid,
    1374                 db_source_id,
    1375                 chanid,
    1376                 callsign,
    1377                 longName,
    1378                 chan_num,
    1379                 vct->ProgramNumber(i),
    1380                 vct->MajorChannel(i), vct->MinorChannel(i),
    1381                 use_eit,
    1382                 vct->IsHidden(i), vct->IsHiddenInGuide(i),
    1383                 QString::number(freqid));
    1384         }
    1385         emit ServiceScanUpdateText(msg);
    1386         VERBOSE(VB_SIPARSER, msg);
    1387     }
    1388 }
    1389 
    1390 /**
    1391  *  \brief Inserts channels from service description table.
    1392  */
    1393 void SIScan::UpdateSDTinDB(int /*mplexid*/, const ServiceDescriptionTable *sdt,
    1394                            const DTVChannelInfoList &channels,
    1395                            bool force_update)
    1396 {
    1397     if (!sdt->ServiceCount())
    1398         return;
    1399 
    1400     int db_mplexid = ChannelUtil::GetMplexID(
    1401         sourceID, sdt->TSID(), sdt->OriginalNetworkID());
    1402 
    1403     // HACK beg -- special exception for this network (dbver == "1067")
    1404     bool force_guide_present = (sdt->OriginalNetworkID() == 70);
    1405     // HACK end -- special exception for this network
    1406 
    1407     if (db_mplexid == -1)
    1408     {
    1409         VERBOSE(VB_IMPORTANT, "SDT: Error determing what transport this "
    1410                 "service table is associated with so failing");
    1411         emit ServiceScanUpdateText(
    1412             tr("Found channel, but it doesn't match existing tsid. You may "
    1413                "wish to delete existing channels and do a full scan."));
    1414         return;
    1415     }
    1416 
    1417     int db_source_id = ChannelUtil::GetSourceID(db_mplexid);
    1418 
    1419     /* This will be fixed post .17 to be more elegant */
    1420     bool upToDate = (ChannelUtil::GetServiceVersion(db_mplexid) ==
    1421                      (int)sdt->Version());
    1422     if (upToDate && !force_update)
    1423     {
    1424         emit ServiceScanUpdateText("Channels up to date");
    1425         return;
    1426     }
    1427     if (!upToDate)
    1428         ChannelUtil::SetServiceVersion(db_mplexid, sdt->Version());
    1429 
    1430     for (uint i = 0; i < sdt->ServiceCount(); i++)
    1431     {
    1432         // Figure out best service name...
    1433         ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
    1434         QString service_name = "";
    1435         if (desc)
    1436             service_name = desc->ServiceName();
    1437 
    1438         if (service_name.trimmed().isEmpty())
    1439             service_name = QString("%1 %2")
    1440                 .arg(sdt->ServiceID(i)).arg(db_mplexid);
    1441 
    1442         // Figure out best channel number
    1443         QString chan_num = QString::number(sdt->ServiceID(i));
    1444         bool have_uk_chan_num =
    1445             dvbChanNums.find(sdt->ServiceID(i)) != dvbChanNums.end();
    1446         if (have_uk_chan_num)
    1447             chan_num = QString::number(dvbChanNums[sdt->ServiceID(i)]);
    1448 
    1449         // Skip to next if this is a service we don't care for
    1450         if (desc && desc->IsDigitalAudio() && ignoreAudioOnlyServices)
    1451         {
    1452             IgnoreAudioOnlyMsg(service_name, sdt->ServiceID(i));
    1453             delete desc;
    1454             continue;
    1455         }
    1456         else if (desc && !desc->IsDTV() && !desc->IsDigitalAudio() &&
    1457                  ignoreDataServices)
    1458         {
    1459             IgnoreDataOnlyMsg(service_name, sdt->ServiceID(i));
    1460             delete desc;
    1461             continue;
    1462         }
    1463         else if (ignoreEncryptedServices && sdt->IsEncrypted(i))
    1464         {
    1465             IgnoreEncryptedMsg(service_name, sdt->ServiceID(i));
    1466             if (desc)
    1467                 delete desc;
    1468             continue;
    1469         }
    1470 
    1471         // Default authority
    1472         QString default_authority = "";
    1473         desc_list_t parsed =
    1474             MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),
    1475                                   sdt->ServiceDescriptorsLength(i));
    1476         const unsigned char *def_auth =
    1477             MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
    1478         if (def_auth)
    1479             default_authority =
    1480                 QString::fromAscii((const char*)def_auth+2, def_auth[1]);
    1481 
    1482         QString common_status_info = service_name;
    1483 
    1484         if (!CheckImportedList(channels, sdt->ServiceID(i),
    1485                                service_name, service_name, common_status_info))
    1486         {
    1487             if (desc)
    1488                 delete desc;
    1489             continue;
    1490         }
    1491 
    1492         // See if service already in database based on service ID
    1493         int chanid = ChannelUtil::GetChanID(db_mplexid, -1, -1, -1,
    1494                                             sdt->ServiceID(i));
    1495 
    1496         if (chanid < 0)
    1497         {   // The service is not in database, add it
    1498             emit ServiceScanUpdateText(tr("Adding %1").arg(service_name));
    1499             chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
    1500             if (chanid > 0)
    1501             {
    1502                 ChannelUtil::CreateChannel(
    1503                     db_mplexid, db_source_id, chanid,
    1504                     service_name,
    1505                     service_name,
    1506                     chan_num,
    1507                     sdt->ServiceID(i),
    1508                     0, 0,
    1509                     sdt->HasEITSchedule(i) ||
    1510                     sdt->HasEITPresentFollowing(i) ||
    1511                     force_guide_present,
    1512                     false, false, QString::null,
    1513                     QString::null, "Default", QString::null,
    1514                     default_authority);
    1515             }
    1516         }
    1517         else if (force_update || (desc && have_uk_chan_num))
    1518         {   // The service is in database & we have good info, update it
    1519             emit ServiceScanUpdateText(tr("Updating %1").arg(service_name));
    1520 
    1521             bool useeit = false;
    1522             bool hidden = false;
    1523 
    1524             ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
    1525 
    1526             if (!renameChannels)
    1527                 chan_num = ChannelUtil::GetChanNum(chanid);
    1528             else
    1529                 useeit = (sdt->HasEITSchedule(i) ||
    1530                             sdt->HasEITPresentFollowing(i) ||
    1531                             force_guide_present);
    1532 
    1533             ChannelUtil::UpdateChannel(
    1534                 db_mplexid,
    1535                 db_source_id,
    1536                 chanid,
    1537                 service_name,
    1538                 service_name,
    1539                 chan_num,
    1540                 sdt->ServiceID(i),
    1541                 0, 0,
    1542                 useeit,
    1543                 hidden, false, QString::null,
    1544                 QString::null, QString::null, QString::null,
    1545                 default_authority);
    1546         }
    1547         else
    1548         {
    1549             emit ServiceScanUpdateText(
    1550                 tr("Skipping %1 - already in DB, and "
    1551                    "we don't have better data.")
    1552                 .arg(service_name));
    1553         }
    1554 
    1555         if (desc)
    1556             delete desc;
    1557     }
    1558 }
    1559 
    1560 // FindBestMplexFreq()
    1561 //  - Examines the freq in the DB against the curent tuning frequency and
    1562 //    it's offset frequencies. If the frequency in the DB is any of the
    1563 //    tuning frequencies or offsets then use the DB frequency.
    1564 uint64_t SIScan::FindBestMplexFreq(
    1565     const uint64_t tuning_freq,
    1566     const transport_scan_items_it_t transport, const uint sourceid,
    1567     const uint transportid, const uint networkid)
    1568 {
    1569     uint64_t    db_freq;
    1570     QString     tmp_modulation;
    1571     QString     tmp_si_std;
    1572     uint        tmp_transportid, tmp_networkid;
    1573     int         mplexid;
    1574 
    1575     if (!transportid || !networkid)
    1576         return tuning_freq;
    1577 
    1578     mplexid = ChannelUtil::GetMplexID(sourceid, transportid, networkid);
    1579     if (mplexid <= 0)
    1580         return tuning_freq;
    1581 
    1582     if (!ChannelUtil::GetTuningParams(
    1583             (uint)mplexid, tmp_modulation,
    1584             db_freq, tmp_transportid, tmp_networkid, tmp_si_std))
    1585     {
    1586         return tuning_freq;
    1587     }
    1588 
    1589     for (uint i = 0; i < (*transport).offset_cnt(); i++)
    1590     {
    1591         if (db_freq == (*transport).freq_offset(i))
    1592             return db_freq;
    1593     }
    1594 
    1595     return tuning_freq;
    1596 }
    1597 
    1598 uint SIScan::InsertMultiplex(const transport_scan_items_it_t transport)
    1599 {
    1600     DTVMultiplex tuning = (*transport).tuning;
    1601     uint tsid  = 0;
    1602     uint netid = 0;
    1603 
    1604     tuning.frequency = (*transport).freq_offset(transport.offset());
    1605 
    1606 #ifdef USING_DVB
    1607     if (GetDVBSignalMonitor())
    1608     {
    1609         DVBSignalMonitor *sm = GetDVBSignalMonitor();
    1610 
    1611         tsid  = sm->GetDetectedTransportID();
    1612         netid = sm->GetDetectedNetworkID();
    1613 
    1614         // Try to read the actual values back from the card
    1615         if (GetDVBChannel()->IsTuningParamsProbeSupported())
    1616             GetDVBChannel()->ProbeTuningParams(tuning);
    1617 
    1618         tuning.frequency = FindBestMplexFreq(
    1619             tuning.frequency, transport, (*transport).SourceID, tsid, netid);
    1620     }
    1621 #endif // USING_DVB
    1622 
    1623 #ifdef USING_V4L
    1624     if (GetV4LChannel())
    1625     {
    1626         // convert to visual carrier
    1627         tuning.frequency = tuning.frequency - 1750000;
    1628     }
    1629 #endif // USING_V4L
    1630 
    1631     return ChannelUtil::CreateMultiplex(
    1632         (*transport).SourceID, tuning, tsid, netid);
    1633 }
  • libs/libmythtv/scanwizard.h

     
    3838#include "settings.h"
    3939
    4040class ScanWizardConfig;
    41 class ScanWizardScanner;
     41class ChannelScannerGUI;
    4242
    4343class MPUBLIC ScanWizard : public QObject, public ConfigurationWizard
    4444{
     
    6262    uint               lastHWCardID;
    6363    uint               lastHWCardType;
    6464    ScanWizardConfig  *configPane;
    65     ScanWizardScanner *scannerPane;
     65    ChannelScannerGUI *scannerPane;
    6666};
    6767
    6868#endif // SCANWIZARD_H
  • libs/libmythtv/frequencytables.h

     
    7676          constellation(_constellation),   trans_mode(_trans_mode),
    7777          guard_interval(_guard_interval), hierarchy(_hierarchy) { ; }
    7878
     79    FrequencyTable(uint64_t                _frequencyStart,
     80                   uint64_t                _frequencyEnd,
     81                   uint                    _frequencyStep,
     82                   QString                 _name_format,
     83                   int                     _name_offset,
     84                   DTVCodeRate             _fec_inner,
     85                   DTVModulation           _modulation,
     86                   uint                    _symbol_rate,
     87                   int                     _offset1,
     88                   int                     _offset2)
     89        : name_format(_name_format),       name_offset(_name_offset),
     90          frequencyStart(_frequencyStart), frequencyEnd(_frequencyEnd),
     91          frequencyStep(_frequencyStep),   modulation(_modulation),
     92          offset1(_offset1),               offset2(_offset2),
     93          symbol_rate(_symbol_rate),       fec_inner(_fec_inner) { ; }
     94
    7995    virtual ~FrequencyTable() { ; }
    8096
    8197    // Common Stuff
     
    93109    DTVBandwidth      bandwidth;
    94110    DTVCodeRate       coderate_hp;
    95111    DTVCodeRate       coderate_lp;
    96     DTVModulation     constellation; 
     112    DTVModulation     constellation;
    97113    DTVTransmitMode   trans_mode;
    98114    DTVGuardInterval  guard_interval;
    99115    DTVHierarchy      hierarchy;
     116
     117    // DVB-C/DVB-S stuff
     118    uint              symbol_rate;
     119    DTVCodeRate       fec_inner;
    100120};
    101121
    102122/**
  • libs/libmythtv/siscan.h

     
    1 // -*- Mode: c++ -*-
    2 
    3 #ifndef SISCAN_H
    4 #define SISCAN_H
    5 
    6 #include <pthread.h>
    7 
    8 // Qt includes
    9 #include <qobject.h>
    10 #include <qstring.h>
    11 #include <qmap.h>
    12 #include <qmutex.h>
    13 #include <qdatetime.h>
    14 
    15 // MythTV includes
    16 #include "frequencytables.h"
    17 #include "streamlisteners.h"
    18 #include "dtvconfparser.h"
    19 #include "signalmonitorlistener.h"
    20 
    21 class MSqlQuery;
    22 
    23 class ChannelBase;
    24 class DTVChannel;
    25 class V4LChannel;
    26 class DVBChannel;
    27 class HDHRChannel;
    28 
    29 class SignalMonitor;
    30 class DTVSignalMonitor;
    31 class DVBSignalMonitor;
    32 
    33 typedef enum
    34 {
    35     IDLE,           ///< Don't do anything
    36     TRANSPORT_LIST, ///< Actively scan for channels
    37 } SCANMODE;
    38 
    39 typedef vector<const ProgramMapTable*>  pmt_vec_t;
    40 typedef QMap<uint, pmt_vec_t>           pmt_map_t;
    41 
    42 class SIScan : public QObject,
    43                public MPEGStreamListener,
    44                public ATSCMainStreamListener,
    45                public DVBMainStreamListener,
    46                public SignalMonitorListener
    47 {
    48     Q_OBJECT
    49   public:
    50     SIScan(const QString &_cardtype, ChannelBase* _channel, int _sourceID,
    51            uint signal_timeout, uint channel_timeout,
    52            const QString &_inputname);
    53     ~SIScan();
    54 
    55     void StartScanner(void);
    56     void StopScanner(void);
    57 
    58     bool ScanTransports(
    59         int src, const QString std, const QString mod, const QString country);
    60     bool ScanTransportsStartingOn(
    61         int sourceid, const QMap<QString,QString> &valueMap);
    62     bool ScanTransport(int mplexid);
    63     bool ScanForChannels(
    64         uint sourceid, const QString &std, const QString &cardtype,
    65         const DTVChannelList&);
    66 
    67     bool ScanServicesSourceID(int SourceID);
    68 
    69     void SetAnalog(bool is_analog)    { isAnalog                = is_analog; }
    70     void SetSourceID(int _SourceID)   { sourceID                = _SourceID; }
    71     void SetFTAOnly(bool _fFTAOnly)   { ignoreEncryptedServices = _fFTAOnly; }
    72     void SetTVOnly(bool _tvOnly)
    73         { ignoreAudioOnlyServices = ignoreDataServices = _tvOnly; }
    74     void SetForceUpdate(bool _force)  { forceUpdate             = _force;    }
    75     void SetRenameChannels(bool _r)   { renameChannels          = _r; }
    76     void SetChannelFormat(const QString _fmt) { channelFormat   = _fmt; }
    77     void SetSignalTimeout(uint val)    { signalTimeout = val; }
    78     void SetChannelTimeout(uint val)   { channelTimeout = val; }
    79 
    80     uint GetSignalTimeout(void)  const { return signalTimeout; }
    81     uint GetChannelTimeout(void) const { return channelTimeout; }
    82 
    83     SignalMonitor    *GetSignalMonitor(void) { return signalMonitor; }
    84     DTVSignalMonitor *GetDTVSignalMonitor(void);
    85     DVBSignalMonitor *GetDVBSignalMonitor(void);
    86 
    87     // MPEG
    88     void HandlePAT(const ProgramAssociationTable*);
    89     void HandleCAT(const ConditionalAccessTable*) { }
    90     void HandlePMT(uint, const ProgramMapTable*) { }
    91     void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { }
    92 
    93     // ATSC Main
    94     void HandleSTT(const SystemTimeTable*) {}
    95     void HandleMGT(const MasterGuideTable*);
    96     void HandleVCT(uint tsid, const VirtualChannelTable*);
    97 
    98     // DVB Main
    99     void HandleNIT(const NetworkInformationTable*);
    100     void HandleSDT(uint tsid, const ServiceDescriptionTable*);
    101     void HandleTDT(const TimeDateTable*) {}
    102 
    103     // SignalMonitorListener
    104     virtual void AllGood(void);
    105     virtual void StatusSignalLock(const SignalMonitorValue&) { }
    106     virtual void StatusSignalStrength(const SignalMonitorValue&) { }
    107 
    108   public slots:
    109     void deleteLater(void);
    110 
    111   signals:
    112     // Values from 1-100 of scan completion
    113     void PctServiceScanComplete(int pct);
    114     void PctTransportScanComplete(int pct);
    115     void ServiceScanUpdateStatusText(const QString& status);
    116     void ServiceScanUpdateText(const QString& status);
    117     void TransportScanUpdateText(const QString& status);
    118     void ServiceScanComplete(void);
    119     void TransportScanComplete(void);
    120 
    121   private:
    122     // some useful gets
    123     DTVChannel       *GetDTVChannel(void);
    124     V4LChannel       *GetV4LChannel(void);
    125     DVBChannel       *GetDVBChannel(void);
    126 
    127     /// \brief Called by SpawnScanner to run scanning thread
    128     void RunScanner(void);
    129     /// \brief Thunk to call RunScanner from pthread
    130     static void *SpawnScanner(void *param);
    131 
    132     bool HasTimedOut(void);
    133     void HandleActiveScan(void);
    134     bool Tune(const transport_scan_items_it_t transport);
    135     uint InsertMultiplex(const transport_scan_items_it_t transport);
    136     void ScanTransport(const transport_scan_items_it_t transport);
    137 
    138     /// \brief Updates Transport Scan progress bar
    139     inline void UpdateScanPercentCompleted(void);
    140 
    141     bool CheckImportedList(const DTVChannelInfoList&,
    142                            uint mpeg_program_num,
    143                            QString &service_name,
    144                            QString &callsign,
    145                            QString &common_status_info);
    146 
    147     void IgnoreDataOnlyMsg( const QString &name, int aux_num);
    148     void IgnoreEmptyChanMsg(const QString &name, int aux_num);
    149     void IgnoreAudioOnlyMsg(const QString &name, int aux_num);
    150     void IgnoreEncryptedMsg(const QString &name, int aux_num);
    151 
    152     void HandleMPEGDBInsertion(const ScanStreamData *sd, bool wait);
    153     void UpdatePATinDB(int mplexid, const QString &friendlyName, int freqid,
    154                        const ProgramAssociationTable*, const pmt_map_t&,
    155                        const DTVChannelInfoList&, const QString &si_standard,
    156                        bool force_update);
    157 
    158     void UpdatePMTinDB(int sourceid,
    159                        int mplexid, const QString &friendlyName, int freqid,
    160                        int pmt_indx, const ProgramMapTable*,
    161                        const DTVChannelInfoList&,
    162                        bool force_update);
    163 
    164     void HandleATSCDBInsertion(const ScanStreamData *sd, bool wait);
    165     void UpdateVCTinDB(int mplexid, const QString &friendlyName, int freqid,
    166                        const VirtualChannelTable*,
    167                        const DTVChannelInfoList&,
    168                        bool force_update);
    169 
    170     void HandleDVBDBInsertion(const ScanStreamData *sd, bool wait);
    171     void UpdateSDTinDB(int mplexid,
    172                        const ServiceDescriptionTable*,
    173                        const DTVChannelInfoList&,
    174                        bool force_update);
    175 
    176     bool HandlePostInsertion(void);
    177 
    178     uint64_t FindBestMplexFreq(const uint64_t tuning_freq,
    179                                const transport_scan_items_it_t transport,
    180                                const uint sourceid, const uint transportid,
    181                                const uint networkid);
    182 
    183 
    184     static QString loc(const SIScan*);
    185 
    186   private:
    187     // Set in constructor
    188     ChannelBase      *channel;
    189     SignalMonitor    *signalMonitor;
    190     int               sourceID;
    191     SCANMODE          scanMode;
    192     uint              signalTimeout;
    193     uint              channelTimeout;
    194     QString           inputname;
    195 
    196     // Settable
    197     bool              isAnalog;
    198     bool              ignoreAudioOnlyServices;
    199     bool              ignoreDataServices;
    200     bool              ignoreEncryptedServices;
    201     bool              forceUpdate;
    202     bool              renameChannels;
    203     QString           channelFormat;
    204 
    205     // State
    206     bool              threadExit;
    207     bool              waitingForTables;
    208     QTime             timer;
    209 
    210     // Transports List
    211     int                         transportsScanned;
    212     transport_scan_items_t      scanTransports;
    213     transport_scan_items_it_t   current;
    214     transport_scan_items_it_t   nextIt;
    215     QMap<uint, uint>            dvbChanNums;
    216 
    217     /// Scanner thread, runs SIScan::StartScanner()
    218     pthread_t        scanner_thread;
    219     bool             scanner_thread_running;
    220 };
    221 
    222 inline void SIScan::UpdateScanPercentCompleted(void)
    223 {
    224     int tmp = (transportsScanned * 100) / scanTransports.size();
    225     emit PctServiceScanComplete(tmp);
    226 }
    227 
    228 #endif // SISCAN_H
  • libs/libmythtv/frequencytables.cpp

     
    9292
    9393    // setup tuning params
    9494    tuning.frequency  = freq;
    95     tuning.sistandard = std;
     95    tuning.sistandard = (std.toLower() != "atsc") ? "dvb" : "atsc";
     96    tuning.modulation = ft.modulation;
    9697    freq_offsets[1]   = ft.offset1;
    9798    freq_offsets[2]   = ft.offset2;
    9899
    99     if (std == "dvb")
     100    if (std == "dvbt")
    100101    {
    101102        tuning.inversion      = ft.inversion;
    102103        tuning.bandwidth      = ft.bandwidth;
    103104        tuning.hp_code_rate   = ft.coderate_hp;
    104105        tuning.lp_code_rate   = ft.coderate_lp;
    105         tuning.modulation     = ft.modulation;
    106106        tuning.trans_mode     = ft.trans_mode;
    107107        tuning.guard_interval = ft.guard_interval;
    108108        tuning.hierarchy      = ft.hierarchy;
    109109    }
    110     else
     110    else if (std == "dvbc" || std == "dvbs")
    111111    {
    112         tuning.modulation     = ft.modulation;
     112        tuning.symbolrate     = ft.symbol_rate;
     113        tuning.fec            = ft.fec_inner;
    113114    }
    114115
    115116    mplexid = GetMultiplexIdFromDB();
     
    283284{
    284285    // United Kingdom
    285286    fmap["dvbt_ofdm_uk0"] = new FrequencyTable(
    286         474000000, 850000000, 8000000, "" , 0, DTVInversion::kInversionOff,
     287        474000000, 850000000, 8000000, "Channel %1", 21,
     288        DTVInversion::kInversionOff,
    287289        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    288290        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
    289291        DTVTransmitMode::kTransmissionMode2K,
     
    292294
    293295    // Finland
    294296    fmap["dvbt_ofdm_fi0"] = new FrequencyTable(
    295         474000000, 850000000, 8000000, "", 0, DTVInversion::kInversionOff,
     297        474000000, 850000000, 8000000, "Channel %1", 21,
     298        DTVInversion::kInversionOff,
    296299        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    297300        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64,
    298301        DTVTransmitMode::kTransmissionModeAuto,
     
    301304
    302305    // Sweden
    303306    fmap["dvbt_ofdm_se0"] = new FrequencyTable(
    304         474000000, 850000000, 8000000, "", 0, DTVInversion::kInversionOff,
     307        474000000, 850000000, 8000000, "Channel %1", 21,
     308        DTVInversion::kInversionOff,
    305309        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    306310        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64,
    307311        DTVTransmitMode::kTransmissionModeAuto,
     
    310314
    311315    // Australia
    312316    fmap["dvbt_ofdm_au0"] = new FrequencyTable(
    313         177500000, 226500000, 7000000, "", 0, DTVInversion::kInversionOff,
     317        177500000, 226500000, 7000000, "Channel %1", 6,
     318        DTVInversion::kInversionOff,
    314319        DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto,
    315320        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64,
    316         DTVTransmitMode::kTransmissionMode8K, DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone,
     321        DTVTransmitMode::kTransmissionMode8K,
     322        DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone,
    317323        DTVModulation::kModulationQAMAuto, 125000, 0); // VHF 6-12
    318324    fmap["dvbt_ofdm_au1"] = new FrequencyTable(
    319         529500000, 816500000, 7000000, "", 0, DTVInversion::kInversionOff,
     325        529500000, 816500000, 7000000, "Channel %1", 28,
     326        DTVInversion::kInversionOff,
    320327        DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto,
    321328        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64,
    322329        DTVTransmitMode::kTransmissionMode8K,
     
    325332
    326333    // Germany (Deuschland)
    327334    fmap["dvbt_ofdm_de0"] = new FrequencyTable(
    328         177500000, 226500000, 7000000, "", 0, DTVInversion::kInversionOff,
     335        177500000, 226500000, 7000000, "Channel %1", 6,
     336        DTVInversion::kInversionOff,
    329337        DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto,
    330338        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
    331339        DTVTransmitMode::kTransmissionMode8K,
    332340        DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone,
    333         DTVModulation::kModulationQAMAuto, 125000, 0); // VHF 6-12
     341        DTVModulation::kModulationQAMAuto, 0, 0); // VHF 6-12
    334342    fmap["dvbt_ofdm_de1"] = new FrequencyTable(
    335         474000000, 826000000, 8000000, "", 0, DTVInversion::kInversionOff,
     343        474000000, 826000000, 8000000, "Channel %1", 21,
     344        DTVInversion::kInversionOff,
    336345        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    337346        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
    338347        DTVTransmitMode::kTransmissionModeAuto,
    339348        DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone,
    340         DTVModulation::kModulationQAMAuto, 125000, 0); // UHF 21-65
     349        DTVModulation::kModulationQAMAuto, 0, 0); // UHF 21-65
    341350
    342351    // Spain
    343352    fmap["dvbt_ofdm_es0"] = new FrequencyTable(
    344         474000000, 858000000, 8000000, "", 0, DTVInversion::kInversionOff,
     353        474000000, 858000000, 8000000, "Channel %1", 21,
     354        DTVInversion::kInversionOff,
    345355        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    346356        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
    347357        DTVTransmitMode::kTransmissionModeAuto,
     
    350360
    351361    // New Zealand
    352362    fmap["dvbt_ofdm_nz0"] = new FrequencyTable(
    353         474000000, 858000000, 8000000, "", 0, DTVInversion::kInversionOff,
     363        474000000, 858000000, 8000000, "Channel %1", 21,
     364        DTVInversion::kInversionOff,
    354365        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFEC_3_4,
    355366        DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAM64,
    356367        DTVTransmitMode::kTransmissionMode8K,
     
    359370
    360371    // france
    361372    fmap["dvbt_ofdm_fr0"] = new FrequencyTable(
    362         474000000, 850000000, 8000000, "" , 0, DTVInversion::kInversionOff,
     373        474000000, 850000000, 8000000, "Channel %1", 21,
     374        DTVInversion::kInversionOff,
    363375        DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto,
    364376        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
    365377        DTVTransmitMode::kTransmissionMode8K,
    366378        DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone,
    367379        DTVModulation::kModulationQAMAuto, 167000, -166000);
    368    
     380
     381    // DVB-C Germany
     382    fmap["dvbc_qam_de0"] = new FrequencyTable(
     383         73000000,  73000000, 8000000, "Channel D%1", 73,
     384        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     385        6900000, 0, 0);
     386    fmap["dvbc_qam_de1"] = new FrequencyTable(
     387         81000000,  81000000, 8000000, "Channel D%1", 81,
     388        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     389        6900000, 0, 0);
     390    fmap["dvbc_qam_de2"] = new FrequencyTable(
     391        113000000, 121000000, 8000000, "Channel S0%1", 2,
     392        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     393        6900000, 0, 0);
     394    fmap["dvbc_qam_de3"] = new FrequencyTable(
     395        306000000, 466000000, 8000000, "Channel S%1", 21,
     396        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     397        6900000, 0, 0);
     398    fmap["dvbc_qam_de4"] = new FrequencyTable(
     399        474000000, 858000000, 8000000, "Channel %1", 21,
     400        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     401        6900000, 0, 0);
     402
     403    fmap["dvbc_qam_uk0"] = new FrequencyTable(
     404        12324000, 12324000+1, 10, "Channel %1", 1,
     405        DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAMAuto,
     406        29500000, 0, 0);
     407    fmap["dvbc_qam_uk1"] = new FrequencyTable(
     408        459000000, 459000000+1, 10, "Channel %1", 2,
     409        DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAM64,
     410        6952000, 0, 0);
     411
     412    fmap["dvbc_qam_bf0"] = new FrequencyTable(
     413        203000000, 795000000, 100000, "BF Channel %1", 1,
     414        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     415        6900000, 0, 0);
     416    fmap["dvbc_qam_bf1"] = new FrequencyTable(
     417        194750000, 794750000, 100000, "BF Channel %1", 1 + (795000-203000) / 100,
     418        DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto,
     419        6900000, 0, 0);
     420
    369421//#define DEBUG_DVB_OFFSETS
    370422#ifdef DEBUG_DVB_OFFSETS
    371423    // UHF 14-69
  • libs/libmythtv/scanwizard.cpp

     
    2929 *
    3030 */
    3131
    32 #include "scanwizardhelpers.h"
    33 #include "scanwizardscanner.h"
     32#include "scanwizardconfig.h"
     33#include "channelscanner_gui.h"
    3434#include "scanwizard.h"
    3535#include "sourceutil.h"
    3636#include "cardutil.h"
    3737#include "videosource.h"
     38#include "scaninfo.h"
     39#include "channelimporter.h"
    3840#include "mythverbose.h"
    3941
    4042#define LOC QString("SWiz: ")
     
    4749    lastHWCardType(CardUtil::ERROR_PROBE),
    4850    configPane(new ScanWizardConfig(
    4951                   this, default_sourceid, default_cardid, default_inputname)),
    50     scannerPane(new ScanWizardScanner())
     52    scannerPane(new ChannelScannerGUI())
    5153{
    5254    addChild(configPane);
    5355    addChild(scannerPane);
     
    6668
    6769void ScanWizard::SetPage(const QString &pageTitle)
    6870{
    69     VERBOSE(VB_SIPARSER, QString("SetPage(%1)").arg(pageTitle));
    70     if (pageTitle != ScanWizardScanner::kTitle)
     71    VERBOSE(VB_CHANSCAN, QString("SetPage(%1)").arg(pageTitle));
     72    if (pageTitle != ChannelScannerGUI::kTitle)
    7173        return;
    7274
    7375    QMap<QString,QString> start_chan;
     
    7981    int     scantype  = configPane->GetScanType();
    8082    bool    do_scan   = true;
    8183
    82     VERBOSE(VB_SIPARSER, LOC + "SetPage(): " +
     84    VERBOSE(VB_CHANSCAN, LOC + "SetPage(): " +
    8385            QString("type(%1) cardid(%2) inputname(%3)")
    8486            .arg(scantype).arg(cardid).arg(inputname));
    8587
     
    8890        scannerPane->ImportDVBUtils(sourceid, lastHWCardType,
    8991                                    configPane->GetFilename());
    9092    }
    91     else if (scantype == ScanTypeSetting::NITAddScan_OFDM)
     93    else if (scantype == ScanTypeSetting::NITAddScan_DVBT)
    9294    {
    9395        start_chan = configPane->GetStartChan();
    9496        parse_type = DTVTunerType::kTunerTypeOFDM;
    9597    }
    96     else if (scantype == ScanTypeSetting::NITAddScan_QPSK)
     98    else if (scantype == ScanTypeSetting::NITAddScan_DVBS)
    9799    {
    98100        start_chan = configPane->GetStartChan();
    99101        parse_type = DTVTunerType::kTunerTypeQPSK;
    100102    }
    101     else if (scantype == ScanTypeSetting::NITAddScan_QAM)
     103    else if (scantype == ScanTypeSetting::NITAddScan_DVBC)
    102104    {
    103105        start_chan = configPane->GetStartChan();
    104106        parse_type = DTVTunerType::kTunerTypeQAM;
     
    111113    else if ((scantype == ScanTypeSetting::FullScan_ATSC)     ||
    112114             (scantype == ScanTypeSetting::FullTransportScan) ||
    113115             (scantype == ScanTypeSetting::TransportScan)     ||
    114              (scantype == ScanTypeSetting::FullScan_OFDM)     ||
     116             (scantype == ScanTypeSetting::FullScan_DVBT)     ||
    115117             (scantype == ScanTypeSetting::FullScan_Analog))
    116118    {
    117119        ;
    118120    }
     121    else if (scantype == ScanTypeSetting::ExistingScanImport)
     122    {
     123        do_scan = false;
     124        uint scanid = configPane->GetScanID();
     125        ScanDTVTransportList transports = LoadScan(scanid);
     126        ChannelImporter ci(true, true, true, false);
     127        ci.Process(transports);
     128    }
    119129    else
    120130    {
    121131        do_scan = false;
    122         VERBOSE(VB_SIPARSER, LOC_ERR + "SetPage(): " +
     132        VERBOSE(VB_CHANSCAN, LOC_ERR + "SetPage(): " +
    123133                QString("type(%1) src(%2) cardid(%3) not handled")
    124134                .arg(scantype).arg(sourceid).arg(cardid));
    125135
     
    150160
    151161    if (do_scan)
    152162    {
     163        QString table_start, table_end;
     164        configPane->GetFrequencyTableRange(table_start, table_end);
     165
    153166        scannerPane->Scan(
    154167            configPane->GetScanType(),       configPane->GetCardID(),
    155168            configPane->GetInputName(),      configPane->GetSourceID(),
    156             configPane->DoDeleteChannels(),  configPane->DoRenameChannels(),
     169            /*configPane->DoDeleteChannels(),configPane->DoRenameChannels(),*/
    157170            configPane->DoIgnoreSignalTimeout(), configPane->GetMultiplex(),
    158171            start_chan,
    159172            configPane->GetFrequencyStandard(), configPane->GetModulation(),
    160             configPane->GetFrequencyTable(), configPane->GetATSCFormat());
     173            configPane->GetFrequencyTable()/*,configPane->GetATSCFormat()*/,
     174            table_start, table_end);
    161175    }
    162176}
    163177
     
    177191        lastHWCardID    = cardid;
    178192        QString subtype = CardUtil::ProbeSubTypeName(cardid);
    179193        lastHWCardType  = CardUtil::toCardType(subtype);
    180         configPane->SetDefaultATSCFormat(
    181             SourceUtil::GetChannelFormat(configPane->GetSourceID()));
    182194    }
    183195}
  • libs/libmythtv/scanwizardscanner.h

     
    1 /* -*- Mode: c++ -*-
    2  * vim: set expandtab tabstop=4 shiftwidth=4:
    3  *
    4  * Original Project
    5  *      MythTV      http://www.mythtv.org
    6  *
    7  * Author(s):
    8  *      John Pullan  (john@pullan.org)
    9  *
    10  * Description:
    11  *     Collection of classes to provide dvb channel scanning
    12  *     functionallity
    13  *
    14  *
    15  * This program is free software; you can redistribute it and/or
    16  * modify it under the terms of the GNU General Public License
    17  * as published by the Free Software Foundation; either version 2
    18  * of the License, or (at your option) any later version.
    19  *
    20  * This program is distributed in the hope that it will be useful,
    21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    23  * GNU General Public License for more details.
    24  *
    25  * You should have received a copy of the GNU General Public License
    26  * along with this program; if not, write to the Free Software
    27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    28  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    29  *
    30  */
    31 
    32 #ifndef _SCANWIZARDSCANNER_H_
    33 #define _SCANWIZARDSCANNER_H_
    34 
    35 // Standard UNIX C headers
    36 #include <pthread.h>
    37 
    38 // Qt headers
    39 #include <qstring.h>
    40 #include <QEvent>
    41 
    42 // MythTV headers
    43 #include "settings.h"
    44 #include "dtvconfparser.h"
    45 #include "signalmonitorlistener.h"
    46 
    47 class ScanWizard;
    48 class AnalogScan;
    49 class IPTVChannelFetcher;
    50 class LogList;
    51 class SIScan;
    52 class ScanProgressPopup;
    53 
    54 class ChannelBase;
    55 class V4LChannel;
    56 class DVBChannel;
    57 class SignalMonitorValue;
    58 
    59 class ScanWizardScanner :
    60     public VerticalConfigurationGroup,
    61     public DVBSignalMonitorListener
    62 {
    63     Q_OBJECT
    64 
    65     friend void *spawn_popup(void*);
    66 
    67   public:
    68     ScanWizardScanner(void);
    69     virtual void deleteLater(void)
    70         { Teardown(); VerticalConfigurationGroup::deleteLater(); }
    71 
    72     void Scan(int            scantype,
    73               uint           cardid,
    74               const QString &inputname,
    75               uint           sourceid,
    76               bool           do_delete_channels,
    77               bool           do_rename_channels,
    78               bool           do_ignore_signal_timeout,
    79               // stuff needed for particular scans
    80               uint           mplexid,
    81               const QMap<QString,QString> &startChan,
    82               const QString &freq_std,
    83               const QString &mod,
    84               const QString &tbl,
    85               const QString &atsc_format);
    86 
    87     void ImportDVBUtils(uint sourceid, int cardtype, const QString &file);
    88     void ImportM3U(     uint cardid, const QString &inputname, uint sourceid);
    89 
    90     // SignalMonitorListener
    91     virtual void AllGood(void) { }
    92     virtual void StatusSignalLock(const SignalMonitorValue&);
    93     virtual void StatusSignalStrength(const SignalMonitorValue&);
    94 
    95     // DVBSignalMonitorListener
    96     virtual void StatusSignalToNoise(const SignalMonitorValue&);
    97     virtual void StatusBitErrorRate(const SignalMonitorValue&) { }
    98     virtual void StatusUncorrectedBlocks(const SignalMonitorValue&) { }
    99     virtual void StatusRotorPosition(const SignalMonitorValue&) { }
    100 
    101   protected slots:
    102     void CancelScan(void) { Teardown(); }
    103     void scanComplete(void);
    104     void transportScanComplete(void);
    105     void updateText(const QString& status);
    106     void updateStatusText(const QString& status);
    107 
    108     void serviceScanPctComplete(int pct);
    109 
    110   protected:
    111     ~ScanWizardScanner();
    112     void Teardown(void);
    113 
    114     void PreScanCommon(int scantype, uint cardid,
    115                        const QString &inputname,
    116                        uint sourceid, bool do_ignore_signal_timeout);
    117 
    118     void dvbLock(int);
    119     void dvbSNR(int);
    120     void dvbSignalStrength(int);
    121     void customEvent(QEvent *e);
    122 
    123     void MonitorProgress(bool lock, bool strength, bool snr);
    124     void RunPopup(void);
    125     void StopPopup(void);
    126 
    127   public:
    128     static QString kTitle;
    129 
    130   private:
    131     LogList           *log;
    132     ChannelBase       *channel;
    133 
    134     ScanProgressPopup  *popupProgress;
    135     pthread_t           popup_thread;
    136     mutable QMutex      popupLock;
    137 
    138     SIScan             *scanner;
    139     IPTVChannelFetcher *freeboxScanner;
    140 
    141     uint               nVideoSource;
    142 
    143     // dvb-utils imported channels
    144     DTVChannelList channels;
    145 };
    146 
    147 #endif // _SCANWIZARDSCANNER_H_
    148 
  • libs/libmythtv/iptv/iptvchannelfetcher.cpp

     
    1515#include "cardutil.h"
    1616#include "channelutil.h"
    1717#include "iptvchannelfetcher.h"
     18#include "scanmonitor.h"
    1819
    1920#define LOC QString("IPTVChanFetch: ")
    2021#define LOC_ERR QString("IPTVChanFetch, Error: ")
     
    3839}
    3940
    4041IPTVChannelFetcher::IPTVChannelFetcher(
    41     uint cardid, const QString &inputname, uint sourceid) :
     42    uint cardid, const QString &inputname, uint sourceid,
     43    ScanMonitor *monitor) :
     44    _scan_monitor(monitor),
    4245    _cardid(cardid),       _inputname(inputname),
    4346    _sourceid(sourceid),
    4447    _chan_cnt(1),          _thread_running(false),
     
    115118    VERBOSE(VB_CHANNEL, QString("Playlist URL: %1").arg(url));
    116119
    117120    // Step 2/4 : Download
    118     emit ServiceScanPercentComplete(5);
    119     emit ServiceScanUpdateText(tr("Downloading Playlist"));
     121    if (_scan_monitor)
     122    {
     123        _scan_monitor->ScanPercentComplete(5);
     124        _scan_monitor->ScanAppendTextToLog(QObject::tr("Downloading Playlist"));
     125    }
    120126
    121127    QString playlist = DownloadPlaylist(url, true);
    122128
     
    127133    }
    128134
    129135    // Step 3/4 : Process
    130     emit ServiceScanPercentComplete(35);
    131     emit ServiceScanUpdateText(tr("Processing Playlist"));
     136    if (_scan_monitor)
     137    {
     138        _scan_monitor->ScanPercentComplete(35);
     139        _scan_monitor->ScanAppendTextToLog(QObject::tr("Processing Playlist"));
     140    }
    132141
    133142    const fbox_chan_map_t channels = ParsePlaylist(playlist, this);
    134143
    135144    // Step 4/4 : Finish up
    136     emit ServiceScanUpdateText(tr("Adding Channels"));
     145    if (_scan_monitor)
     146        _scan_monitor->ScanAppendTextToLog(QObject::tr("Adding Channels"));
    137147    SetTotalNumChannels(channels.size());
    138148    fbox_chan_map_t::const_iterator it = channels.begin();   
    139149    for (uint i = 1; it != channels.end(); ++it, ++i)
     
    141151        QString channum = it.key();
    142152        QString name    = (*it).m_name;
    143153        QString xmltvid = (*it).m_xmltvid.isEmpty() ? "" : (*it).m_xmltvid;
    144         QString msg     = tr("Channel #%1 : %2").arg(channum).arg(name);
     154        QString msg = QObject::tr("Channel #%1 : %2").arg(channum).arg(name);
    145155
    146156        int chanid = ChannelUtil::GetChanID(_sourceid, channum);
    147157        if (chanid <= 0)
    148158        {
    149             emit ServiceScanUpdateText(tr("Adding %1").arg(msg));
     159            if (_scan_monitor)
     160            {
     161                _scan_monitor->ScanAppendTextToLog(
     162                    QObject::tr("Adding %1").arg(msg));
     163            }
    150164            chanid = ChannelUtil::CreateChanID(_sourceid, channum);
    151165            ChannelUtil::CreateChannel(
    152166                0, _sourceid, chanid, name, name, channum,
     
    155169        }
    156170        else
    157171        {
    158             emit ServiceScanUpdateText(tr("Updating %1").arg(msg));
     172            if (_scan_monitor)
     173            {
     174                _scan_monitor->ScanAppendTextToLog(
     175                    QObject::tr("Updating %1").arg(msg));
     176            }
    159177            ChannelUtil::UpdateChannel(
    160178                0, _sourceid, chanid, name, name, channum,
    161179                0, 0, 0, false, false, false, QString::null,
     
    165183        SetNumChannelsInserted(i);
    166184    }
    167185
    168     emit ServiceScanUpdateText(tr("Done"));
    169     emit ServiceScanUpdateText("");
    170     emit ServiceScanPercentComplete(100);
    171     emit ServiceScanComplete();
     186    if (_scan_monitor)
     187    {
     188        _scan_monitor->ScanAppendTextToLog(QObject::tr("Done"));
     189        _scan_monitor->ScanAppendTextToLog("");
     190        _scan_monitor->ScanPercentComplete(100);
     191        _scan_monitor->ScanComplete();
     192    }
    172193
    173194    _thread_running = false;
    174195}
     
    177198{
    178199    uint minval = 35, range = 70 - minval;
    179200    uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range);
    180     emit ServiceScanPercentComplete(pct);
     201    if (_scan_monitor)
     202        _scan_monitor->ScanPercentComplete(pct);
    181203}
    182204
    183205void IPTVChannelFetcher::SetNumChannelsInserted(uint val)
    184206{
    185207    uint minval = 70, range = 100 - minval;
    186208    uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range);
    187     emit ServiceScanPercentComplete(pct);
     209    if (_scan_monitor)
     210        _scan_monitor->ScanPercentComplete(pct);
    188211}
    189212
    190213void IPTVChannelFetcher::SetMessage(const QString &status)
    191214{
    192     emit ServiceScanUpdateText(status);
     215    if (_scan_monitor)
     216        _scan_monitor->ScanAppendTextToLog(status);
    193217}
    194218
    195219QString IPTVChannelFetcher::DownloadPlaylist(const QString &url,
     
    265289                QString("Invalid channel list header (%1)").arg(header));
    266290
    267291        if (fetcher)
    268             fetcher->SetMessage(tr("ERROR: M3U channel list is malformed"));
     292        {
     293            fetcher->SetMessage(
     294                QObject::tr("ERROR: M3U channel list is malformed"));
     295        }
    269296
    270297        return chanmap;
    271298    }
     
    290317        if (!parse_chan_info(rawdata, info, channum, lineNum))
    291318            break;
    292319
    293         QString msg = tr("Encountered malformed channel");
     320        QString msg = QObject::tr("Encountered malformed channel");
    294321        if (!channum.isEmpty())
    295322        {
    296323            chanmap[channum] = info;
    297324
    298             msg = tr("Parsing Channel #%1 : %2 : %3")
     325            msg = QObject::tr("Parsing Channel #%1 : %2 : %3")
    299326                .arg(channum).arg(info.m_name).arg(info.m_url);
    300327            VERBOSE(VB_CHANNEL, msg);
    301328
  • libs/libmythtv/iptv/iptvchannelfetcher.h

     
    22#define _IPTVCHANNELFETCHER_H_
    33
    44// Qt headers
    5 #include <qobject.h>
    6 #include <qmutex.h>
    7 #include <qthread.h>
     5#include <QObject>
     6#include <QMutex>
     7#include <QThread>
    88
    99// MythTV headers
    1010#include "iptvchannelinfo.h"
    1111
     12class ScanMonitor;
    1213class IPTVChannelFetcher;
    1314
    1415class IPTVChannelFetcherThread : public QThread
     
    1819    IPTVChannelFetcher *iptvfetcher;
    1920};
    2021
    21 class IPTVChannelFetcher : public QObject
     22class IPTVChannelFetcher
    2223{
    23     Q_OBJECT
    24 
    2524    friend class IPTVChannelFetcherThread;
    2625
    2726  public:
    28     IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid);
     27    IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid,
     28                       ScanMonitor *monitor = NULL);
     29    ~IPTVChannelFetcher();
    2930
    3031    bool Scan(void);
    3132    void Stop(void);
     
    3435    static fbox_chan_map_t ParsePlaylist(
    3536        const QString &rawdata, IPTVChannelFetcher *fetcher = NULL);
    3637
    37   signals:
    38     /** \brief Tells listener how far along we are from 0..100%
    39      *  \param p percentage completion
    40      */
    41     void ServiceScanPercentComplete(int p);
    42     /// \brief Returns tatus message from the scanner
    43     void ServiceScanUpdateText(const QString &status);
    44     /// \brief Signals that the scan is complete
    45     void ServiceScanComplete(void);
    46 
    47   protected:
    48     void RunScan(void);
    49 
    5038  private:
    51     ~IPTVChannelFetcher();
    5239    void SetTotalNumChannels(uint val) { _chan_cnt = (val) ? val : 1; }
    5340    void SetNumChannelsParsed(uint);
    5441    void SetNumChannelsInserted(uint);
    5542    void SetMessage(const QString &status);
    5643
     44  protected:
     45    void RunScan(void);
     46
    5747  private:
     48    ScanMonitor *_scan_monitor;
    5849    uint      _cardid;
    5950    QString   _inputname;
    6051    uint      _sourceid;
  • libs/libmythtv/scanwizardhelpers.cpp

     
    1 /* -*- Mode: c++ -*-
    2  * $Id$
    3  * vim: set expandtab tabstop=4 shiftwidth=4:
    4  *
    5  * Original Project
    6  *      MythTV      http://www.mythtv.org
    7  *
    8  * Author(s):
    9  *      John Pullan  (john@pullan.org)
    10  *
    11  * Description:
    12  *     Collection of classes to provide dvb channel scanning
    13  *     functionallity
    14  *
    15  *
    16  * This program is free software; you can redistribute it and/or
    17  * modify it under the terms of the GNU General Public License
    18  * as published by the Free Software Foundation; either version 2
    19  * of the License, or (at your option) any later version.
    20  *
    21  * This program is distributed in the hope that it will be useful,
    22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    24  * GNU General Public License for more details.
    25  *
    26  * You should have received a copy of the GNU General Public License
    27  * along with this program; if not, write to the Free Software
    28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    29  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    30  *
    31  */
    32 
    33 // Qt headers
    34 #include <QApplication>
    35 #include <QLocale>
    36 
    37 // MythTV headers
    38 #include "mythcontext.h"
    39 #include "mythdb.h"
    40 #include "mythverbose.h"
    41 #include "frequencies.h"
    42 #include "videosource.h"
    43 #include "cardutil.h"
    44 #include "sourceutil.h"
    45 #include "scanwizardhelpers.h"
    46 #include "scanwizardscanner.h"
    47 #include "scanwizard.h"
    48 
    49 static QString card_types(void)
    50 {
    51     QString cardTypes = "";
    52 
    53 #ifdef USING_DVB
    54     cardTypes += "'DVB'";
    55 #endif // USING_DVB
    56 
    57 #ifdef USING_V4L
    58     if (!cardTypes.isEmpty())
    59         cardTypes += ",";
    60     cardTypes += "'V4L'";
    61 # ifdef USING_IVTV
    62     cardTypes += ",'MPEG'";
    63 # endif // USING_IVTV
    64 # ifdef USING_HDPVR
    65     cardTypes += ",'HDPVR'";
    66 # endif // USING_HDPVR
    67 #endif // USING_V4L
    68 
    69 #ifdef USING_IPTV
    70     if (!cardTypes.isEmpty())
    71         cardTypes += ",";
    72     cardTypes += "'FREEBOX'";
    73 #endif // USING_IPTV
    74 
    75 #ifdef USING_HDHOMERUN
    76     if (!cardTypes.isEmpty())
    77         cardTypes += ",";
    78     cardTypes += "'HDHOMERUN'";
    79 #endif // USING_HDHOMERUN
    80 
    81     if (cardTypes.isEmpty())
    82         cardTypes = "'DUMMY'";
    83 
    84     return QString("(%1)").arg(cardTypes);
    85 }
    86 
    87 ScanProgressPopup::ScanProgressPopup(bool lock, bool strength, bool snr) :
    88     ConfigurationPopupDialog(),
    89     done(false), ss(NULL), sn(NULL), progressBar(NULL), sl(NULL), sta(NULL)
    90 {
    91     setLabel(tr("Scan Progress"));
    92 
    93     addChild(sta = new TransLabelSetting());
    94     sta->setLabel(tr("Status"));
    95     sta->setValue(tr("Tuning"));
    96 
    97     if (lock)
    98     {
    99         addChild(sl = new TransLabelSetting());
    100         sl->setValue("                                  "
    101                      "                                  ");
    102     }
    103 
    104     if (strength)
    105     {
    106         addChild(ss = new ScanSignalMeter(65535));
    107         ss->setLabel(tr("Signal Strength"));
    108     }
    109 
    110     if (snr)
    111     {
    112         addChild(sn = new ScanSignalMeter(65535));
    113         sn->setLabel(tr("Signal/Noise"));
    114     }
    115 
    116     addChild(progressBar = new ScanSignalMeter(65535));
    117     progressBar->setValue(0);
    118     progressBar->setLabel(tr("Scan"));
    119 
    120 
    121     TransButtonSetting *cancel = new TransButtonSetting();
    122     cancel->setLabel(tr("Cancel"));
    123     addChild(cancel);
    124 
    125     connect(cancel, SIGNAL(pressed(void)),
    126             this,   SLOT(  reject(void)));
    127 
    128     //Seem to need to do this as the constructor doesn't seem enough
    129     setUseLabel(false);
    130     setUseFrame(false);
    131 }
    132 
    133 ScanProgressPopup::~ScanProgressPopup()
    134 {
    135     VERBOSE(VB_SIPARSER, "~ScanProgressPopup()");
    136 }
    137 
    138 void ScanProgressPopup::SetStatusSignalToNoise(int value)
    139 {
    140     if (sn)
    141         sn->setValue(value);
    142 }
    143 
    144 void ScanProgressPopup::SetStatusSignalStrength(int value)
    145 {
    146     if (ss)
    147         ss->setValue(value);
    148 }
    149 
    150 void ScanProgressPopup::SetStatusLock(int value)
    151 {
    152     if (sl)
    153         sl->setValue((value) ? tr("Locked") : tr("No Lock"));
    154 }
    155 
    156 void ScanProgressPopup::SetScanProgress(double value)
    157 {
    158     if (progressBar)
    159         progressBar->setValue((uint)(value * 65535));
    160 }
    161 
    162 void ScanProgressPopup::SetStatusText(const QString &value)
    163 {
    164     if (sta)
    165         sta->setValue(value);
    166 }
    167 
    168 void ScanProgressPopup::SetStatusTitleText(const QString &value)
    169 {
    170     QString msg = tr("Scan Progress") + QString(" %1").arg(value);
    171     setLabel(msg);
    172 }
    173 
    174 void ScanProgressPopup::deleteLater(void)
    175 {
    176     disconnect();
    177     if (dialog)
    178     {
    179         VERBOSE(VB_IMPORTANT, "Programmer Error: "
    180                 "ScanProgressPopup::DeleteDialog() never called.");
    181     }
    182     ConfigurationPopupDialog::deleteLater();
    183 }
    184 
    185 void ScanProgressPopup::CreateDialog(void)
    186 {
    187     if (!dialog)
    188     {
    189         dialog = (ConfigPopupDialogWidget*)
    190             dialogWidget(gContext->GetMainWindow(),
    191                          "ConfigurationPopupDialog");
    192         dialog->ShowPopup(this, SLOT(Done(void)));
    193     }
    194 }
    195 
    196 void ScanProgressPopup::DeleteDialog(void)
    197 {
    198     if (dialog)
    199     {
    200         dialog->deleteLater();
    201         dialog = NULL;
    202     }
    203 }
    204 
    205 DialogCode ScanProgressPopup::exec(void)
    206 {
    207     if (!dialog)
    208     {
    209         dialog = (ConfigPopupDialogWidget*)
    210             dialogWidget(gContext->GetMainWindow(),
    211                          "ConfigurationPopupDialog");
    212     }
    213 
    214     dialog->setResult(kDialogCodeRejected);
    215 
    216     done = false;
    217 
    218     // Qt4 requires a QMutex as a parameter...
    219     // not sure if this is the best solution.  Mutex Must be locked before wait.
    220     QMutex mutex;
    221     QMutexLocker locker(&mutex);
    222 
    223     while (!done)
    224         wait.wait(&mutex, 100);
    225 
    226     return dialog->result();
    227 }
    228 
    229 void ScanProgressPopup::Done(void)
    230 {
    231     done = true;
    232     wait.wakeAll();
    233 }
    234 
    235 void post_event(QObject *dest, ScannerEvent::TYPE type, int val)
    236 {
    237     ScannerEvent *e = new ScannerEvent(type);
    238     e->intValue(val);
    239     QApplication::postEvent(dest, e);
    240 }
    241 
    242 void post_event(QObject *dest, ScannerEvent::TYPE type, const QString &val)
    243 {
    244     ScannerEvent *e = new ScannerEvent(type);
    245     QString tmp = val; tmp.detach();
    246     e->strValue(tmp);
    247     QApplication::postEvent(dest, e);
    248 }
    249 
    250 void post_event(QObject *dest, ScannerEvent::TYPE type, int val,
    251                 ScanProgressPopup *spp)
    252 {
    253     ScannerEvent *e = new ScannerEvent(type);
    254     e->intValue(val);
    255     e->ScanProgressPopupValue(spp);
    256     QApplication::postEvent(dest, e);
    257 }
    258 
    259 void MultiplexSetting::Load(void)
    260 {
    261     clearSelections();
    262 
    263     if (!sourceid)
    264         return;
    265 
    266     MSqlQuery query(MSqlQuery::InitCon());
    267 
    268     query.prepare(
    269         "SELECT mplexid,   networkid,  transportid, "
    270         "       frequency, symbolrate, modulation "
    271         "FROM dtv_multiplex "
    272         "WHERE sourceid = :SOURCEID "
    273         "ORDER by frequency, networkid, transportid");
    274     query.bindValue(":SOURCEID", sourceid);
    275 
    276     if (!query.exec() || !query.isActive() || query.size() <= 0)
    277         return;
    278 
    279     while (query.next())
    280     {
    281         QString DisplayText;
    282         if (query.value(5).toString() == "8vsb")
    283         {
    284             QString ChannelNumber =
    285                 QString("Freq %1").arg(query.value(3).toInt());
    286             struct CHANLIST* curList = chanlists[0].list;
    287             int totalChannels = chanlists[0].count;
    288             int findFrequency = (query.value(3).toInt() / 1000) - 1750;
    289             for (int x = 0 ; x < totalChannels ; x++)
    290             {
    291                 if ((curList[x].freq <= findFrequency + 200) &&
    292                     (curList[x].freq >= findFrequency - 200))
    293                 {
    294                     ChannelNumber = QString("%1").arg(curList[x].name);
    295                 }
    296             }
    297             DisplayText = QObject::tr("ATSC Channel %1").arg(ChannelNumber);
    298         }
    299         else
    300         {
    301             DisplayText = QString("%1 Hz (%2) (%3) (%4)")
    302                 .arg(query.value(3).toString())
    303                 .arg(query.value(4).toString())
    304                 .arg(query.value(1).toInt())
    305                 .arg(query.value(2).toInt());
    306         }
    307         addSelection(DisplayText, query.value(0).toString());
    308     }
    309 }
    310 
    311 void MultiplexSetting::SetSourceID(uint _sourceid)
    312 {
    313     sourceid = _sourceid;
    314     Load();
    315 }
    316 
    317 InputSelector::InputSelector(
    318     uint _default_cardid, const QString &_default_inputname) :
    319     ComboBoxSetting(this), sourceid(0), default_cardid(_default_cardid),
    320     default_inputname(_default_inputname)
    321 {
    322     default_inputname.detach();
    323     setLabel(tr("Input"));
    324 }
    325 
    326 void InputSelector::Load(void)
    327 {
    328     clearSelections();
    329 
    330     if (!sourceid)
    331         return;
    332 
    333     MSqlQuery query(MSqlQuery::InitCon());
    334     query.prepare(
    335         "SELECT capturecard.cardid, cardtype, videodevice, inputname "
    336         "FROM capturecard, cardinput, videosource "
    337         "WHERE cardinput.sourceid = videosource.sourceid AND "
    338         "      hostname           = :HOSTNAME            AND "
    339         "      cardinput.sourceid = :SOURCEID            AND "
    340         "      cardinput.cardid   = capturecard.cardid");
    341 
    342     query.bindValue(":HOSTNAME", gContext->GetHostName());
    343     query.bindValue(":SOURCEID", sourceid);
    344 
    345     if (!query.exec() || !query.isActive())
    346     {
    347         MythDB::DBError("InputSelector::Load()", query);
    348         return;
    349     }
    350 
    351     uint which = 0, cnt = 0;
    352     for (; query.next(); cnt++)
    353     {
    354         uint    cardid     = query.value(0).toUInt();
    355         QString inputname  = query.value(3).toString();
    356 
    357         QString desc = CardUtil::GetDeviceLabel(
    358             cardid, query.value(1).toString(), query.value(2).toString());
    359 
    360         desc += QString(" (%1)").arg(inputname);
    361 
    362         QString key = QString("%1:%2").arg(cardid).arg(inputname);
    363 
    364         addSelection(desc, key);
    365 
    366         which = (default_cardid == cardid) ? cnt : which;
    367     }
    368 
    369     if (cnt)
    370         setValue(which);
    371 }
    372 
    373 void InputSelector::SetSourceID(const QString &_sourceid)
    374 {
    375     if (sourceid != _sourceid.toUInt())
    376     {
    377         sourceid = _sourceid.toUInt();
    378         Load();
    379     }
    380 }
    381 
    382 uint InputSelector::GetCardID(void) const
    383 {
    384     uint    cardid    = 0;
    385     QString inputname = QString::null;
    386 
    387     Parse(getValue(), cardid, inputname);
    388 
    389     return cardid;
    390 }
    391 
    392 QString InputSelector::GetInputName(void) const
    393 {
    394     uint    cardid    = 0;
    395     QString inputname = QString::null;
    396 
    397     Parse(getValue(), cardid, inputname);
    398 
    399     return inputname;
    400 }
    401 
    402 bool InputSelector::Parse(const QString &cardid_inputname,
    403                           uint          &cardid,
    404                           QString       &inputname)
    405 {
    406     cardid    = 0;
    407     inputname = QString::null;
    408 
    409     int sep0 = cardid_inputname.indexOf(':');
    410     if (sep0 < 1)
    411         return false;
    412 
    413     cardid    = cardid_inputname.left(sep0).toUInt();
    414     inputname = cardid_inputname.mid(sep0 + 1);
    415 
    416     return true;
    417 }
    418 
    419 void ScanTypeSetting::SetInput(const QString &cardids_inputname)
    420 {
    421     uint    cardid    = 0;
    422     QString inputname = QString::null;
    423     if (!InputSelector::Parse(cardids_inputname, cardid, inputname))
    424         return;
    425 
    426     // Only refresh if we really have to. If we do it too often
    427     // Then we end up fighting the scan routine when we want to
    428     // check the type of dvb card :/
    429     if (cardid == hw_cardid)
    430         return;
    431 
    432     hw_cardid       = cardid;
    433     QString subtype = CardUtil::ProbeSubTypeName(hw_cardid);
    434     int nCardType   = CardUtil::toCardType(subtype);
    435     clearSelections();
    436 
    437     bool importConf = false;
    438 
    439     switch (nCardType)
    440     {
    441         case CardUtil::V4L:
    442         case CardUtil::MPEG:
    443             addSelection(tr("Full Scan"),
    444                          QString::number(FullScan_Analog), true);
    445             return;
    446         case CardUtil::OFDM:
    447             addSelection(tr("Full Scan"),
    448                          QString::number(FullScan_OFDM), true);
    449             addSelection(tr("Full Scan (Tuned)"),
    450                          QString::number(NITAddScan_OFDM));
    451             importConf = true;
    452             break;
    453         case CardUtil::QPSK:
    454             addSelection(tr("Full Scan (Tuned)"),
    455                          QString::number(NITAddScan_QPSK));
    456             importConf = true;
    457             break;
    458         case CardUtil::QAM:
    459             addSelection(tr("Full Scan (Tuned)"),
    460                          QString::number(NITAddScan_QAM));
    461             importConf = true;
    462             break;
    463         case CardUtil::ATSC:
    464             addSelection(tr("Full Scan"),
    465                          QString::number(FullScan_ATSC), true);
    466             importConf = true;
    467             break;
    468         case CardUtil::HDHOMERUN:
    469             addSelection(tr("Full Scan (ATSC)"),
    470                          QString::number(FullScan_ATSC), true);
    471             addSelection(tr("Full Scan (DVB)"),
    472                          QString::number(FullScan_OFDM), true);
    473             addSelection(tr("Full Scan (DVB, tuned)"),
    474                          QString::number(NITAddScan_OFDM));
    475             importConf = true;
    476             break;
    477         case CardUtil::FREEBOX:
    478             addSelection(tr("M3U Import"),
    479                          QString::number(IPTVImport), true);
    480             return;
    481         case CardUtil::ERROR_PROBE:
    482             addSelection(QObject::tr("Failed to probe the card"),
    483                          QString::number(Error_Probe), true);
    484             return;
    485         default:
    486             addSelection(QObject::tr("Failed to open the card"),
    487                          QString::number(Error_Open), true);
    488             return;
    489     }
    490 
    491     if (importConf)
    492         addSelection(tr("Import channels.conf"),
    493                      QString::number(DVBUtilsImport));
    494 
    495     addSelection(tr("Full Scan of Existing Transports"),
    496                  QString::number(FullTransportScan));
    497     addSelection(tr("Existing Transport Scan"),
    498                  QString::number(TransportScan));
    499 }
    500 
    501 ScanCountry::ScanCountry() : ComboBoxSetting(this)
    502 {
    503     Country country = AU;
    504     QLocale locale = QLocale::system();
    505     QLocale::Country qtcountry = locale.country();
    506     if (qtcountry == QLocale::Australia)
    507         country = AU;
    508     else if (qtcountry == QLocale::Germany)
    509         country = DE;
    510     else if (qtcountry == QLocale::Finland)
    511         country = FI;
    512     else if (qtcountry == QLocale::Sweden)
    513         country = SE;
    514     else if (qtcountry == QLocale::UnitedKingdom)
    515         country = UK;
    516     else if (qtcountry == QLocale::Spain)
    517         country = ES;
    518     else if (qtcountry == QLocale::NewZealand)
    519         country = NZ;
    520     else if (qtcountry == QLocale::France)
    521         country = FR;
    522 
    523     setLabel(tr("Country"));
    524     addSelection(QObject::tr("Australia"),      "au", country == AU);
    525     addSelection(QObject::tr("Finland"),        "fi", country == FI);
    526     addSelection(QObject::tr("Sweden"),         "se", country == SE);
    527     addSelection(QObject::tr("United Kingdom"), "uk", country == UK);
    528     addSelection(QObject::tr("Germany"),        "de", country == DE);
    529     addSelection(QObject::tr("Spain"),          "es", country == ES);
    530     addSelection(QObject::tr("New Zealand"),    "nz", country == NZ);
    531     addSelection(QObject::tr("France"),         "fr", country == FR);
    532 }
    533 
    534 AnalogPane::AnalogPane() :
    535     VerticalConfigurationGroup(false, false, true, false),
    536     freq_table(new TransFreqTableSelector(0)),
    537     old_channel_treatment(new ScanOldChannelTreatment(false))
    538 {
    539     addChild(freq_table);
    540     addChild(old_channel_treatment);
    541 }
    542 
    543 void AnalogPane::SetSourceID(uint sourceid)
    544 {
    545     freq_table->SetSourceID(sourceid);
    546 }
    547 
    548 QString AnalogPane::GetFrequencyTable(void) const
    549 {
    550     return freq_table->getValue();
    551 }
    552 
    553 ScanOptionalConfig::ScanOptionalConfig(ScanTypeSetting *_scan_type) :
    554     TriggeredConfigurationGroup(false, false, true, true,
    555                                 false, false, true, true),
    556     scanType(_scan_type),
    557     country(new ScanCountry()),
    558     ignoreSignalTimeoutAll(new IgnoreSignalTimeout()),
    559     paneOFDM(new OFDMPane()),     paneQPSK(new QPSKPane()),
    560     paneDVBS2(new DVBS2Pane()),   paneATSC(new ATSCPane()),
    561     paneQAM(new QAMPane()),       paneAnalog(new AnalogPane()),
    562     paneSingle(new STPane()),
    563     paneDVBUtilsImport(new DVBUtilsImportPane())
    564 {
    565     setTrigger(scanType);
    566 
    567     // only save settings for the selected pane
    568     setSaveAll(false);
    569 
    570     // There need to be two IgnoreSignalTimeout instances
    571     // because otherwise Qt will free the one instance twice..
    572 
    573     // There need to be two IgnoreSignalTimeout instances
    574     // because otherwise Qt will free the one instance twice..
    575     VerticalConfigurationGroup *scanAllTransports =
    576         new VerticalConfigurationGroup(false,false,true,true);
    577     scanAllTransports->addChild(ignoreSignalTimeoutAll);
    578 
    579     addTarget(QString::number(ScanTypeSetting::Error_Open),
    580              new ErrorPane(QObject::tr("Failed to open the card")));
    581     addTarget(QString::number(ScanTypeSetting::Error_Probe),
    582              new ErrorPane(QObject::tr("Failed to probe the card")));
    583     addTarget(QString::number(ScanTypeSetting::NITAddScan_QAM),
    584               paneQAM);
    585     addTarget(QString::number(ScanTypeSetting::NITAddScan_QPSK),
    586               paneQPSK);
    587     addTarget(QString::number(ScanTypeSetting::NITAddScan_OFDM),
    588               paneOFDM);
    589     addTarget(QString::number(ScanTypeSetting::FullScan_ATSC),
    590               paneATSC);
    591     addTarget(QString::number(ScanTypeSetting::FullScan_OFDM),
    592               country);
    593     addTarget(QString::number(ScanTypeSetting::FullScan_Analog),
    594               paneAnalog);
    595     addTarget(QString::number(ScanTypeSetting::TransportScan),
    596               paneSingle);
    597     addTarget(QString::number(ScanTypeSetting::FullTransportScan),
    598               scanAllTransports);
    599     addTarget(QString::number(ScanTypeSetting::IPTVImport),
    600               new BlankSetting());
    601     addTarget(QString::number(ScanTypeSetting::DVBUtilsImport),
    602               paneDVBUtilsImport);
    603 }
    604 
    605 void ScanOptionalConfig::triggerChanged(const QString& value)
    606 {
    607     TriggeredConfigurationGroup::triggerChanged(value);
    608 }
    609 
    610 void ScanOptionalConfig::SetSourceID(const QString &sourceid)
    611 {
    612     paneAnalog->SetSourceID(sourceid.toUInt());
    613     paneSingle->SetSourceID(sourceid.toUInt());
    614 }
    615 
    616 void ScanOptionalConfig::SetDefaultATSCFormat(const QString &atscFormat)
    617 {
    618     paneATSC->SetDefaultATSCFormat(atscFormat);
    619     paneSingle->SetDefaultATSCFormat(atscFormat);
    620     paneDVBUtilsImport->SetDefaultATSCFormat(atscFormat);
    621 }
    622 
    623 QString ScanOptionalConfig::GetATSCFormat(const QString &dfl) const
    624 {
    625     int     st =  scanType->getValue().toInt();
    626 
    627     bool    ts0 = (ScanTypeSetting::FullScan_ATSC  == st);
    628     QString vl0 = paneATSC->GetATSCFormat();
    629 
    630     bool    ts1 = (ScanTypeSetting::TransportScan  == st);
    631     QString vl1 = paneSingle->GetATSCFormat();
    632 
    633     bool    ts2 = (ScanTypeSetting::DVBUtilsImport == st);
    634     QString vl2 = paneDVBUtilsImport->GetATSCFormat();
    635 
    636     return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : dfl);
    637 }
    638 
    639 QString ScanOptionalConfig::GetFrequencyStandard(void) const
    640 {
    641     int     st =  scanType->getValue().toInt();
    642 
    643     bool    ts0 = (ScanTypeSetting::FullScan_ATSC   == st);
    644     bool    ts1 = (ScanTypeSetting::FullScan_Analog == st);
    645 
    646     return (ts0) ? "atsc" : ((ts1) ? "analog" : "dvbt");
    647 }
    648 
    649 QString ScanOptionalConfig::GetModulation(void) const
    650 {
    651     int     st =  scanType->getValue().toInt();
    652 
    653     bool    ts0 = (ScanTypeSetting::FullScan_ATSC == st);
    654     QString vl0 = paneATSC->atscModulation();
    655 
    656     bool    ts1 = (ScanTypeSetting::FullScan_OFDM == st);
    657     QString vl1 = "ofdm";
    658 
    659     bool    ts2 = (ScanTypeSetting::FullScan_Analog == st);
    660     QString vl2 = "analog";
    661 
    662     return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : "unknown");
    663 }
    664 
    665 QString ScanOptionalConfig::GetFrequencyTable(void) const
    666 {
    667     int     st =  scanType->getValue().toInt();
    668 
    669     bool    ts0 = (ScanTypeSetting::FullScan_ATSC == st);
    670     QString vl0 = paneATSC->atscFreqTable();
    671 
    672     bool    ts1 = (ScanTypeSetting::FullScan_OFDM == st);
    673     QString vl1 = country->getValue();
    674 
    675     bool    ts2 = (ScanTypeSetting::FullScan_Analog == st);
    676     QString vl2 = paneAnalog->GetFrequencyTable();
    677 
    678     return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : "unknown");
    679 }
    680 
    681 bool ScanOptionalConfig::DoIgnoreSignalTimeout(void) const
    682 {
    683     int  st  = scanType->getValue().toInt();
    684 
    685     bool ts0 = (ScanTypeSetting::TransportScan     == st);
    686     bool vl0 = paneSingle->ignoreSignalTimeout();
    687 
    688     bool ts1 = (ScanTypeSetting::FullTransportScan == st);
    689     bool vl1 = (ignoreSignalTimeoutAll->getValue().toInt());
    690 
    691     bool ts2 = (ScanTypeSetting::DVBUtilsImport    == st);
    692     bool vl2 = paneDVBUtilsImport->DoIgnoreSignalTimeout();
    693 
    694     return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : false);
    695 }
    696 
    697 bool ScanOptionalConfig::DoDeleteChannels(void) const
    698 {
    699     int  st  = scanType->getValue().toInt();
    700 
    701     bool ts0 = (ScanTypeSetting::FullScan_ATSC  == st);
    702     bool vl0 = paneATSC->DoDeleteChannels();
    703 
    704     bool ts1 = (ScanTypeSetting::TransportScan  == st);
    705     bool vl1 = paneSingle->DoDeleteChannels();
    706 
    707     bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);
    708     bool vl2 = paneDVBUtilsImport->DoDeleteChannels();
    709 
    710     bool ts3 = (ScanTypeSetting::FullScan_Analog == st);
    711     bool vl3 = paneAnalog->DoDeleteChannels();
    712 
    713     return (ts0) ? vl0 : (((ts1) ? vl1 : (ts2) ? vl2 : (ts3) ? vl3 : false));
    714 }
    715 
    716 bool ScanOptionalConfig::DoRenameChannels(void) const
    717 {
    718     int  st  = scanType->getValue().toInt();
    719 
    720     bool ts0 = (ScanTypeSetting::FullScan_ATSC  == st);
    721     bool vl0 = paneATSC->DoRenameChannels();
    722 
    723     bool ts1 = (ScanTypeSetting::TransportScan  == st);
    724     bool vl1 = paneSingle->DoRenameChannels();
    725 
    726     bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);
    727     bool vl2 = paneDVBUtilsImport->DoRenameChannels();
    728 
    729     bool ts3 = (ScanTypeSetting::FullScan_Analog == st);
    730     bool vl3 = paneAnalog->DoRenameChannels();
    731 
    732     return (ts0) ? vl0 : (((ts1) ? vl1 : (ts2) ? vl2 : (ts3) ? vl3 : false));
    733 }
    734 
    735 QString ScanOptionalConfig::GetFilename(void) const
    736 {
    737     return paneDVBUtilsImport->GetFilename();
    738 }
    739 
    740 uint ScanOptionalConfig::GetMultiplex(void) const
    741 {
    742     int mplexid = paneSingle->GetMultiplex();
    743     return (mplexid <= 0) ? 0 : mplexid;
    744 }
    745 
    746 QMap<QString,QString> ScanOptionalConfig::GetStartChan(void) const
    747 {
    748     QMap<QString,QString> startChan;
    749 
    750     int st = scanType->getValue().toInt();
    751     if (ScanTypeSetting::NITAddScan_OFDM == st)
    752     {
    753         const OFDMPane *pane = paneOFDM;
    754 
    755         startChan["std"]            = "dvb";
    756         startChan["frequency"]      = pane->frequency();
    757         startChan["inversion"]      = pane->inversion();
    758         startChan["bandwidth"]      = pane->bandwidth();
    759         startChan["modulation"]     = "ofdm";
    760         startChan["coderate_hp"]    = pane->coderate_hp();
    761         startChan["coderate_lp"]    = pane->coderate_lp();
    762         startChan["constellation"]  = pane->constellation();
    763         startChan["trans_mode"]     = pane->trans_mode();
    764         startChan["guard_interval"] = pane->guard_interval();
    765         startChan["hierarchy"]      = pane->hierarchy();
    766     }
    767     else if (ScanTypeSetting::NITAddScan_QPSK == st)
    768     {
    769         const QPSKPane *pane = paneQPSK;
    770 
    771         startChan["std"]        = "dvb";
    772         startChan["frequency"]  = pane->frequency();
    773         startChan["inversion"]  = pane->inversion();
    774         startChan["symbolrate"] = pane->symbolrate();
    775         startChan["fec"]        = pane->fec();
    776         startChan["modulation"] = "qpsk";
    777         startChan["polarity"]   = pane->polarity();
    778     }
    779     else if (ScanTypeSetting::NITAddScan_QAM == st)
    780     {
    781         const QAMPane *pane = paneQAM;
    782 
    783         startChan["std"]        = "dvb";
    784         startChan["frequency"]  = pane->frequency();
    785         startChan["inversion"]  = pane->inversion();
    786         startChan["symbolrate"] = pane->symbolrate();
    787         startChan["fec"]        = pane->fec();
    788         startChan["modulation"] = pane->modulation();
    789     }
    790 
    791     return startChan;
    792 }
    793 
    794 ScanWizardConfig::ScanWizardConfig(
    795     ScanWizard *_parent,
    796     uint    default_sourceid,  uint default_cardid,
    797     QString default_inputname) :
    798     VerticalConfigurationGroup(false, true, false, false),
    799     videoSource(new VideoSourceSelector(
    800                     default_sourceid, card_types(), false)),
    801     input(new InputSelector(default_cardid, default_inputname)),
    802     scanType(new ScanTypeSetting()),
    803     scanConfig(new ScanOptionalConfig(scanType))
    804 {
    805     setLabel(tr("Scan Configuration"));
    806 
    807     addChild(videoSource);
    808     addChild(input);
    809     addChild(scanType);
    810     addChild(scanConfig);
    811 
    812     connect(videoSource, SIGNAL(valueChanged(const QString&)),
    813             scanConfig,  SLOT(  SetSourceID( const QString&)));
    814 
    815     connect(videoSource, SIGNAL(valueChanged(const QString&)),
    816             input,       SLOT(  SetSourceID( const QString&)));
    817 
    818     connect(input,       SIGNAL(valueChanged(const QString&)),
    819             scanType,    SLOT(  SetInput(    const QString&)));
    820 
    821     connect(input,       SIGNAL(valueChanged(const QString&)),
    822             _parent,     SLOT(  SetInput(    const QString&)));
    823 }
    824 
    825 uint ScanWizardConfig::GetSourceID(void) const
    826 {
    827     return videoSource->getValue().toUInt();
    828 }
    829 
    830 QString ScanWizardConfig::GetATSCFormat(void) const
    831 {
    832     QString dfl = SourceUtil::GetChannelFormat(GetSourceID());
    833     return scanConfig->GetATSCFormat(dfl);
    834 }
    835 
    836 LogList::LogList() : ListBoxSetting(this), n(0)
    837 {
    838     setSelectionMode(MythListBox::NoSelection);
    839 }
    840 
    841 void LogList::updateText(const QString& status)
    842 {
    843     addSelection(status,QString::number(n));
    844     setCurrentItem(n);
    845     n++;
    846 }
  • programs/mythtv-setup/main.cpp

     
    2020#include "mythuihelper.h"
    2121#include "mythdirs.h"
    2222
     23#include "libmythtv/channelscan/channelscanner_cli.h"
     24#include "libmythtv/channelscan/scanwizardconfig.h"
     25#include "libmythtv/channelscan/scaninfo.h"
     26#include "libmythtv/channelscan/channelimporter.h"
     27#include "libmythtv/cardutil.h"
    2328#include "libmythtv/dbcheck.h"
    2429#include "libmythtv/videosource.h"
    2530#include "channeleditor.h"
     
    108113{
    109114    QString geometry = QString::null;
    110115    QString display  = QString::null;
    111     QString verboseString = QString(" important general");
     116    bool    doScan   = false;
     117    bool    doScanList = false;
     118    bool    doScanSaveOnly = false;
     119    bool    scanInteractive = true;
     120    uint    scanImport = 0;
     121    uint    scanCardId = 0;
     122    QString scanTableName = "atsc-vsb8-us";
     123    QString scanInputName = "";
     124    bool    use_display = true;
    112125
    113126#ifdef USING_X11
    114127    // Remember any -display or -geometry argument
     
    119132            geometry = argv[argpos+1];
    120133        else if (!strcmp(argv[argpos],"-display"))
    121134            display = argv[argpos+1];
     135        else if (QString(argv[argpos]).left(6) == "--scan")
     136        {
     137            use_display = false;
     138            print_verbose_messages = 0;
     139            verboseString = "";
     140        }
    122141    }
    123142#endif
    124143
     
    127146    // of the MythPushButton widgets, and they don't use the themed background.
    128147    QApplication::setDesktopSettingsAware(FALSE);
    129148#endif
    130     QApplication a(argc, argv);
     149    QApplication a(argc, argv, use_display);
    131150
    132151    QMap<QString, QString> settingsOverride;
    133152
     
    223242
    224243            ++argpos;
    225244        }
     245        else if (!strcmp(a.argv()[argpos],"--scan-list"))
     246        {
     247            doScanList = true;
     248        }
     249        else if (!strcmp(a.argv()[argpos],"--scan-import"))
     250        {
     251            if (a.argc()-1 > argpos)
     252            {
     253                QString tmpArg = a.argv()[argpos + 1];
     254                scanImport = tmpArg.toUInt();
     255                ++argpos;
     256            }
     257            else
     258            {
     259                cerr << "Missing scan number for import, please run "
     260                     << "--scan-list to list importable scans." << endl;
     261                return BACKEND_EXIT_INVALID_CMDLINE;
     262            }
     263        }
     264        else if (!strcmp(a.argv()[argpos],"--scan-save-only"))
     265        {
     266            doScanSaveOnly = true;
     267        }
     268        else if (!strcmp(a.argv()[argpos],"--scan-non-interactive"))
     269        {
     270            scanInteractive = false;
     271        }
     272        else if (!strcmp(a.argv()[argpos],"--scan"))
     273        {
     274            if (a.argc()-1 > argpos)
     275            {
     276                scanTableName = a.argv()[argpos + 1];
     277                ++argpos;
     278            }
     279            if (a.argc()-1 > argpos)
     280            {
     281                QString tmpArg = a.argv()[argpos + 1];
     282                scanCardId = tmpArg.toUInt();
     283                ++argpos;
     284            }
     285            if (a.argc()-1 > argpos)
     286            {
     287                scanInputName = a.argv()[argpos + 1];
     288                ++argpos;
     289            }
     290            doScan = true;
     291        }
    226292        else
    227293        {
    228294            if (!(!strcmp(a.argv()[argpos],"-h") ||
     
    245311                 << "-v or --verbose debug-level    "
    246312                    "Use '-v help' for level info" << endl
    247313                 << endl;
    248             return -1;
     314            return BACKEND_EXIT_INVALID_CMDLINE;
    249315        }
    250316    }
    251317
     
    258324
    259325    std::auto_ptr<MythContext> contextScopeDelete(gContext);
    260326
    261     if (!gContext->Init(true))
     327    if (!gContext->Init(use_display))
    262328    {
    263329        VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
    264330        return GENERIC_EXIT_NO_MYTHCONTEXT;
     
    293359        return GENERIC_EXIT_DB_ERROR;
    294360    }
    295361
    296     gContext->SetSetting("Theme", "G.A.N.T");
    297     GetMythUI()->LoadQtConfig();
     362    if (use_display)
     363    {
     364        gContext->SetSetting("Theme", "G.A.N.T");
     365        GetMythUI()->LoadQtConfig();
    298366
    299     QString fileprefix = GetConfDir();
     367        QString fileprefix = GetConfDir();
    300368
    301     QDir dir(fileprefix);
    302     if (!dir.exists())
    303         dir.mkdir(fileprefix);
     369        QDir dir(fileprefix);
     370        if (!dir.exists())
     371            dir.mkdir(fileprefix);
     372    }
    304373
     374    if (doScan)
     375    {
     376        bool okCardID = scanCardId;
     377
     378        QStringList inputnames = CardUtil::GetInputNames(scanCardId);
     379        okCardID &= !inputnames.empty();
     380
     381        if (scanInputName.isEmpty())
     382            scanInputName = CardUtil::GetDefaultInput(scanCardId);
     383
     384        bool okInputName = inputnames.contains(scanInputName);
     385
     386        doScan = (okCardID && okInputName);
     387
     388        if (!okCardID)
     389        {
     390            cerr << "You must enter a valid cardid to scan." << endl;
     391            vector<uint> cardids = CardUtil::GetCardIDs();
     392            if (cardids.empty())
     393            {
     394                cerr << "But no cards have been defined on this host"
     395                     << endl;
     396                return BACKEND_EXIT_INVALID_CMDLINE;
     397            }
     398            cerr << "Valid cards: " << endl;
     399            for (uint i = 0; i < cardids.size(); i++)
     400            {
     401                fprintf(stderr, "%5i: %s %s\n",
     402                        cardids[i],
     403                        CardUtil::GetRawCardType(cardids[i])
     404                        .toAscii().constData(),
     405                        CardUtil::GetVideoDevice(cardids[i])
     406                        .toAscii().constData());
     407            }
     408            return BACKEND_EXIT_INVALID_CMDLINE;
     409        }
     410
     411        if (!okInputName)
     412        {
     413            cerr << "You must enter a valid input to scan this card."
     414                 << endl;
     415            cerr << "Valid inputs: " << endl;
     416            for (int i = 0; i < inputnames.size(); i++)
     417            {
     418                cerr << inputnames[i].toAscii().constData() << endl;
     419            }
     420            return BACKEND_EXIT_INVALID_CMDLINE;
     421        }
     422    }
     423
     424    if (doScan)
     425    {
     426        int ret = 0;
     427        int firstBreak   = scanTableName.indexOf("-");
     428        int secondBreak  = scanTableName.lastIndexOf("-");
     429        QString freq_std = scanTableName.mid(0, firstBreak).toLower();
     430        QString mod      = scanTableName.mid(
     431            firstBreak+1, secondBreak-firstBreak-1).toLower();
     432        QString tbl      = scanTableName.mid(secondBreak+1).toLower();
     433        uint    inputid  = CardUtil::GetInputID(scanCardId, scanInputName);
     434        uint    sourceid = ChannelUtil::GetSourceID(inputid);
     435        QMap<QString,QString> startChan;
     436        {
     437            ChannelScannerCLI scanner(doScanSaveOnly, scanInteractive);
     438            scanner.Scan(
     439                (freq_std=="atsc") ?
     440                ScanTypeSetting::FullScan_ATSC :
     441                ((freq_std=="dvbt") ?
     442                 ScanTypeSetting::FullScan_DVBT :
     443                 ScanTypeSetting::FullScan_ATSC),
     444                /* cardid    */ scanCardId,
     445                /* inputname */ scanInputName,
     446                /* sourceid  */ sourceid,
     447                false,
     448                // stuff needed for particular scans
     449                /* mplexid   */ 0,
     450                startChan, freq_std, mod, tbl);
     451            ret = a.exec();
     452        }
     453        return (ret) ? GENERIC_EXIT_NOT_OK : BACKEND_EXIT_OK;
     454    }
     455
     456    if (doScanList)
     457    {
     458        vector<ScanInfo> scans = LoadScanList();
     459
     460        cout<<" scanid cardid sourceid processed        date"<<endl;
     461        for (uint i = 0; i < scans.size(); i++)
     462        {
     463            printf("%5i %6i %8i %8s    %20s\n",
     464                   scans[i].scanid,   scans[i].cardid,
     465                   scans[i].sourceid, (scans[i].processed) ? "yes" : "no",
     466                   scans[i].scandate.toString().toAscii().constData());
     467        }
     468        cout<<endl;
     469
     470        return BACKEND_EXIT_OK;
     471    }
     472
     473    if (scanImport)
     474    {
     475        cout<<"*** SCAN IMPORT START ***"<<endl;
     476        {
     477            ScanDTVTransportList list = LoadScan(scanImport);
     478            ChannelImporter ci(false, true, true, false);
     479            ci.Process(list);
     480        }
     481        cout<<"*** SCAN IMPORT END ***"<<endl;
     482        return BACKEND_EXIT_OK;
     483    }
     484
    305485    MythMainWindow *mainWindow = GetMythMainWindow();
    306486    mainWindow->Init();
    307487    gContext->SetMainWindow(mainWindow);