diff options
| -rw-r--r-- | CONTRIBUTORS | 1 | ||||
| -rw-r--r-- | HISTORY | 10 | ||||
| -rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsdffdevice.c | 19 | ||||
| -rw-r--r-- | device.c | 12 | ||||
| -rw-r--r-- | device.h | 12 | ||||
| -rw-r--r-- | dvbdevice.c | 175 | ||||
| -rw-r--r-- | dvbdevice.h | 5 | ||||
| -rw-r--r-- | skinsttng.c | 40 | 
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 @@ -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"); @@ -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; @@ -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();  } | 
