MythTV  0.26-pre
dvbsignalmonitor.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 
00003 #include <cerrno>
00004 #include <cstring>
00005 #include <cmath>
00006 
00007 #include <unistd.h>
00008 
00009 #include "mythcontext.h"
00010 #include "mythdbcon.h"
00011 #include "dvbsignalmonitor.h"
00012 #include "dvbchannel.h"
00013 #include "dvbstreamdata.h"
00014 #include "atscstreamdata.h"
00015 #include "mpegtables.h"
00016 #include "atsctables.h"
00017 #include "cardutil.h"
00018 
00019 #include "dvbtypes.h"
00020 #include "dvbchannel.h"
00021 #include "dvbrecorder.h"
00022 #include "dvbstreamhandler.h"
00023 
00024 #define LOC QString("DVBSM(%1): ").arg(channel->GetDevice())
00025 
00040 DVBSignalMonitor::DVBSignalMonitor(int db_cardnum, DVBChannel* _channel,
00041                                    uint64_t _flags)
00042     : DTVSignalMonitor(db_cardnum, _channel, _flags),
00043       // This snr setup is incorrect for API 3.x but works better
00044       // than int16_t range in practice, however this is correct
00045       // for the 4.0 DVB API which uses a uint16_t for the snr
00046       signalToNoise    (QObject::tr("Signal To Noise"),    "snr",
00047                         0,      true,      0, 65535, 0),
00048       bitErrorRate     (QObject::tr("Bit Error Rate"),     "ber",
00049                         65535,  false,     0, 65535, 0),
00050       uncorrectedBlocks(QObject::tr("Uncorrected Blocks"), "ucb",
00051                         65535,  false,     0, 65535, 0),
00052       rotorPosition    (QObject::tr("Rotor Progress"),     "pos",
00053                         100,    true,      0,   100, 0),
00054       streamHandlerStarted(false),
00055       streamHandler(NULL)
00056 {
00057     // These two values should probably come from the database...
00058     int wait = 3000; // timeout when waiting on signal
00059     int threshold = 0; // signal strength threshold
00060 
00061     signalLock.SetTimeout(wait);
00062     signalStrength.SetTimeout(wait);
00063     signalStrength.SetThreshold(threshold);
00064 
00065     // This is incorrect for API 3.x but works better than int16_t range
00066     // in practice, however this is correct for the 4.0 DVB API
00067     signalStrength.SetRange(0, 65535);
00068 
00069     bool ok;
00070     _channel->HasLock(&ok);
00071     if (!ok)
00072         LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot read DVB status" + ENO);
00073 
00074     uint64_t rmflags = 0;
00075 
00076 #define DVB_IO(FLAG, METHOD, MSG) \
00077   do { if (HasFlags(FLAG)) { bool ok; _channel->METHOD(&ok); \
00078           if (!ok) { \
00079               LOG(VB_GENERAL, LOG_WARNING, LOC+"Cannot "+MSG+ENO); \
00080               rmflags |= FLAG; } \
00081           else { \
00082               LOG(VB_CHANNEL, LOG_INFO, LOC + "Can " + MSG); } } } while (false)
00083 
00084     DVB_IO(kSigMon_WaitForSig, GetSignalStrength,
00085            "measure Signal Strength");
00086     DVB_IO(kDVBSigMon_WaitForSNR, GetSNR,
00087            "measure S/N");
00088     DVB_IO(kDVBSigMon_WaitForBER, GetBitErrorRate,
00089            "measure Bit Error Rate");
00090     DVB_IO(kDVBSigMon_WaitForUB, GetUncorrectedBlockCount,
00091            "count Uncorrected Blocks");
00092 
00093 #undef DVB_IO
00094 
00095     RemoveFlags(rmflags);
00096 
00097     LOG(VB_CHANNEL, LOG_INFO, LOC + "DVBSignalMonitor::ctor " +
00098             QString("initial flags %1").arg(sm_flags_to_string(flags)));
00099 
00100     minimum_update_rate = _channel->GetMinSignalMonitorDelay();
00101     if (minimum_update_rate > 30)
00102         usleep(minimum_update_rate * 1000);
00103 
00104     streamHandler = DVBStreamHandler::Get(_channel->GetCardNum());
00105 }
00106 
00110 DVBSignalMonitor::~DVBSignalMonitor()
00111 {
00112     Stop();
00113     DVBStreamHandler::Return(streamHandler);
00114 }
00115 
00116 // documented in dtvsignalmonitor.h
00117 void DVBSignalMonitor::SetRotorTarget(float target)
00118 {
00119     QMutexLocker locker(&statusLock);
00120     rotorPosition.SetThreshold((int)roundf(100 * target));
00121 }
00122 
00123 void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving)
00124 {
00125     DVBChannel *dvbchannel = GetDVBChannel();
00126     if (!dvbchannel)
00127         return;
00128 
00129     const DiSEqCDevRotor *rotor = dvbchannel->GetRotor();
00130     if (!rotor)
00131         return;
00132 
00133     QMutexLocker locker(&statusLock);
00134     was_moving = rotorPosition.GetValue() < 100;
00135     int pos    = (int)truncf(rotor->GetProgress() * 100);
00136     rotorPosition.SetValue(pos);
00137     is_moving  = rotorPosition.GetValue() < 100;
00138 }
00139 
00143 void DVBSignalMonitor::Stop(void)
00144 {
00145     LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- begin");
00146     SignalMonitor::Stop();
00147     if (GetStreamData())
00148         streamHandler->RemoveListener(GetStreamData());
00149     streamHandlerStarted = false;
00150     streamHandler->SetRetuneAllowed(false, NULL, NULL);
00151     LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- end");
00152 }
00153 
00154 QStringList DVBSignalMonitor::GetStatusList(void) const
00155 {
00156     QStringList list = DTVSignalMonitor::GetStatusList();
00157     statusLock.lock();
00158     if (HasFlags(kDVBSigMon_WaitForSNR))
00159         list<<signalToNoise.GetName()<<signalToNoise.GetStatus();
00160     if (HasFlags(kDVBSigMon_WaitForBER))
00161         list<<bitErrorRate.GetName()<<bitErrorRate.GetStatus();
00162     if (HasFlags(kDVBSigMon_WaitForUB))
00163         list<<uncorrectedBlocks.GetName()<<uncorrectedBlocks.GetStatus();
00164     if (HasFlags(kDVBSigMon_WaitForPos))
00165         list<<rotorPosition.GetName()<<rotorPosition.GetStatus();
00166     statusLock.unlock();
00167     return list;
00168 }
00169 
00170 void DVBSignalMonitor::HandlePMT(uint program_num, const ProgramMapTable *pmt)
00171 {
00172     DTVSignalMonitor::HandlePMT(program_num, pmt);
00173 
00174     if (pmt->ProgramNumber() == (uint)programNumber)
00175     {
00176         DVBChannel *dvbchannel = GetDVBChannel();
00177         if (dvbchannel)
00178             dvbchannel->SetPMT(pmt);
00179     }
00180 }
00181 
00182 void DVBSignalMonitor::HandleSTT(const SystemTimeTable *stt)
00183 {
00184     DTVSignalMonitor::HandleSTT(stt);
00185     DVBChannel *dvbchannel = GetDVBChannel();
00186     if (dvbchannel)
00187         dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
00188 }
00189 
00190 void DVBSignalMonitor::HandleTDT(const TimeDateTable *tdt)
00191 {
00192     DTVSignalMonitor::HandleTDT(tdt);
00193     DVBChannel *dvbchannel = GetDVBChannel();
00194     if (dvbchannel)
00195         dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
00196 }
00197 
00198 DVBChannel *DVBSignalMonitor::GetDVBChannel(void)
00199 {
00200     return dynamic_cast<DVBChannel*>(channel);
00201 }
00202 
00209 void DVBSignalMonitor::UpdateValues(void)
00210 {
00211     if (!running || exit)
00212         return;
00213 
00214     if (streamHandlerStarted)
00215     {
00216         if (!streamHandler->IsRunning())
00217         {
00218             error = QObject::tr("Error: stream handler died");
00219             update_done = true;
00220             return;
00221         }
00222 
00223         EmitStatus();
00224         if (IsAllGood())
00225             SendMessageAllGood();
00226 
00227         // TODO dtv signals...
00228 
00229         update_done = true;
00230         return;
00231     }
00232 
00233     AddFlags(kSigMon_WaitForSig);
00234 
00235     DVBChannel *dvbchannel = GetDVBChannel();
00236     if (!dvbchannel)
00237         return;
00238 
00239     // Handle retuning after rotor has turned
00240     if (HasFlags(SignalMonitor::kDVBSigMon_WaitForPos))
00241     {
00242         if (dvbchannel->GetRotor())
00243         {
00244             if (!streamHandler->IsRetuneAllowed())
00245                 streamHandler->SetRetuneAllowed(true, this, dvbchannel);
00246             streamHandler->RetuneMonitor();
00247         }
00248         else
00249             RemoveFlags(SignalMonitor::kDVBSigMon_WaitForPos);
00250     }
00251 
00252     bool wasLocked = false, isLocked = false;
00253     uint sig = 0, snr = 0, ber = 0, ublocks = 0;
00254 
00255     // Get info from card
00256     bool has_lock = dvbchannel->HasLock();
00257     if (HasFlags(kSigMon_WaitForSig))
00258         sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
00259     if (HasFlags(kDVBSigMon_WaitForSNR))
00260         snr = (uint) (dvbchannel->GetSNR() * 65535);
00261     if (HasFlags(kDVBSigMon_WaitForBER))
00262         ber = (uint) dvbchannel->GetBitErrorRate();
00263     if (HasFlags(kDVBSigMon_WaitForUB))
00264         ublocks = (uint) dvbchannel->GetUncorrectedBlockCount();
00265 
00266     has_lock |= streamHandler->IsRunning();
00267 
00268     // Set SignalMonitorValues from info from card.
00269     {
00270         QMutexLocker locker(&statusLock);
00271 
00272         // BER and UB are actually uint32 values, but we
00273         // clamp them at 64K. This is because these values
00274         // are acutally cumulative, but we don't try to
00275         // normalize these to a time period.
00276 
00277         wasLocked = signalLock.IsGood();
00278         signalLock.SetValue((has_lock) ? 1 : 0);
00279         isLocked = signalLock.IsGood();
00280 
00281         if (HasFlags(kSigMon_WaitForSig))
00282             signalStrength.SetValue(sig);
00283         if (HasFlags(kDVBSigMon_WaitForSNR))
00284             signalToNoise.SetValue(snr);
00285         if (HasFlags(kDVBSigMon_WaitForBER))
00286             bitErrorRate.SetValue(ber);
00287         if (HasFlags(kDVBSigMon_WaitForUB))
00288             uncorrectedBlocks.SetValue(ublocks);
00289     }
00290 
00291     // Debug output
00292     if (wasLocked != isLocked)
00293     {
00294         LOG(VB_CHANNEL, LOG_INFO, LOC + "UpdateValues -- Signal " +
00295                 (isLocked ? "Locked" : "Lost"));
00296     }
00297 
00298     EmitStatus();
00299     if (IsAllGood())
00300         SendMessageAllGood();
00301 
00302     // Start table monitoring if we are waiting on any table
00303     // and we have a lock.
00304     if (isLocked && GetStreamData() &&
00305         (!HasFlags(kDVBSigMon_WaitForPos) || rotorPosition.IsGood()) &&
00306         HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT |
00307                    kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
00308                    kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
00309     {
00310         GetStreamData()->AddListeningPID(MPEG_PAT_PID);
00311         streamHandler->AddListener(GetStreamData(), true, false);
00312         streamHandlerStarted = true;
00313     }
00314 
00315     update_done = true;
00316 }
00317 
00321 void DVBSignalMonitor::EmitStatus(void)
00322 {
00323     // Emit signals..
00324     DTVSignalMonitor::EmitStatus();
00325     if (HasFlags(kDVBSigMon_WaitForSNR))
00326         SendMessage(kStatusSignalToNoise,     signalToNoise);
00327     if (HasFlags(kDVBSigMon_WaitForBER))
00328         SendMessage(kStatusBitErrorRate,      bitErrorRate);
00329     if (HasFlags(kDVBSigMon_WaitForUB))
00330         SendMessage(kStatusUncorrectedBlocks, uncorrectedBlocks);
00331     if (HasFlags(kDVBSigMon_WaitForPos))
00332         SendMessage(kStatusRotorPosition,     rotorPosition);
00333 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends