MythTV  master
dvbsignalmonitor.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 #include <cerrno>
4 #include <cstring>
5 #include <cmath>
6 
7 #include <unistd.h>
8 
9 //Qt headers
10 #include <QCoreApplication>
11 
12 // MythTV headers
13 #include "mythcontext.h"
14 #include "mythdbcon.h"
15 #include "dvbsignalmonitor.h"
16 #include "dvbchannel.h"
17 #include "dvbstreamdata.h"
18 #include "atscstreamdata.h"
19 #include "mpegtables.h"
20 #include "atsctables.h"
21 #include "cardutil.h"
22 
23 #include "dvbtypes.h"
24 #include "dvbchannel.h"
25 #include "dvbrecorder.h"
26 #include "dvbstreamhandler.h"
27 
28 #define LOC QString("DVBSigMon[%1](%2): ") \
29  .arg(m_inputid).arg(m_channel->GetDevice())
30 
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, 0),
55  m_bitErrorRate (tr("Bit Error Rate"), "ber",
56  65535, false, 0, 65535, 0),
57  m_uncorrectedBlocks(tr("Uncorrected Blocks"), "ucb",
58  65535, false, 0, 65535, 0),
59  m_rotorPosition (tr("Rotor Progress"), "pos",
60  100, true, 0, 100, 0),
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 3000 ms
68  uint wait = 3000; // Minimum timeout time
69  uint signal_timeout = 0; // Not used
70  uint tuning_timeout = 0; // 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).arg(wait));
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));
83  }
84 
87  m_signalStrength.SetThreshold(threshold);
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  uint64_t rmflags = 0;
94 
95 #define DVB_IO(FLAG, METHOD, MSG) \
96  do { if (HasFlags(FLAG)) { bool mok; _channel->METHOD(&mok); \
97  if (!mok) { \
98  LOG(VB_GENERAL, LOG_WARNING, LOC+"Cannot "+(MSG)+ENO); \
99  rmflags |= (FLAG); } \
100  else { \
101  LOG(VB_CHANNEL, LOG_INFO, LOC + "Can " + (MSG)); } } } while (false)
102 
103  DVB_IO(kSigMon_WaitForSig, GetSignalStrength,
104  "measure Signal Strength");
106  "measure S/N");
107  DVB_IO(kDVBSigMon_WaitForBER, GetBitErrorRate,
108  "measure Bit Error Rate");
109  DVB_IO(kDVBSigMon_WaitForUB, GetUncorrectedBlockCount,
110  "count Uncorrected Blocks");
111 
112 #undef DVB_IO
113 
114  RemoveFlags(rmflags);
115 
116  LOG(VB_CHANNEL, LOG_INFO, LOC + "DVBSignalMonitor::ctor " +
117  QString("initial flags %1").arg(sm_flags_to_string(m_flags)));
118 
120  if (m_minimum_update_rate > 30)
122 
124 }
125 
130 {
133 }
134 
135 // documented in dtvsignalmonitor.h
137 {
138  QMutexLocker locker(&m_statusLock);
139  m_rotorPosition.SetThreshold((int)roundf(100 * target));
140 }
141 
142 void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving)
143 {
144  DVBChannel *dvbchannel = GetDVBChannel();
145  if (!dvbchannel)
146  return;
147 
148  const DiSEqCDevRotor *rotor = dvbchannel->GetRotor();
149  if (!rotor)
150  return;
151 
152  QMutexLocker locker(&m_statusLock);
153  was_moving = m_rotorPosition.GetValue() < 100;
154  int pos = (int)truncf(rotor->GetProgress() * 100);
156  is_moving = m_rotorPosition.GetValue() < 100;
157 }
158 
163 {
164  LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- begin");
166  if (GetStreamData())
168  m_streamHandlerStarted = false;
169  m_streamHandler->SetRetuneAllowed(false, nullptr, nullptr);
170  LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- end");
171 }
172 
173 QStringList DVBSignalMonitor::GetStatusList(void) const
174 {
175  QStringList list = DTVSignalMonitor::GetStatusList();
176  m_statusLock.lock();
185  m_statusLock.unlock();
186  return list;
187 }
188 
189 void DVBSignalMonitor::HandlePMT(uint program_num, const ProgramMapTable *pmt)
190 {
191  DTVSignalMonitor::HandlePMT(program_num, pmt);
192 
193  if (pmt->ProgramNumber() == (uint)m_programNumber)
194  {
195  DVBChannel *dvbchannel = GetDVBChannel();
196  if (dvbchannel)
197  dvbchannel->SetPMT(pmt);
198  }
199 }
200 
202 {
204  DVBChannel *dvbchannel = GetDVBChannel();
205  if (dvbchannel)
206  dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
207 }
208 
210 {
212  DVBChannel *dvbchannel = GetDVBChannel();
213  if (dvbchannel)
214  dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
215 }
216 
218 {
219  return dynamic_cast<DVBChannel*>(m_channel);
220 }
221 
229 {
230  if (!m_running || m_exit)
231  return;
232 
234  {
235  if (!m_streamHandler->IsRunning())
236  {
237  m_error = tr("Error: stream handler died");
238  m_update_done = true;
239  return;
240  }
241 
242  // Update signal status for display
243  DVBChannel *dvbchannel = GetDVBChannel();
244  if (dvbchannel)
245  {
246  // Get info from card
247  uint sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
248  uint snr = (uint) (dvbchannel->GetSNR() * 65535);
249 
250  // Set SignalMonitorValues from info from card.
251  {
252  QMutexLocker locker(&m_statusLock);
253 
258 
259  // LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
260  // QString("Update sig:%1 snr:%2").arg(sig).arg(snr));
261  }
262  }
263 
264  EmitStatus();
265  if (IsAllGood())
267 
268  m_update_done = true;
269  return;
270  }
271 
273 
274  DVBChannel *dvbchannel = GetDVBChannel();
275  if (!dvbchannel)
276  return;
277 
278  // Handle retuning after rotor has turned
280  {
281  if (dvbchannel->GetRotor())
282  {
284  m_streamHandler->SetRetuneAllowed(true, this, dvbchannel);
286  }
287  else
289  }
290 
291  bool wasLocked = false;
292  bool isLocked = false;
293  uint sig = 0;
294  uint snr = 0;
295  uint ber = 0;
296  uint ublocks = 0;
297 
298  // Get info from card
299  bool has_lock = dvbchannel->HasLock();
301  sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
303  snr = (uint) (dvbchannel->GetSNR() * 65535);
305  ber = (uint) dvbchannel->GetBitErrorRate();
307  ublocks = (uint) dvbchannel->GetUncorrectedBlockCount();
308 
309  has_lock |= m_streamHandler->IsRunning();
310 
311  // Set SignalMonitorValues from info from card.
312  {
313  QMutexLocker locker(&m_statusLock);
314 
315  // BER and UB are actually uint32 values, but we
316  // clamp them at 64K. This is because these values
317  // are actually cumulative, but we don't try to
318  // normalize these to a time period.
319 
320  wasLocked = m_signalLock.IsGood();
321  m_signalLock.SetValue((has_lock) ? 1 : 0);
322  isLocked = m_signalLock.IsGood();
323 
331  m_uncorrectedBlocks.SetValue(ublocks);
332  }
333 
334  // Debug output
335  if (wasLocked != isLocked)
336  {
337  LOG(VB_CHANNEL, LOG_INFO, LOC + "UpdateValues -- Signal " +
338  (isLocked ? "Locked" : "Lost"));
339  }
340 
341  EmitStatus();
342  if (IsAllGood())
344 
345  // Start table monitoring if we are waiting on any table
346  // and we have a lock.
347  if (isLocked && GetStreamData() &&
352  {
354  m_streamHandler->AddListener(GetStreamData(), true, false);
355  m_streamHandlerStarted = true;
356  }
357 
358  m_update_done = true;
359 }
360 
365 {
366  // Emit signals..
376 }
double GetSignalStrength(bool *ok=nullptr) const
Returns signal strength in the range [0.0..1.0] (non-calibrated).
QString GetStatus() const
Returns a signal monitor value as one long string.
double GetBitErrorRate(bool *ok=nullptr) const
Returns # of corrected bits since last call. First call undefined.
QMutex m_statusLock
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
void SetRetuneAllowed(bool allow, DTVSignalMonitor *sigmon, DVBChannel *dvbchan)
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
DVBChannel * GetDVBChannel(void)
QStringList GetStatusList(void) const override
Returns QStringList containing all signals and their current values.
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
QString GetName(void) const
Returns the long name of this value.
void Stop(void) override
Stop signal monitoring and table monitoring threads.
static const uint64_t kDTVSigMon_WaitForPMT
static const uint64_t kDVBSigMon_WaitForBER
Wait for the Bit Error Rate to fall below a threshold.
static const uint64_t kDTVSigMon_WaitForPAT
void SetTimeout(int _timeout)
int GetValue() const
Returns the value.
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
bool HasAnyFlag(uint64_t _flags) const
virtual void RemoveListener(MPEGStreamData *data)
This table gives the current DVB stream time.
Definition: dvbtables.h:373
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:29
static const uint64_t kDTVSigMon_WaitForVCT
static const uint64_t kDTVSigMon_WaitForMGT
void SendMessage(SignalMonitorMessageType type, const SignalMonitorValue &val)
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
Definition: dvbchannel.cpp:999
void SetValue(int _value)
static const uint64_t kDTVSigMon_WaitForNIT
static bool GetTimeouts(uint inputid, uint &signal_timeout, uint &channel_timeout)
Definition: cardutil.cpp:2090
Overall structure.
static void Return(DVBStreamHandler *&ref, int inputid)
void SetTimeOffset(double offset)
Tells the Conditional Access Module the offset from the computers utc time to dvb time.
Definition: dvbchannel.cpp:507
static DVBStreamHandler * Get(const QString &devname, int inputid)
void RemoveFlags(uint64_t _flags) override
double GetUncorrectedBlockCount(bool *ok=nullptr) const
Returns # of uncorrected blocks since last call. First call undefined.
virtual void Stop()
Stop signal monitoring thread.
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
static const uint64_t kSigMon_WaitForSig
double GetProgress(void) const
Returns an indication of rotor progress.
Definition: diseqc.cpp:1964
bool HasLock(bool *ok=nullptr) const
Returns true iff we have a signal carrier lock.
virtual void AddListener(MPEGStreamData *data, bool allow_section_reader=false, bool needs_buffering=false, QString output_file=QString())
ChannelBase * m_channel
volatile bool m_exit
Rotor class.
Definition: diseqc.h:295
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
void SetPMT(const ProgramMapTable *pmt)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:495
unsigned int uint
Definition: compat.h:140
void SendMessageAllGood(void)
SignalMonitorValue m_signalToNoise
volatile bool m_running
SignalMonitorValue m_uncorrectedBlocks
uint GetMinSignalMonitorDelay(void) const
Definition: dvbchannel.h:63
void SetRotorTarget(float target) override
Sets rotor target pos from 0.0 to 1.0.
void UpdateValues(void) override
Fills in frontend stats and emits status Qt signals.
SignalMonitorValue m_bitErrorRate
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
QStringList GetStatusList(void) const override
Returns QStringList containing all signals and their current values.
This class is intended to detect the presence of needed tables.
QString sm_flags_to_string(uint64_t flags)
void AddFlags(uint64_t _flags) override
QString GetCardNum(void) const
Returns DVB device number, used to construct filenames for DVB devices.
Definition: dvbchannel.h:57
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
~DVBSignalMonitor() override
Stops signal monitoring and table monitoring threads.
bool IsRetuneAllowed(void) const
bool IsAllGood(void) const override
SignalMonitorValue m_signalStrength
void SetRange(int _min, int _max)
Sets the minimum and maximum values.
volatile uint64_t m_flags
uint ProgramNumber(void) const
Definition: mpegtables.h:703
#define LOC
double GetSNR(bool *ok=nullptr) const
Returns signal/noise in the range [0..1.0].
void EmitStatus(void) override
Emits signals for lock, signal strength, etc.
static const uint64_t kDTVSigMon_WaitForSDT
void HandleTDT(const TimeDateTable *tdt) override
void HandleTDT(const TimeDateTable *tdt) override
DVBStreamHandler * m_streamHandler
SignalMonitorValue m_rotorPosition
static void usleep(unsigned long time)
Definition: mthread.cpp:348
bool IsGood() const
Returns true if the value is equal to the threshold, or on the right side of the threshold (depends o...
void SetThreshold(int _threshold)
This table contains the GPS time at the time of transmission.
Definition: atsctables.h:682
static const uint64_t kDVBSigMon_WaitForUB
Wait for uncorrected FEC blocks to fall below a threshold.
static const uint64_t kDVBSigMon_WaitForSNR
Wait for the Signal to Noise Ratio to rise above a threshold.
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:666
SignalMonitorValue m_signalLock
uint m_minimum_update_rate
bool IsRunning(void) const
void HandleSTT(const SystemTimeTable *stt) override
void GetRotorStatus(bool &was_moving, bool &is_moving) override
void HandleSTT(const SystemTimeTable *stt) override
virtual void EmitStatus(void)
#define DVB_IO(FLAG, METHOD, MSG)
bool HasFlags(uint64_t _flags) const