MythTV master
dvbsignalmonitor.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2
3#include <cerrno>
4#include <cmath>
5#include <cstring>
6
7#include <unistd.h>
8
9//Qt headers
10#include <QCoreApplication>
11
12// MythTV headers
15
16#include "cardutil.h"
17#include "dvbchannel.h"
18#include "dvbrecorder.h"
19#include "dvbsignalmonitor.h"
20#include "dvbstreamhandler.h"
21#include "dvbtypes.h"
22#include "mpeg/atscstreamdata.h"
23#include "mpeg/atsctables.h"
24#include "mpeg/dvbstreamdata.h"
25#include "mpeg/mpegtables.h"
26
27#define LOC QString("DVBSigMon[%1](%2): ") \
28 .arg(m_inputid).arg(m_channel->GetDevice())
29
46 bool _release_stream,
47 uint64_t _flags)
48 : DTVSignalMonitor(db_cardnum, _channel, _release_stream, _flags),
49 // This snr setup is incorrect for API 3.x but works better
50 // than int16_t range in practice, however this is correct
51 // for the 4.0 DVB API which uses a uint16_t for the snr
52 m_signalToNoise (QCoreApplication::translate("(Common)",
53 "Signal To Noise"), "snr",
54 0, true, 0, 65535, 0ms),
55 m_bitErrorRate (tr("Bit Error Rate"), "ber",
56 65535, false, 0, 65535, 0ms),
57 m_uncorrectedBlocks(tr("Uncorrected Blocks"), "ucb",
58 65535, false, 0, 65535, 0ms),
59 m_rotorPosition (tr("Rotor Progress"), "pos",
60 100, true, 0, 100, 0ms),
61 m_streamHandlerStarted(false),
62 m_streamHandler(nullptr)
63{
64 // This value should probably come from the database...
65 int threshold = 0; // signal strength threshold
66
67 // Tuning timeout time for channel lock from database, minimum is 3s
68 std::chrono::milliseconds wait = 3s; // Minimum timeout time
69 std::chrono::milliseconds signal_timeout = 0ms; // Not used
70 std::chrono::milliseconds tuning_timeout = 0ms; // Maximum time for channel lock from card
71 CardUtil::GetTimeouts(db_cardnum, signal_timeout, tuning_timeout);
72 if (tuning_timeout < wait)
73 {
74 LOG(VB_CHANNEL, LOG_DEBUG, LOC +
75 QString("Tuning timeout from database: %1 ms is too small, using %2 ms")
76 .arg(tuning_timeout.count()).arg(wait.count()));
77 }
78 else
79 {
80 wait = tuning_timeout; // Use value from database
81 LOG(VB_CHANNEL, LOG_DEBUG, LOC +
82 QString("Tuning timeout: %1 ms").arg(wait.count()));
83 }
84
88
89 // This is incorrect for API 3.x but works better than int16_t range
90 // in practice, however this is correct for the 4.0 DVB API
91 m_signalStrength.SetRange(0, 65535);
92
93 // Determine the signal monitoring capabilities from the card and
94 // do not use the capabilities that are not present.
95 uint64_t rmflags = 0;
96 bool mok = false;
97
98 auto log_message = [&mok](const QString& loc, const QString& msg)
99 {
100 if (mok)
101 LOG(VB_CHANNEL, LOG_INFO, loc + "Can " + msg);
102 else
103 LOG(VB_GENERAL, LOG_WARNING, loc + "Cannot " + msg + ENO);
104 };
105
106 auto log_message_channel = [&mok](const QString& loc, const QString& msg)
107 {
108 if (mok)
109 LOG(VB_CHANNEL, LOG_INFO, loc + "Can " + msg);
110 else
111 LOG(VB_CHANNEL, LOG_WARNING, loc + "Cannot " + msg + ENO);
112 };
113
114 auto update_rmflags = [&mok, &rmflags](uint64_t flag)
115 {
116 if (!mok)
117 rmflags |= flag;
118 };
119
120 // Signal strength
121 auto flag = kSigMon_WaitForSig;
122 if (HasFlags(flag))
123 {
124 _channel->GetSignalStrength(&mok);
125 update_rmflags(flag);
126 log_message(LOC, "measure Signal Strength");
127 }
128
129 // Signal/Noise ratio
131 if (HasFlags(flag))
132 {
133 _channel->GetSNR(&mok);
134 update_rmflags(flag);
135 log_message(LOC, "measure S/N");
136 }
137
138 // Bit error rate
140 if (HasFlags(flag))
141 {
142 _channel->GetBitErrorRate(&mok);
143 update_rmflags(flag);
144 log_message_channel(LOC, "measure Bit Error Rate");
145 }
146
147 // Uncorrected block count
149 if (HasFlags(flag))
150 {
151 _channel->GetUncorrectedBlockCount(&mok);
152 update_rmflags(flag);
153 log_message_channel(LOC, "count Uncorrected Blocks");
154 }
155
156 RemoveFlags(rmflags);
157
158 LOG(VB_CHANNEL, LOG_INFO, LOC + "DVBSignalMonitor::ctor " +
159 QString("initial flags %1").arg(sm_flags_to_string(m_flags)));
160
162 if (m_minimumUpdateRate > 30ms)
164
166}
167
172{
175}
176
177// documented in dtvsignalmonitor.h
179{
180 QMutexLocker locker(&m_statusLock);
181 m_rotorPosition.SetThreshold((int)roundf(100 * target));
182}
183
184void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving)
185{
186 DVBChannel *dvbchannel = GetDVBChannel();
187 if (!dvbchannel)
188 return;
189
190 const DiSEqCDevRotor *rotor = dvbchannel->GetRotor();
191 if (!rotor)
192 return;
193
194 QMutexLocker locker(&m_statusLock);
195 was_moving = m_rotorPosition.GetValue() < 100;
196 int pos = (int)std::trunc(rotor->GetProgress() * 100);
198 is_moving = m_rotorPosition.GetValue() < 100;
199}
200
205{
206 LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- begin");
208 if (GetStreamData())
211 m_streamHandler->SetRetuneAllowed(false, nullptr, nullptr);
212 LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- end");
213}
214
215QStringList DVBSignalMonitor::GetStatusList(void) const
216{
217 QStringList list = DTVSignalMonitor::GetStatusList();
218 m_statusLock.lock();
227 m_statusLock.unlock();
228 return list;
229}
230
232{
233 DTVSignalMonitor::HandlePMT(program_num, pmt);
234
235 if (pmt->ProgramNumber() == (uint)m_programNumber)
236 {
237 DVBChannel *dvbchannel = GetDVBChannel();
238 if (dvbchannel)
239 dvbchannel->SetPMT(pmt);
240 }
241}
242
244{
246 DVBChannel *dvbchannel = GetDVBChannel();
247 if (dvbchannel)
248 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
249}
250
252{
254 DVBChannel *dvbchannel = GetDVBChannel();
255 if (dvbchannel)
256 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
257}
258
260{
261 return dynamic_cast<DVBChannel*>(m_channel);
262}
263
271{
272 if (!m_running || m_exit)
273 return;
274
276 {
278 {
279 m_error = tr("Error: stream handler died");
280 m_updateDone = true;
281 return;
282 }
283
284 // Update signal status for display
285 DVBChannel *dvbchannel = GetDVBChannel();
286 if (dvbchannel)
287 {
288 // Get info from card
289 uint sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
290 uint snr = (uint) (dvbchannel->GetSNR() * 65535);
291
292 // Set SignalMonitorValues from info from card.
293 {
294 QMutexLocker locker(&m_statusLock);
295
300
301 // LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
302 // QString("Update sig:%1 snr:%2").arg(sig).arg(snr));
303 }
304 }
305
306 EmitStatus();
307 if (IsAllGood())
309
310 m_updateDone = true;
311 return;
312 }
313
315
316 DVBChannel *dvbchannel = GetDVBChannel();
317 if (!dvbchannel)
318 return;
319
320 // Handle retuning after rotor has turned
322 {
323 if (dvbchannel->GetRotor())
324 {
326 m_streamHandler->SetRetuneAllowed(true, this, dvbchannel);
328 }
329 else
330 {
332 }
333 }
334
335 bool wasLocked = false;
336 bool isLocked = false;
337 uint sig = 0;
338 uint snr = 0;
339 uint ber = 0;
340 uint ublocks = 0;
341
342 // Get info from card
343 bool has_lock = dvbchannel->HasLock();
345 sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
347 snr = (uint) (dvbchannel->GetSNR() * 65535);
349 ber = (uint) dvbchannel->GetBitErrorRate();
351 ublocks = (uint) dvbchannel->GetUncorrectedBlockCount();
352
353 has_lock |= m_streamHandler->IsRunning();
354
355 // Set SignalMonitorValues from info from card.
356 {
357 QMutexLocker locker(&m_statusLock);
358
359 // BER and UB are actually uint32 values, but we
360 // clamp them at 64K. This is because these values
361 // are actually cumulative, but we don't try to
362 // normalize these to a time period.
363
364 wasLocked = m_signalLock.IsGood();
365 m_signalLock.SetValue((has_lock) ? 1 : 0);
366 isLocked = m_signalLock.IsGood();
367
376 }
377
378 // Signal lock change
379 if (wasLocked != isLocked)
380 {
381 LOG(VB_CHANNEL, LOG_INFO, LOC + "UpdateValues -- Signal " +
382 (isLocked ? "Locked" : "Lost"));
383 }
384
385 EmitStatus();
386 if (IsAllGood())
388
389 // Start table monitoring if we are waiting on any table
390 // and we have a lock.
391 if (isLocked && GetStreamData() &&
396 {
400 }
401
402 m_updateDone = true;
403}
404
409{
410 // Emit signals..
420}
Overall structure.
static bool GetTimeouts(uint inputid, std::chrono::milliseconds &signal_timeout, std::chrono::milliseconds &channel_timeout)
Definition: cardutil.cpp:2288
This class is intended to detect the presence of needed tables.
bool IsAllGood(void) const override
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
void AddFlags(uint64_t _flags) override
void HandleTDT(const TimeDateTable *tdt) override
QStringList GetStatusList(void) const override
Returns QStringList containing all signals and their current values.
void HandleSTT(const SystemTimeTable *stt) override
void RemoveFlags(uint64_t _flags) override
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:31
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
void SetPMT(const ProgramMapTable *pmt)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:729
void SetTimeOffset(double offset)
Tells the Conditional Access Module the offset from the computers utc time to dvb time.
Definition: dvbchannel.cpp:741
double GetUncorrectedBlockCount(bool *ok=nullptr) const
Returns # of uncorrected blocks since last call. First call undefined.
std::chrono::milliseconds GetMinSignalMonitorDelay(void) const
Definition: dvbchannel.h:64
bool HasLock(bool *ok=nullptr) const
Returns true iff we have a signal carrier lock.
double GetBitErrorRate(bool *ok=nullptr) const
Returns # of corrected bits since last call. First call undefined.
double GetSNR(bool *ok=nullptr) const
Returns signal/noise in the range [0..1.0].
double GetSignalStrength(bool *ok=nullptr) const
Returns signal strength in the range [0.0..1.0] (non-calibrated).
QString GetCardNum(void) const
Returns DVB device number, used to construct filenames for DVB devices.
Definition: dvbchannel.h:58
void HandleTDT(const TimeDateTable *tdt) override
void EmitStatus(void) override
Emits signals for lock, signal strength, etc.
void UpdateValues(void) override
Fills in frontend stats and emits status Qt signals.
SignalMonitorValue m_uncorrectedBlocks
~DVBSignalMonitor() override
Stops signal monitoring and table monitoring threads.
DVBChannel * GetDVBChannel(void)
SignalMonitorValue m_bitErrorRate
void Stop(void) override
Stop signal monitoring and table monitoring threads.
void SetRotorTarget(float target) override
Sets rotor target pos from 0.0 to 1.0.
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
SignalMonitorValue m_rotorPosition
QStringList GetStatusList(void) const override
Returns QStringList containing all signals and their current values.
void HandleSTT(const SystemTimeTable *stt) override
DVBStreamHandler * m_streamHandler
void GetRotorStatus(bool &was_moving, bool &is_moving) override
SignalMonitorValue m_signalToNoise
bool IsRetuneAllowed(void) const
void SetRetuneAllowed(bool allow, DTVSignalMonitor *sigmon, DVBChannel *dvbchan)
static void Return(DVBStreamHandler *&ref, int inputid)
static DVBStreamHandler * Get(const QString &devname, int inputid)
Rotor class.
Definition: diseqc.h:303
double GetProgress(void) const
Returns an indication of rotor progress.
Definition: diseqc.cpp:1939
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
static void usleep(std::chrono::microseconds time)
Definition: mthread.cpp:335
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
@ MPEG_PAT_PID
Definition: mpegtables.h:211
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:676
uint ProgramNumber(void) const
Definition: mpegtables.h:712
void SetTimeout(std::chrono::milliseconds _timeout)
void SetThreshold(int _threshold)
void SetRange(int _min, int _max)
Sets the minimum and maximum values.
int GetValue() const
Returns the value.
bool IsGood() const
Returns true if the value is equal to the threshold, or on the right side of the threshold (depends o...
QString GetName(void) const
Returns the long name of this value.
void SetValue(int _value)
QString GetStatus() const
Returns a signal monitor value as one long string.
static const uint64_t kDTVSigMon_WaitForVCT
QRecursiveMutex m_statusLock
volatile bool m_exit
void SendMessageAllGood(void)
SignalMonitorValue m_signalLock
static const uint64_t kDTVSigMon_WaitForNIT
void SendMessage(SignalMonitorMessageType type, const SignalMonitorValue &val)
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
bool HasFlags(uint64_t _flags) const
static const uint64_t kDTVSigMon_WaitForSDT
virtual void Stop()
Stop signal monitoring thread.
volatile bool m_running
ChannelBase * m_channel
static const uint64_t kDTVSigMon_WaitForPMT
virtual void EmitStatus(void)
static const uint64_t kSigMon_WaitForSig
static const uint64_t kDTVSigMon_WaitForPAT
static const uint64_t kDTVSigMon_WaitForMGT
static const uint64_t kDVBSigMon_WaitForUB
Wait for uncorrected FEC blocks to fall below a threshold.
SignalMonitorValue m_signalStrength
std::chrono::milliseconds m_minimumUpdateRate
static const uint64_t kDVBSigMon_WaitForSNR
Wait for the Signal to Noise Ratio to rise above a threshold.
static const uint64_t kDVBSigMon_WaitForBER
Wait for the Bit Error Rate to fall below a threshold.
volatile uint64_t m_flags
bool HasAnyFlag(uint64_t _flags) const
bool IsRunning(void) const
virtual void RemoveListener(MPEGStreamData *data)
virtual void AddListener(MPEGStreamData *data, bool allow_section_reader=false, bool needs_buffering=false, const QString &output_file=QString())
This table contains the GPS time at the time of transmission.
Definition: atsctables.h:688
This table gives the current DVB stream time.
Definition: dvbtables.h:387
#define LOC
unsigned int uint
Definition: freesurround.h:24
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString sm_flags_to_string(uint64_t flags)
@ kStatusBitErrorRate
@ kStatusUncorrectedBlocks
@ kStatusRotorPosition
@ kStatusSignalToNoise
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:95
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:89