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  signalToNoise (QCoreApplication::translate("(Common)",
53  "Signal To Noise"), "snr",
54  0, true, 0, 65535, 0),
55  bitErrorRate (tr("Bit Error Rate"), "ber",
56  65535, false, 0, 65535, 0),
57  uncorrectedBlocks(tr("Uncorrected Blocks"), "ucb",
58  65535, false, 0, 65535, 0),
59  rotorPosition (tr("Rotor Progress"), "pos",
60  100, true, 0, 100, 0),
61  streamHandlerStarted(false),
62  streamHandler(nullptr)
63 {
64  // These two values should probably come from the database...
65  int wait = 3000; // timeout when waiting on signal
66  int threshold = 0; // signal strength threshold
67 
70  m_signalStrength.SetThreshold(threshold);
71 
72  // This is incorrect for API 3.x but works better than int16_t range
73  // in practice, however this is correct for the 4.0 DVB API
74  m_signalStrength.SetRange(0, 65535);
75 
76  uint64_t rmflags = 0;
77 
78 #define DVB_IO(FLAG, METHOD, MSG) \
79  do { if (HasFlags(FLAG)) { bool mok; _channel->METHOD(&mok); \
80  if (!mok) { \
81  LOG(VB_GENERAL, LOG_WARNING, LOC+"Cannot "+(MSG)+ENO); \
82  rmflags |= (FLAG); } \
83  else { \
84  LOG(VB_CHANNEL, LOG_INFO, LOC + "Can " + (MSG)); } } } while (false)
85 
86  DVB_IO(kSigMon_WaitForSig, GetSignalStrength,
87  "measure Signal Strength");
89  "measure S/N");
90  DVB_IO(kDVBSigMon_WaitForBER, GetBitErrorRate,
91  "measure Bit Error Rate");
92  DVB_IO(kDVBSigMon_WaitForUB, GetUncorrectedBlockCount,
93  "count Uncorrected Blocks");
94 
95 #undef DVB_IO
96 
97  RemoveFlags(rmflags);
98 
99  LOG(VB_CHANNEL, LOG_INFO, LOC + "DVBSignalMonitor::ctor " +
100  QString("initial flags %1").arg(sm_flags_to_string(m_flags)));
101 
103  if (m_minimum_update_rate > 30)
105 
107 }
108 
113 {
116 }
117 
118 // documented in dtvsignalmonitor.h
120 {
121  QMutexLocker locker(&m_statusLock);
122  rotorPosition.SetThreshold((int)roundf(100 * target));
123 }
124 
125 void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving)
126 {
127  DVBChannel *dvbchannel = GetDVBChannel();
128  if (!dvbchannel)
129  return;
130 
131  const DiSEqCDevRotor *rotor = dvbchannel->GetRotor();
132  if (!rotor)
133  return;
134 
135  QMutexLocker locker(&m_statusLock);
136  was_moving = rotorPosition.GetValue() < 100;
137  int pos = (int)truncf(rotor->GetProgress() * 100);
138  rotorPosition.SetValue(pos);
139  is_moving = rotorPosition.GetValue() < 100;
140 }
141 
146 {
147  LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- begin");
149  if (GetStreamData())
151  streamHandlerStarted = false;
152  streamHandler->SetRetuneAllowed(false, nullptr, nullptr);
153  LOG(VB_CHANNEL, LOG_INFO, LOC + "Stop() -- end");
154 }
155 
156 QStringList DVBSignalMonitor::GetStatusList(void) const
157 {
158  QStringList list = DTVSignalMonitor::GetStatusList();
159  m_statusLock.lock();
168  m_statusLock.unlock();
169  return list;
170 }
171 
172 void DVBSignalMonitor::HandlePMT(uint program_num, const ProgramMapTable *pmt)
173 {
174  DTVSignalMonitor::HandlePMT(program_num, pmt);
175 
176  if (pmt->ProgramNumber() == (uint)m_programNumber)
177  {
178  DVBChannel *dvbchannel = GetDVBChannel();
179  if (dvbchannel)
180  dvbchannel->SetPMT(pmt);
181  }
182 }
183 
185 {
187  DVBChannel *dvbchannel = GetDVBChannel();
188  if (dvbchannel)
189  dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
190 }
191 
193 {
195  DVBChannel *dvbchannel = GetDVBChannel();
196  if (dvbchannel)
197  dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset());
198 }
199 
201 {
202  return dynamic_cast<DVBChannel*>(m_channel);
203 }
204 
212 {
213  if (!m_running || m_exit)
214  return;
215 
217  {
218  if (!streamHandler->IsRunning())
219  {
220  m_error = tr("Error: stream handler died");
221  m_update_done = true;
222  return;
223  }
224 
225  // Update signal status for display
226  DVBChannel *dvbchannel = GetDVBChannel();
227  if (dvbchannel)
228  {
229  // Get info from card
230  uint sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
231  uint snr = (uint) (dvbchannel->GetSNR() * 65535);
232 
233  // Set SignalMonitorValues from info from card.
234  {
235  QMutexLocker locker(&m_statusLock);
236 
240  signalToNoise.SetValue(snr);
241 
242  // LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
243  // QString("Update sig:%1 snr:%2").arg(sig).arg(snr));
244  }
245  }
246 
247  EmitStatus();
248  if (IsAllGood())
250 
251  m_update_done = true;
252  return;
253  }
254 
256 
257  DVBChannel *dvbchannel = GetDVBChannel();
258  if (!dvbchannel)
259  return;
260 
261  // Handle retuning after rotor has turned
263  {
264  if (dvbchannel->GetRotor())
265  {
267  streamHandler->SetRetuneAllowed(true, this, dvbchannel);
269  }
270  else
272  }
273 
274  bool wasLocked = false, isLocked = false;
275  uint sig = 0, snr = 0, ber = 0, ublocks = 0;
276 
277  // Get info from card
278  bool has_lock = dvbchannel->HasLock();
280  sig = (uint) (dvbchannel->GetSignalStrength() * 65535);
282  snr = (uint) (dvbchannel->GetSNR() * 65535);
284  ber = (uint) dvbchannel->GetBitErrorRate();
286  ublocks = (uint) dvbchannel->GetUncorrectedBlockCount();
287 
288  has_lock |= streamHandler->IsRunning();
289 
290  // Set SignalMonitorValues from info from card.
291  {
292  QMutexLocker locker(&m_statusLock);
293 
294  // BER and UB are actually uint32 values, but we
295  // clamp them at 64K. This is because these values
296  // are actually cumulative, but we don't try to
297  // normalize these to a time period.
298 
299  wasLocked = m_signalLock.IsGood();
300  m_signalLock.SetValue((has_lock) ? 1 : 0);
301  isLocked = m_signalLock.IsGood();
302 
306  signalToNoise.SetValue(snr);
308  bitErrorRate.SetValue(ber);
310  uncorrectedBlocks.SetValue(ublocks);
311  }
312 
313  // Debug output
314  if (wasLocked != isLocked)
315  {
316  LOG(VB_CHANNEL, LOG_INFO, LOC + "UpdateValues -- Signal " +
317  (isLocked ? "Locked" : "Lost"));
318  }
319 
320  EmitStatus();
321  if (IsAllGood())
323 
324  // Start table monitoring if we are waiting on any table
325  // and we have a lock.
326  if (isLocked && GetStreamData() &&
331  {
333  streamHandler->AddListener(GetStreamData(), true, false);
334  streamHandlerStarted = true;
335  }
336 
337  m_update_done = true;
338 }
339 
344 {
345  // Emit signals..
355 }
double GetSignalStrength(bool *ok=nullptr) const
Returns signal strength in the range [0.0..1.0] (non-calibrated).
void HandlePMT(uint, const ProgramMapTable *) override
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 SetRetuneAllowed(bool allow, DTVSignalMonitor *sigmon, DVBChannel *dvbchan)
DVBChannel * GetDVBChannel(void)
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
QStringList GetStatusList(void) const override
Returns QStringList containing all signals and their current values.
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.
DVBStreamHandler * streamHandler
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
void HandleTDT(const TimeDateTable *) override
bool HasAnyFlag(uint64_t _flags) const
void SetPMT(const ProgramMapTable *)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:494
virtual void RemoveListener(MPEGStreamData *data)
This table gives the current DVB stream time.
Definition: dvbtables.h:373
unsigned int uint
Definition: compat.h:140
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)
QString sm_flags_to_string(uint64_t)
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
void HandlePMT(uint, const ProgramMapTable *) override
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:506
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.
SignalMonitorValue bitErrorRate
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:1977
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
SignalMonitorValue rotorPosition
Rotor class.
Definition: diseqc.h:293
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
void SendMessageAllGood(void)
volatile bool m_running
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.
void HandleSTT(const SystemTimeTable *) override
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
void HandleSTT(const SystemTimeTable *) override
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.
void HandleTDT(const TimeDateTable *) override
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
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:693
#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
SignalMonitorValue uncorrectedBlocks
virtual ~DVBSignalMonitor()
Stops signal monitoring and table monitoring threads.
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:683
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:656
SignalMonitorValue m_signalLock
uint m_minimum_update_rate
bool IsRunning(void) const
void GetRotorStatus(bool &was_moving, bool &is_moving) override
virtual void EmitStatus(void)
SignalMonitorValue signalToNoise
#define DVB_IO(FLAG, METHOD, MSG)
bool HasFlags(uint64_t _flags) const