summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2011-06-02 13:28:42 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2011-06-02 13:28:42 +0200
commite572cbda47df902ae7d83313fd01483ce2d3193f (patch)
tree55a020216bff73ad3541089eabdd331f81ff5520
parent40278ec12131f07fdc15556511f689455e2b7931 (diff)
downloadvdr-e572cbda47df902ae7d83313fd01483ce2d3193f.tar.gz
vdr-e572cbda47df902ae7d83313fd01483ce2d3193f.tar.bz2
Implemented signal strength and quality handling
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY10
-rw-r--r--PLUGINS/src/dvbsddevice/dvbsdffdevice.c19
-rw-r--r--device.c12
-rw-r--r--device.h12
-rw-r--r--dvbdevice.c175
-rw-r--r--dvbdevice.h5
-rw-r--r--skinsttng.c40
8 files changed, 235 insertions, 39 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index bc5b0b47..d128222b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1104,6 +1104,7 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
for adding support for "registration descriptor" to 'libsi' and using it in pat.c
for adding an include of VDR's 'Make.global' to libsi's Makefile
for adding handling of "ANSI/SCTE 57" descriptors
+ for some input on how to use BER and UNC values to generate a "quality" value
Ralf Klueber <ralf.klueber@vodafone.com>
for reporting a bug in cutting a recording if there is only a single editing mark
diff --git a/HISTORY b/HISTORY
index 3dbbb38c..4b091020 100644
--- a/HISTORY
+++ b/HISTORY
@@ -6607,7 +6607,7 @@ Video Disk Recorder Revision History
- Avoiding an unecessary call to Recordings.ResetResume() (thanks to Reinhard
Nissl).
-2011-05-22: Version 1.7.19
+2011-06-02: Version 1.7.19
- Fixed cString's operator=(const char *String) in case the given string is the
same as the existing one (thanks to Dirk Leber).
@@ -6624,3 +6624,11 @@ Video Disk Recorder Revision History
- Fixed a possible race condition in cDiseqc::Execute() (reported by Marco Göbenich).
The return value of cDiseqcs::Get() is now const, so plugin authors may need to
adjust their code if they use this function.
+- The new functions cDevice::SignalStrength() and cDevice::SignalQuality() can be
+ used to determine the signal strength and quality of a given device (thanks to
+ Rolf Ahrenberg for some input on how to use BER and UNC values to generate a
+ "quality" value).
+- The 'sttng' skin now displays two colored bars at the bottom of the channel display,
+ indicating the strength (upper bar) and quality (lower bar) of the received signal.
+ The number to the left of these bars indicates the actual device the current
+ channel is being received with.
diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
index cad7d311..73e55bac 100644
--- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
+++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: dvbsdffdevice.c 2.28 2011/05/21 13:24:35 kls Exp $
+ * $Id: dvbsdffdevice.c 2.29 2011/05/22 15:22:14 kls Exp $
*/
#include "dvbsdffdevice.h"
@@ -777,22 +777,7 @@ bool cDvbSdFfDeviceProbe::Probe(int Adapter, int Frontend)
0x13C21002, // Technotrend/Hauppauge WinTV DVB-S rev1.3 SE
0x00000000
};
- cString FileName;
- cReadLine ReadLine;
- FILE *f = NULL;
- uint32_t SubsystemId = 0;
- FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
- if ((f = fopen(FileName, "r")) != NULL) {
- if (char *s = ReadLine.Read(f))
- SubsystemId = strtoul(s, NULL, 0) << 16;
- fclose(f);
- }
- FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
- if ((f = fopen(FileName, "r")) != NULL) {
- if (char *s = ReadLine.Read(f))
- SubsystemId |= strtoul(s, NULL, 0);
- fclose(f);
- }
+ uint32_t SubsystemId = GetSubsystemId(Adapter, Frontend);
for (uint32_t *sid = SubsystemIds; *sid; sid++) {
if (*sid == SubsystemId) {
dsyslog("creating cDvbSdFfDevice");
diff --git a/device.c b/device.c
index 854ee677..07599936 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 2.40 2011/05/22 09:42:57 kls Exp $
+ * $Id: device.c 2.41 2011/06/02 13:14:16 kls Exp $
*/
#include "device.h"
@@ -618,6 +618,16 @@ int cDevice::NumProvidedSystems(void) const
return 0;
}
+int cDevice::SignalStrength(void) const
+{
+ return -1;
+}
+
+int cDevice::SignalQuality(void) const
+{
+ return -1;
+}
+
const cChannel *cDevice::GetCurrentlyTunedTransponder(void) const
{
return NULL;
diff --git a/device.h b/device.h
index 14036c61..d937e5f0 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 2.25 2011/05/21 12:54:43 kls Exp $
+ * $Id: device.h 2.26 2011/06/02 13:15:31 kls Exp $
*/
#ifndef __DEVICE_H
@@ -253,6 +253,16 @@ public:
///< actually provide channels must implement this function.
///< The result of this function is used when selecting a device, in order
///< to avoid devices that provide more than one system.
+ virtual int SignalStrength(void) const;
+ ///< Returns the "strength" of the currently received signal.
+ ///< This is a value in the range 0 (no signal at all) through
+ ///< 100 (best possible signal). A value of -1 indicates that this
+ ///< device has no concept of a "signal strength".
+ virtual int SignalQuality(void) const;
+ ///< Returns the "quality" of the currently received signal.
+ ///< This is a value in the range 0 (worst quality) through
+ ///< 100 (best possible quality). A value of -1 indicates that this
+ ///< device has no concept of a "signal quality".
virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
///< Returns a pointer to the currently tuned transponder.
///< This is not one of the channels in the global cChannels list, but rather
diff --git a/dvbdevice.c b/dvbdevice.c
index 0d882b15..7ce31ce2 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 2.39 2011/05/22 10:34:49 kls Exp $
+ * $Id: dvbdevice.c 2.40 2011/06/02 13:28:42 kls Exp $
*/
#include "dvbdevice.h"
@@ -253,12 +253,15 @@ bool cDvbTransponderParameters::Parse(const char *s)
// --- cDvbTuner -------------------------------------------------------------
+#define TUNER_POLL_TIMEOUT 10 // ms
+
class cDvbTuner : public cThread {
private:
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
int device;
int fd_frontend;
int adapter, frontend;
+ uint32_t subsystemId;
int tuneTimeout;
int lockTimeout;
time_t lastTimeoutReport;
@@ -269,16 +272,20 @@ private:
cMutex mutex;
cCondVar locked;
cCondVar newSet;
- bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0);
+ void ClearEventQueue(void) const;
+ bool GetFrontendStatus(fe_status_t &Status) const;
bool SetFrontend(void);
virtual void Action(void);
public:
cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
virtual ~cDvbTuner();
const cChannel *GetTransponder(void) const { return &channel; }
+ uint32_t SubsystemId(void) const { return subsystemId; }
bool IsTunedTo(const cChannel *Channel) const;
void Set(const cChannel *Channel);
bool Locked(int TimeoutMs = 0);
+ int GetSignalStrength(void) const;
+ int GetSignalQuality(void) const;
};
cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
@@ -288,6 +295,7 @@ cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_
adapter = Adapter;
frontend = Frontend;
frontendType = FrontendType;
+ subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, frontend);
tuneTimeout = 0;
lockTimeout = 0;
lastTimeoutReport = 0;
@@ -339,16 +347,19 @@ bool cDvbTuner::Locked(int TimeoutMs)
return tunerStatus >= tsLocked;
}
-bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs)
+void cDvbTuner::ClearEventQueue(void) const
{
- if (TimeoutMs) {
- cPoller Poller(fd_frontend);
- if (Poller.Poll(TimeoutMs)) {
- dvb_frontend_event Event;
- while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
- ; // just to clear the event queue - we'll read the actual status below
- }
+ cPoller Poller(fd_frontend);
+ if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
+ dvb_frontend_event Event;
+ while (ioctl(fd_frontend, FE_GET_EVENT, &Event) == 0)
+ ; // just to clear the event queue - we'll read the actual status below
}
+}
+
+bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
+{
+ ClearEventQueue();
while (1) {
if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
return true;
@@ -358,6 +369,104 @@ bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs)
return false;
}
+//#define DEBUG_SIGNALSTRENGTH
+//#define DEBUG_SIGNALQUALITY
+
+int cDvbTuner::GetSignalStrength(void) const
+{
+ ClearEventQueue();
+ uint16_t Signal;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
+ break;
+ if (errno != EINTR)
+ return -1;
+ }
+ uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
+ // Use the subsystemId to identify individual devices in case they need
+ // special treatment to map their Signal value into the range 0...0xFFFF.
+ int s = int(Signal) * 100 / MaxSignal;
+ if (s > 100)
+ s = 100;
+#ifdef DEBUG_SIGNALSTRENGTH
+ fprintf(stderr, "FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
+#endif
+ return s;
+}
+
+#define LOCK_THRESHOLD 10
+
+int cDvbTuner::GetSignalQuality(void) const
+{
+ fe_status_t Status;
+ if (GetFrontendStatus(Status)) {
+ if ((Status & FE_HAS_SIGNAL) == 0)
+ return 0;
+ if ((Status & FE_HAS_CARRIER) == 0)
+ return LOCK_THRESHOLD / 4;
+ if ((Status & FE_HAS_VITERBI) == 0)
+ return LOCK_THRESHOLD / 3;
+ if ((Status & FE_HAS_SYNC) == 0)
+ return LOCK_THRESHOLD / 2;
+ if ((Status & FE_HAS_LOCK) == 0)
+ return LOCK_THRESHOLD;
+ bool HasSnr = true;
+ uint16_t Snr;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
+ break;
+ if (errno == EOPNOTSUPP) {
+ Snr = 0xFFFF;
+ HasSnr = false;
+ break;
+ }
+ if (errno != EINTR)
+ return -1;
+ }
+ bool HasBer = true;
+ uint32_t Ber;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
+ break;
+ if (errno == EOPNOTSUPP) {
+ Ber = 0;
+ HasBer = false;
+ break;
+ }
+ if (errno != EINTR)
+ return -1;
+ }
+ bool HasUnc = true;
+ uint32_t Unc;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
+ break;
+ if (errno == EOPNOTSUPP) {
+ Unc = 0;
+ HasUnc = false;
+ break;
+ }
+ if (errno != EINTR)
+ return -1;
+ }
+ uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
+ // Use the subsystemId to identify individual devices in case they need
+ // special treatment to map their Snr value into the range 0...0xFFFF.
+ int a = int(Snr) * 100 / MaxSnr;
+ int b = 100 - (Unc * 10 + (Ber / 256) * 5);
+ if (b < 0)
+ b = 0;
+ int q = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
+ if (q > 100)
+ q = 100;
+#ifdef DEBUG_SIGNALQUALITY
+ fprintf(stderr, "FE %d/%d: %08X Q = %04X %04X %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
+#endif
+ return q;
+ }
+ return -1;
+}
+
static unsigned int FrequencyToHz(unsigned int f)
{
while (f && f < 1000000)
@@ -504,9 +613,9 @@ bool cDvbTuner::SetFrontend(void)
SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency()));
SETCMD(DTV_INVERSION, dtp.Inversion());
SETCMD(DTV_MODULATION, dtp.Modulation());
-
+
tuneTimeout = ATSC_TUNE_TIMEOUT;
- lockTimeout = ATSC_LOCK_TIMEOUT;
+ lockTimeout = ATSC_LOCK_TIMEOUT;
}
else {
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
@@ -527,7 +636,7 @@ void cDvbTuner::Action(void)
fe_status_t Status = (fe_status_t)0;
while (Running()) {
fe_status_t NewStatus;
- if (GetFrontendStatus(NewStatus, 10))
+ if (GetFrontendStatus(NewStatus))
Status = NewStatus;
cMutexLock MutexLock(&mutex);
switch (tunerStatus) {
@@ -936,7 +1045,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
bool hasPriority = Priority < 0 || Priority > this->Priority();
bool needsDetachReceivers = false;
- if (ProvidesTransponder(Channel)) {
+ if (dvbTuner && ProvidesTransponder(Channel)) {
result = hasPriority;
if (Priority >= 0 && Receiving(true)) {
if (dvbTuner->IsTunedTo(Channel)) {
@@ -969,19 +1078,30 @@ int cDvbDevice::NumProvidedSystems(void) const
return numProvidedSystems;
}
+int cDvbDevice::SignalStrength(void) const
+{
+ return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
+}
+
+int cDvbDevice::SignalQuality(void) const
+{
+ return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
+}
+
const cChannel *cDvbDevice::GetCurrentlyTunedTransponder(void) const
{
- return dvbTuner->GetTransponder();
+ return dvbTuner ? dvbTuner->GetTransponder() : NULL;
}
bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
{
- return dvbTuner->IsTunedTo(Channel);
+ return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
}
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
- dvbTuner->Set(Channel);
+ if (dvbTuner)
+ dvbTuner->Set(Channel);
return true;
}
@@ -1036,3 +1156,24 @@ cDvbDeviceProbe::~cDvbDeviceProbe()
{
DvbDeviceProbes.Del(this, false);
}
+
+uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
+{
+ cString FileName;
+ cReadLine ReadLine;
+ FILE *f = NULL;
+ uint32_t SubsystemId = 0;
+ FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
+ if ((f = fopen(FileName, "r")) != NULL) {
+ if (char *s = ReadLine.Read(f))
+ SubsystemId = strtoul(s, NULL, 0) << 16;
+ fclose(f);
+ }
+ FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
+ if ((f = fopen(FileName, "r")) != NULL) {
+ if (char *s = ReadLine.Read(f))
+ SubsystemId |= strtoul(s, NULL, 0);
+ fclose(f);
+ }
+ return SubsystemId;
+}
diff --git a/dvbdevice.h b/dvbdevice.h
index ff606fd4..0962548c 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.h 2.14 2010/04/11 10:29:37 kls Exp $
+ * $Id: dvbdevice.h 2.15 2011/06/02 13:20:05 kls Exp $
*/
#ifndef __DVBDEVICE_H
@@ -141,6 +141,8 @@ public:
virtual bool ProvidesTransponder(const cChannel *Channel) const;
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
virtual int NumProvidedSystems(void) const;
+ virtual int SignalStrength(void) const;
+ virtual int SignalQuality(void) const;
virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
virtual bool IsTunedToTransponder(const cChannel *Channel);
protected:
@@ -196,6 +198,7 @@ class cDvbDeviceProbe : public cListObject {
public:
cDvbDeviceProbe(void);
virtual ~cDvbDeviceProbe();
+ static uint32_t GetSubsystemId(int Adapter, int Frontend);
virtual bool Probe(int Adapter, int Frontend) = 0;
///< Probes for a DVB device at the given Adapter and creates the appropriate
///< object derived from cDvbDevice if applicable.
diff --git a/skinsttng.c b/skinsttng.c
index 9bd1b15c..5039a6c2 100644
--- a/skinsttng.c
+++ b/skinsttng.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinsttng.c 2.7 2011/02/20 13:02:49 kls Exp $
+ * $Id: skinsttng.c 2.8 2011/06/02 12:54:43 kls Exp $
*/
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@@ -92,6 +92,8 @@ THEME_CLR(Theme, clrChannelEpgTitle, clrCyan);
THEME_CLR(Theme, clrChannelEpgShortText, clrYellow);
THEME_CLR(Theme, clrChannelTimebarSeen, clrYellow);
THEME_CLR(Theme, clrChannelTimebarRest, clrGray50);
+THEME_CLR(Theme, clrChannelSignalValue, clrGreen);
+THEME_CLR(Theme, clrChannelSignalRest, clrRed);
THEME_CLR(Theme, clrMenuFrame, clrYellow);
THEME_CLR(Theme, clrMenuTitle, clrBlack);
THEME_CLR(Theme, clrMenuDate, clrBlack);
@@ -134,6 +136,9 @@ private:
const cEvent *present;
cString lastDate;
int lastSeen;
+ int lastDeviceNumber;
+ int lastSignalStrength;
+ int lastSignalQuality;
tTrackId lastTrackId;
static cBitmap bmTeletext, bmRadio, bmAudio, bmDolbyDigital, bmEncrypted, bmRecording;
public:
@@ -156,6 +161,9 @@ cSkinSTTNGDisplayChannel::cSkinSTTNGDisplayChannel(bool WithInfo)
{
present = NULL;
lastSeen = -1;
+ lastDeviceNumber = -1;
+ lastSignalStrength = -1;
+ lastSignalQuality = -1;
memset(&lastTrackId, 0, sizeof(lastTrackId));
const cFont *font = cFont::GetFont(fontOsd);
withInfo = WithInfo;
@@ -344,6 +352,36 @@ void cSkinSTTNGDisplayChannel::Flush(void)
osd->DrawRectangle(x1 + Gap, y3, x1 + Gap + ScrollWidth - 1, y3 + seen, Theme.Color(clrChannelTimebarSeen));
lastSeen = seen;
}
+ int DeviceNumber = cDevice::ActualDevice()->DeviceNumber() + 1;
+ int SignalStrength = cDevice::ActualDevice()->SignalStrength();
+ int SignalQuality = cDevice::ActualDevice()->SignalQuality();
+ if (DeviceNumber != lastDeviceNumber || SignalStrength != lastSignalStrength || SignalQuality != lastSignalQuality) {
+ int d = 3;
+ int h = ((y7 - y6 + 1) - 3 * d) / 2;
+ int w = (x4 - x3) / 5;
+ int x = (x3 + x4) / 2 - w / 2;
+ if (SignalStrength >= 0) {
+ int s = SignalStrength * w / 100;
+ osd->DrawRectangle(x, y6 + d, x + s - 1, y6 + d + h - 1, Theme.Color(clrChannelSignalValue));
+ osd->DrawRectangle(x + s, y6 + d, x + w - 1, y6 + d + h - 1, Theme.Color(clrChannelSignalRest));
+ }
+ else if (DeviceNumber != lastDeviceNumber)
+ osd->DrawRectangle(x, y6 + d, x + w - 1, y6 + d + h - 1, Theme.Color(clrChannelFrame));
+ if (SignalQuality >= 0) {
+ int q = SignalQuality * w / 100;
+ osd->DrawRectangle(x, y7 - d - h + 1, x + q - 1, y7 - d, Theme.Color(clrChannelSignalValue));
+ osd->DrawRectangle(x + q, y7 - d - h + 1, x + w - 1, y7 - d, Theme.Color(clrChannelSignalRest));
+ }
+ else if (DeviceNumber != lastDeviceNumber)
+ osd->DrawRectangle(x, y7 - d - h + 1, x + w - 1, y7 - d, Theme.Color(clrChannelFrame));
+ cString dn = cString::sprintf(" %d ", DeviceNumber);
+ const cFont *font = cFont::GetFont(fontSml);
+ int dw = font->Width(dn);
+ osd->DrawText(x - 2 * d - dw, y6, dn, Theme.Color(clrChannelDate), frameColor, font, dw);
+ lastDeviceNumber = DeviceNumber;
+ lastSignalStrength = SignalStrength;
+ lastSignalQuality = SignalQuality;
+ }
}
osd->Flush();
}