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#include <thread>
7
8//Qt headers
9#include <QCoreApplication>
10
11// MythTV headers
14
15#include "cardutil.h"
16#include "dvbchannel.h"
17#include "dvbrecorder.h"
18#include "dvbsignalmonitor.h"
19#include "dvbstreamhandler.h"
20#include "dvbtypes.h"
21#include "mpeg/atscstreamdata.h"
22#include "mpeg/atsctables.h"
23#include "mpeg/dvbstreamdata.h"
24#include "mpeg/mpegtables.h"
25
26#define LOC QString("DVBSigMon[%1](%2): ") \
27 .arg(m_inputid).arg(m_channel->GetDevice())
28
45 bool _release_stream,
46 uint64_t _flags)
47 : DTVSignalMonitor(db_cardnum, _channel, _release_stream, _flags),
48 // This snr setup is incorrect for API 3.x but works better
49 // than int16_t range in practice, however this is correct
50 // for the 4.0 DVB API which uses a uint16_t for the snr
51 m_signalToNoise (QCoreApplication::translate("(Common)",
52 "Signal To Noise"), "snr",
53 0, true, 0, 65535, 0ms),
54 m_bitErrorRate (tr("Bit Error Rate"), "ber",
55 65535, false, 0, 65535, 0ms),
56 m_uncorrectedBlocks(tr("Uncorrected Blocks"), "ucb",
57 65535, false, 0, 65535, 0ms),
58 m_rotorPosition (tr("Rotor Progress"), "pos",
59 100, true, 0, 100, 0ms),
60 m_streamHandlerStarted(false),
61 m_streamHandler(nullptr)
62{
63 // This value should probably come from the database...
64 int threshold = 0; // signal strength threshold
65
66 // Tuning timeout time for channel lock from database, minimum is 3s
67 std::chrono::milliseconds wait = 3s; // Minimum timeout time
68 std::chrono::milliseconds signal_timeout = 0ms; // Not used
69 std::chrono::milliseconds tuning_timeout = 0ms; // Maximum time for channel lock from card
70 CardUtil::GetTimeouts(db_cardnum, signal_timeout, tuning_timeout);
71 if (tuning_timeout < wait)
72 {
73 LOG(VB_CHANNEL, LOG_DEBUG, LOC +
74 QString("Tuning timeout from database: %1 ms is too small, using %2 ms")
75 .arg(tuning_timeout.count()).arg(wait.count()));
76 }
77 else
78 {
79 wait = tuning_timeout; // Use value from database
80 LOG(VB_CHANNEL, LOG_DEBUG, LOC +
81 QString("Tuning timeout: %1 ms").arg(wait.count()));
82 }
83
87
88 // This is incorrect for API 3.x but works better than int16_t range
89 // in practice, however this is correct for the 4.0 DVB API
90 m_signalStrength.SetRange(0, 65535);
91
92 // Determine the signal monitoring capabilities from the card and
93 // do not use the capabilities that are not present.
94 uint64_t rmflags = 0;
95 bool mok = false;
96
97 auto log_message = [&mok](const QString& loc, const QString& msg)
98 {
99 if (mok)
100 LOG(VB_CHANNEL, LOG_INFO, loc + "Can " + msg);
101 else
102 LOG(VB_GENERAL, LOG_WARNING, loc + "Cannot " + msg + ENO);
103 };
104
105 auto log_message_channel = [&mok](const QString& loc, const QString& msg)
106 {
107 if (mok)
108 LOG(VB_CHANNEL, LOG_INFO, loc + "Can " + msg);
109 else
110 LOG(VB_CHANNEL, LOG_WARNING, loc + "Cannot " + msg + ENO);
111 };
112
113 auto update_rmflags = [&mok, &rmflags](uint64_t flag)
114 {
115 if (!mok)
116 rmflags |= flag;
117 };
118
119 // Signal strength
120 auto flag = kSigMon_WaitForSig;
121 if (HasFlags(flag))
122 {
123 _channel->GetSignalStrength(&mok);
124 update_rmflags(flag);
125 log_message(LOC, "measure Signal Strength");
126 }
127
128 // Signal/Noise ratio
130 if (HasFlags(flag))
131 {
132 _channel->GetSNR(&mok);
133 update_rmflags(flag);
134 log_message(LOC, "measure S/N");
135 }
136
137 // Bit error rate
139 if (HasFlags(flag))
140 {
141 _channel->GetBitErrorRate(&mok);
142 update_rmflags(flag);
143 log_message_channel(LOC, "measure Bit Error Rate");
144 }
145
146 // Uncorrected block count
148 if (HasFlags(flag))
149 {
150 _channel->GetUncorrectedBlockCount(&mok);
151 update_rmflags(flag);
152 log_message_channel(LOC, "count Uncorrected Blocks");
153 }
154
155 RemoveFlags(rmflags);
156
157 LOG(VB_CHANNEL, LOG_INFO, LOC + "DVBSignalMonitor::ctor " +
158 QString("initial flags %1").arg(sm_flags_to_string(m_flags)));
159
161 if (m_minimumUpdateRate > 30ms)
162 std::this_thread::sleep_for(m_minimumUpdateRate);
163
165}
166
171{
174}
175
176// documented in dtvsignalmonitor.h
178{
179 QMutexLocker locker(&m_statusLock);
180 m_rotorPosition.SetThreshold((int)roundf(100 * target));
181}
182
183void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving)
184{
185 DVBChannel *dvbchannel = GetDVBChannel();
186 if (!dvbchannel)
187 return;
188
189 const DiSEqCDevRotor *rotor = dvbchannel->GetRotor();
190 if (!rotor)
191 return;
192
193 QMutexLocker locker(&m_statusLock);
194 was_moving = m_rotorPosition.GetValue() < 100;
195 int pos = (int)std::trunc(rotor->GetProgress() * 100);
197 is_moving = m_rotorPosition.GetValue() < 100;
198}
199
204{
205 LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- begin");
207 if (GetStreamData())
210 m_streamHandler->SetRetuneAllowed(false, nullptr, nullptr);
211 LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- end");
212}
213
214QStringList DVBSignalMonitor::GetStatusList(void) const
215{
216 QStringList list = DTVSignalMonitor::GetStatusList();
217 m_statusLock.lock();
226 m_statusLock.unlock();
227 return list;
228}
229
231{
232 DTVSignalMonitor::HandlePMT(program_num, pmt);
233
234 if (pmt->ProgramNumber() == (uint)m_programNumber)
235 {
236 DVBChannel *dvbchannel = GetDVBChannel();
237 if (dvbchannel)
238 dvbchannel->SetPMT(pmt);
239 }
240}
241
243{
245 DVBChannel *dvbchannel = GetDVBChannel();
246 if (dvbchannel)
247 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
248}
249
251{
253 DVBChannel *dvbchannel = GetDVBChannel();
254 if (dvbchannel)
255 dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
256}
257
259{
260 return dynamic_cast<DVBChannel*>(m_channel);
261}
262
270{
271 if (!m_running || m_exit)
272 return;
273
275 {
277 {
278 m_error = tr("Error: stream handler died");
279 m_updateDone = true;
280 return;
281 }
282
283 // Update signal status for display
284 DVBChannel *dvbchannel = GetDVBChannel();
285 if (dvbchannel)
286 {
287 // Get info from card
288 uint sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
289 uint snr = (uint) (dvbchannel->GetSNR() * 65535);
290
291 // Set SignalMonitorValues from info from card.
292 {
293 QMutexLocker locker(&m_statusLock);
294
299
300 // LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
301 // QString("Update sig:%1 snr:%2").arg(sig).arg(snr));
302 }
303 }
304
305 EmitStatus();
306 if (IsAllGood())
308
309 m_updateDone = true;
310 return;
311 }
312
314
315 DVBChannel *dvbchannel = GetDVBChannel();
316 if (!dvbchannel)
317 return;
318
319 // Handle retuning after rotor has turned
321 {
322 if (dvbchannel->GetRotor())
323 {
325 m_streamHandler->SetRetuneAllowed(true, this, dvbchannel);
327 }
328 else
329 {
331 }
332 }
333
334 bool wasLocked = false;
335 bool isLocked = false;
336 uint sig = 0;
337 uint snr = 0;
338 uint ber = 0;
339 uint ublocks = 0;
340
341 // Get info from card
342 bool has_lock = dvbchannel->HasLock();
344 sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
346 snr = (uint) (dvbchannel->GetSNR() * 65535);
348 ber = (uint) dvbchannel->GetBitErrorRate();
350 ublocks = (uint) dvbchannel->GetUncorrectedBlockCount();
351
352 has_lock |= m_streamHandler->IsRunning();
353
354 // Set SignalMonitorValues from info from card.
355 {
356 QMutexLocker locker(&m_statusLock);
357
358 // BER and UB are actually uint32 values, but we
359 // clamp them at 64K. This is because these values
360 // are actually cumulative, but we don't try to
361 // normalize these to a time period.
362
363 wasLocked = m_signalLock.IsGood();
364 m_signalLock.SetValue((has_lock) ? 1 : 0);
365 isLocked = m_signalLock.IsGood();
366
375 }
376
377 // Signal lock change
378 if (wasLocked != isLocked)
379 {
380 LOG(VB_CHANNEL, LOG_INFO, LOC + "UpdateValues -- Signal " +
381 (isLocked ? "Locked" : "Lost"));
382 }
383
384 EmitStatus();
385 if (IsAllGood())
387
388 // Start table monitoring if we are waiting on any table
389 // and we have a lock.
390 if (isLocked && GetStreamData() &&
395 {
399 }
400
401 m_updateDone = true;
402}
403
408{
409 // Emit signals..
419}
Overall structure.
static bool GetTimeouts(uint inputid, std::chrono::milliseconds &signal_timeout, std::chrono::milliseconds &channel_timeout)
Definition: cardutil.cpp:2294
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:726
void SetTimeOffset(double offset)
Tells the Conditional Access Module the offset from the computers utc time to dvb time.
Definition: dvbchannel.cpp:738
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:1941
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:298
@ 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:686
This table gives the current DVB stream time.
Definition: dvbtables.h:387
unsigned int uint
Definition: compat.h:60
#define LOC
#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:86
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:80