femon cleanup/SVDRP enhancement

Message ID 20060619185233.GD25098@MAIL.13thfloor.at
State New
Headers

Commit Message

Herbert Poetzl June 19, 2006, 6:52 p.m. UTC
  On Sun, Jun 18, 2006 at 07:05:12PM +0300, Rolf Ahrenberg wrote:
> On Sun, 18 Jun 2006, Herbert Poetzl wrote:
> 
> >the first patch moves most of the value-to-string
> >conversions from femonosd.c to femontools.c and
> >declares them properly in the femontools.h file.
> >the osd part is updated to utilize them.
> >the second patch extends the SVDRP interface of
> >femon by a basic INFO command (which can easily
> >be extended in the future), giving output like
> >this:
> 
> Thanks for the patch. However, there're a few glitches in it. The INFO
> command should differentiate the frontend type: for example there's
> no polarization setting if using DVB-T or DVB-C. Also SVDRP output
> shouldn't be localized, but now the INFO command uses those conv*
> functions that are outputting translated strings.
> 
> >would be nice to get some feedback
> 
> Just get those mentioned things corrected, remove all tabulators and
> replace them with spaces, and finally send the patch directly to me
> and I'll integrate it into the next release.

okay, I guess I corrected all the mentioned stuff, 
but I could not test the Cable and Terrestrial cases,
nevertheless I _think_ they should be fine ...

best,
Herbert
  

Comments

Frank Schmirler June 20, 2006, 6:33 a.m. UTC | #1
On Mon, 19 Jun 2006 20:52:33 +0200, Herbert Poetzl wrote
> +  else if (strcasecmp(Command, "INFO") == 0) {
> +     cString str = getFrontendInfo(atoi(Option));

I like the possibility to pass the device index as option. However it should
be optional. I'd suggest:

cString str = getFrontendInfo(*Option ? atoi(Option) :
cDevice::ActualDevice()->CardIndex());

Would be nice if all commands worked that way...

Cheers,
Frank
  
Herbert Poetzl June 20, 2006, 3:54 p.m. UTC | #2
On Tue, Jun 20, 2006 at 08:33:28AM +0200, Frank Schmirler wrote:
> On Mon, 19 Jun 2006 20:52:33 +0200, Herbert Poetzl wrote
> > +  else if (strcasecmp(Command, "INFO") == 0) {
> > +     cString str = getFrontendInfo(atoi(Option));
> 
> I like the possibility to pass the device index as option. However it should
> be optional. I'd suggest:
> 
> cString str = getFrontendInfo(*Option ? atoi(Option) :
> cDevice::ActualDevice()->CardIndex());

ah, yes good point ...

> Would be nice if all commands worked that way...

should be easy to add, when I find some time, I'll
prepare a patch if that is appreciated ...

best,
Herbert

> Cheers,
> Frank
> 
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
  
Rolf Ahrenberg June 20, 2006, 4:59 p.m. UTC | #3
On Tue, 20 Jun 2006, Herbert Poetzl wrote:

> On Tue, Jun 20, 2006 at 08:33:28AM +0200, Frank Schmirler wrote:
>> On Mon, 19 Jun 2006 20:52:33 +0200, Herbert Poetzl wrote
>>> +  else if (strcasecmp(Command, "INFO") == 0) {
>>> +     cString str = getFrontendInfo(atoi(Option));
>>
>> I like the possibility to pass the device index as option. However it should
>> be optional. I'd suggest:
>>
>> cString str = getFrontendInfo(*Option ? atoi(Option) :
>> cDevice::ActualDevice()->CardIndex());
>
> ah, yes good point ...

Well, I don't see the point to check statistics on secondary devices 
that might _not_ even be tuned to any transponder. However, if you want 
to check how the current transponder looks like on other devices, you 
can always use NEXT/PREV commands.

>> Would be nice if all commands worked that way...

Would it? Why? Bitrates are calculated only on current channel, so 
should they be available also for all channels on all available 
transponders/devices?

--
rofa
  
Frank Schmirler June 21, 2006, 11:35 a.m. UTC | #4
On Tue, 20 Jun 2006 19:59:15 +0300 (EEST), Rolf Ahrenberg wrote
> On Tue, 20 Jun 2006, Herbert Poetzl wrote:
> 
> > On Tue, Jun 20, 2006 at 08:33:28AM +0200, Frank Schmirler wrote:
> >> On Mon, 19 Jun 2006 20:52:33 +0200, Herbert Poetzl wrote
> >>> +  else if (strcasecmp(Command, "INFO") == 0) {
> >>> +     cString str = getFrontendInfo(atoi(Option));
> >>
> >> I like the possibility to pass the device index as option. However it should
> >> be optional. I'd suggest:
> >>
> >> cString str = getFrontendInfo(*Option ? atoi(Option) :
> >> cDevice::ActualDevice()->CardIndex());
> >
> > ah, yes good point ...
> 
> Well, I don't see the point to check statistics on secondary devices 
> that might _not_ even be tuned to any transponder. However, if you 
> want to check how the current transponder looks like on other 
> devices, you can always use NEXT/PREV commands.

I am about to write a femon patch for vdr-to-vdr streaming clients. I want to
make it possible for the client to see the signal information from the server.
Prototype which always shows the output of the primary device is already
working. Now I need to get the information which server dvbcard is currently
tuned to the clients channel. Still need to investigate the best way to do
this (cDevice::IsTunedToTransponder? Watching cStatus::ChannelSwitch? Check
the output of the femon INFO command once it is included? Anyone a better
idea?). With the correct card index I could then get the frontend information
if the femon SVDRP commands would accept the card index as parameter.

Will post the patch when I'm done, however it will still take a few weeks as I
have little time to work on it.

> >> Would be nice if all commands worked that way...
> 
> Would it? Why? Bitrates are calculated only on current channel, so 
> should they be available also for all channels on all available 
> transponders/devices?

In my case the streaming client can do the stream analysis, so I won't need
the bitrates per device. Making this information available would have quite an
impact on the femon code anyway. However for the frontend commands it is
fairly easy.

Cheers,
Frank
  
Rolf Ahrenberg June 22, 2006, 6:15 a.m. UTC | #5
On Wed, 21 Jun 2006, Frank Schmirler wrote:

> working. Now I need to get the information which server dvbcard is currently
> tuned to the clients channel. Still need to investigate the best way to do
> this (cDevice::IsTunedToTransponder? Watching cStatus::ChannelSwitch? Check
> the output of the femon INFO command once it is included? Anyone a better
> idea?). With the correct card index I could then get the frontend information
> if the femon SVDRP commands would accept the card index as parameter.

Femon's current frontend svdrp commands (STAT,NAME,SGNL,SNRA,BERA,UNCB) 
are using the actual device as a fixed parameter, so, you'll currently 
need just to tune the server to the same channel as your clients are 
using and you'll always get the correct information. All those mentioned 
svdr commands also print out the card index, if you'll need to show that 
to your clients too.

If your server-client-system is having a dedicated plugin on both ends, 
you could use the service interface to access frontend information: 
femonclient plugin should hopefully give you a glimpse how it could be 
done.

--
rofa
  
Frank Schmirler June 22, 2006, 11:19 a.m. UTC | #6
On Thu, 22 Jun 2006 09:15:10 +0300 (EEST), Rolf Ahrenberg wrote
> Femon's current frontend svdrp commands (STAT,NAME,SGNL,SNRA,BERA,
> UNCB) are using the actual device as a fixed parameter, so, you'll 
> currently need just to tune the server to the same channel as your 
> clients are using and you'll always get the correct information. All 
> those mentioned svdr commands also print out the card index, if 
> you'll need to show that to your clients too.

I guess that should work on a headless streaming server like mine when I add
the dummydevice plugin and set the primary device to it, right? Without dummy
device it won't tune to a different channel if the primary device is
recording. Might work for me, so I will give it a try.

But in case more people are interested in it: what would happen on a server
with someone watching live TV on the FF card and the client streaming from the
budget card? Can't test it as I have no FF card, but I guess the SVDRP CHAN
command would change the channel visible on the server. Could be annoying if
the guy behind the client loves femon statistics...
 
> If your server-client-system is having a dedicated plugin on both 
> ends, you could use the service interface to access frontend 
> information: femonclient plugin should hopefully give you a glimpse 
> how it could be done.

I have it running that way at home. Getting the card index was easy that way
as of course streamdev-server knows it. But I also had to extend the femon
service interface to get the information by card index. I don't like this
solution as it requires patching streamdev-server, streamdev-client and femon.
 That's why I decided to rewrite the whole thing based on SVDRP and trying to
patch femon only.

Cheers,
Frank
  

Patch

--- femon-1.0.1/femon.c	2006-06-18 00:46:51.000000000 +0200
+++ femon-1.0.1.4/femon.c	2006-06-19 20:10:21.000000000 +0200
@@ -132,6 +132,8 @@  const char **cPluginFemon::SVDRPHelpPage
     "    Switch to previous possible device.",
     "NAME\n"
     "    Print the current frontend name.",
+    "INFO\n"
+    "    Print the current frontend info.",
     "STAT\n"
     "    Print the current frontend status.",
     "SGNL\n"
@@ -180,6 +184,14 @@  cString cPluginFemon::SVDRPCommand(const
   else if (strcasecmp(Command, "NAME") == 0) {
      return getFrontendName(cDevice::ActualDevice()->CardIndex());
      }
+  else if (strcasecmp(Command, "INFO") == 0) {
+     cString str = getFrontendInfo(atoi(Option));
+     if (!str) {
+       ReplyCode = 550;
+       return cString("Card not found.");
+       }
+     else return str;
+     }
   else if (strcasecmp(Command, "STAT") == 0) {
      return getFrontendStatus(cDevice::ActualDevice()->CardIndex());
      }
--- femon-1.0.1/femonconv.h	1970-01-01 01:00:00.000000000 +0100
+++ femon-1.0.1.4/femonconv.h	2006-06-19 20:12:28.000000000 +0200
@@ -0,0 +1,289 @@ 
+/*
+ * Frontend Status Monitor plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id$
+ */
+
+#ifndef __FEMONCONV_H
+#define __FEMONCONV_H
+
+#ifndef ctr
+#define ctr tr
+#endif
+
+static inline
+cString convCA(int value)
+{
+  cString str;
+
+  /* http://www.dvb.org/index.php?id=174 */
+  switch (value) {
+    case 0x0000:
+         /* Reserved */
+         str = cString(ctr("Free to Air"));
+         break;
+    case 0x0001 ... 0x00FF:
+         /* Standardized systems */
+         if ((value == 0x00A0) || (value == 0x00A1))
+            str = cString(ctr("Analog"));
+         else
+            str = cString(ctr("Fixed"));
+         break;
+    case 0x0100 ... 0x01FF:
+         /* Canal Plus */
+         str = cString(ctr("SECA/Mediaguard"));
+         break;
+    case 0x0500 ... 0x05FF:
+         /* France Telecom */
+         str = cString(ctr("Viaccess"));
+         break;
+    case 0x0600 ... 0x06FF:
+         /* Irdeto */
+         str = cString(ctr("Irdeto"));
+         break;
+    case 0x0900 ... 0x09FF:
+         /* News Datacom */
+         str = cString(ctr("NDS/Videoguard"));
+         break;
+    case 0x0B00 ... 0x0BFF:
+         /* Norwegian Telekom */
+         str = cString(ctr("Conax"));
+         break;
+    case 0x0D00 ... 0x0DFF:
+         /* Philips */
+         str = cString(ctr("CryptoWorks"));
+         break;
+    case 0x0E00 ... 0x0EFF:
+         /* Scientific Atlanta */
+         str = cString(ctr("PowerVu"));
+         break;
+    case 0x1200 ... 0x12FF:
+         /* BellVu Express */
+         str = cString(ctr("NagraVision"));
+         break;
+    case 0x1700 ... 0x17FF:
+         /* BetaTechnik */
+         str = cString(ctr("BetaCrypt"));
+         break;
+    case 0x1800 ... 0x18FF:
+         /* Kudelski SA */
+         str = cString(ctr("NagraVision"));
+         break;
+    case 0x4A60 ... 0x4A6F:
+         /* @Sky */
+         str = cString(ctr("SkyCrypt"));
+         break;
+    default:
+         str = cString::sprintf("%X", value);
+         break;
+    }
+  return str;
+}
+
+static inline
+cString convCoderate(int value)
+{
+  cString str;
+
+  if      (value == FEC_NONE)  str = cString(ctr("None"));
+  else if (value == FEC_1_2)   str = cString("1/2");
+  else if (value == FEC_2_3)   str = cString("2/3");
+  else if (value == FEC_3_4)   str = cString("3/4");
+  else if (value == FEC_4_5)   str = cString("4/5");
+  else if (value == FEC_5_6)   str = cString("5/6");
+  else if (value == FEC_6_7)   str = cString("6/7");
+  else if (value == FEC_7_8)   str = cString("7/8");
+  else if (value == FEC_8_9)   str = cString("8/9");
+  else            /*FEC_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convTransmission(int value)
+{
+  cString str;
+
+  if      (value == TRANSMISSION_MODE_2K)    str = cString("2K");
+  else if (value == TRANSMISSION_MODE_8K)    str = cString("8K");
+  else            /*TRANSMISSION_MODE_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convBandwidth(int value)
+{
+  cString str;
+
+  if      (value == BANDWIDTH_8_MHZ) str = cString("8 %s", ctr("MHz"));
+  else if (value == BANDWIDTH_7_MHZ) str = cString("7 %s", ctr("MHz"));
+  else if (value == BANDWIDTH_6_MHZ) str = cString("6 %s", ctr("MHz"));
+  else            /*BANDWIDTH_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convInversion(int value)
+{
+  cString str;
+
+  if      (value == INVERSION_OFF)   str = cString(ctr("Off"));
+  else if (value == INVERSION_ON)    str = cString(ctr("On"));
+  else            /*INVERSION_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convHierarchy(int value)
+{
+  cString str;
+
+  if      (value == HIERARCHY_NONE)  str = cString(ctr("None"));
+  else if (value == HIERARCHY_1)     str = cString("1");
+  else if (value == HIERARCHY_2)     str = cString("2");
+  else if (value == HIERARCHY_4)     str = cString("4");
+  else            /*HIERARCHY_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convGuard(int value)
+{
+  cString str;
+
+  if      (value == GUARD_INTERVAL_1_32)  str = cString("1/32");
+  else if (value == GUARD_INTERVAL_1_16)  str = cString("1/16");
+  else if (value == GUARD_INTERVAL_1_8)   str = cString("1/8");
+  else if (value == GUARD_INTERVAL_1_4)   str = cString("1/4");
+  else            /*GUARD_INTERVAL_AUTO*/ str = cString(ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convModulation(int value)
+{
+  cString str;
+ 
+  if      (value == QPSK)      str = cString("QPSK");
+  else if (value == QAM_16)    str = cString("QAM 16");
+  else if (value == QAM_32)    str = cString("QAM 32");
+  else if (value == QAM_64)    str = cString("QAM 64");
+  else if (value == QAM_128)   str = cString("QAM 128");
+  else if (value == QAM_256)   str = cString("QAM 256");
+  else            /*QAM_AUTO*/ str = cString::sprintf("QAM %s", ctr("Auto"));
+  return str;
+}
+
+static inline
+cString convAspectRatio(int value)
+{
+  cString str;
+  
+  if      (value == AR_1_1)    str = cString("1:1");
+  else if (value == AR_4_3)    str = cString("4:3");
+  else if (value == AR_16_9)   str = cString("16:9");
+  else if (value == AR_2_21_1) str = cString("2.21:1");
+  else                         str = cString(ctr("reserved"));
+  return str;
+}
+
+static inline
+cString convVideoFormat(int value)
+{
+  cString str;
+
+  if      (value == VF_PAL)    str = cString(ctr("PAL"));
+  else if (value == VF_NTSC)   str = cString(ctr("NTSC"));
+  else                         str = cString(ctr("unknown"));
+  return str;
+}
+
+static inline
+cString convAC3BitStreamMode(int value, int mode)
+{
+  cString str;
+
+  switch (value) {
+    case 0: str = cString(ctr("Complete Main (CM)"));     break;
+    case 1: str = cString(ctr("Music and Effects (ME)")); break;
+    case 2: str = cString(ctr("Visually Impaired (VI)")); break;
+    case 3: str = cString(ctr("Hearing Impaired (HI)"));  break;
+    case 4: str = cString(ctr("Dialogue (D)"));           break;
+    case 5: str = cString(ctr("Commentary (C)"));         break;
+    case 6: str = cString(ctr("Emergency (E)"));          break;
+    case 7: str = (mode == 1) ? cString(ctr("Voice Over (VO)")) : cString(ctr("Karaoke")); break;
+    default: str = cString("---");
+    }
+  return str;
+}
+
+static inline
+cString convAC3AudioCodingMode(int value)
+{
+  cString str;
+
+  switch (value) {
+    case 0:  str = cString::sprintf("1+1 - %s, %s",             ctr("Ch1"), ctr("Ch2"));                              break;
+    case 1:  str = cString::sprintf("1/0 - %s",                 ctr("C"));                                            break;
+    case 2:  str = cString::sprintf("2/0 - %s, %s",             ctr("L"), ctr("R"));                                  break;
+    case 3:  str = cString::sprintf("3/0 - %s, %s, %s",         ctr("L"), ctr("C"), ctr("R"));                        break;
+    case 4:  str = cString::sprintf("2/1 - %s, %s, %s",         ctr("L"), ctr("R"), ctr("S"));                        break;
+    case 5:  str = cString::sprintf("3/1 - %s, %s, %s, %s",     ctr("L"), ctr("C"), ctr("R"),  ctr("S"));             break;
+    case 6:  str = cString::sprintf("2/2 - %s, %s, %s, %s",     ctr("L"), ctr("R"), ctr("SL"), ctr("SR"));            break;
+    case 7:  str = cString::sprintf("3/2 - %s, %s, %s, %s, %s", ctr("L"), ctr("C"), ctr("R"),  ctr("SL"), ctr("SR")); break;
+    default: str = cString("---");
+    }
+  return str;
+}
+
+static inline
+cString convAC3CenterMixLevel(int value)
+{
+  cString str;
+
+  switch (value) {
+    case CML_MINUS_3dB:   str = cString::sprintf("-3.0 %s", ctr("dB")); break;
+    case CML_MINUS_4_5dB: str = cString::sprintf("-4.5 %s", ctr("dB")); break;
+    case CML_MINUS_6dB:   str = cString::sprintf("-6.0 %s", ctr("dB")); break;
+    case CML_RESERVED:    str = cString(ctr("reserved")); break;
+    default:              str = cString("---");
+    }
+  return str;
+}
+
+static inline
+cString convAC3SurroundMixLevel(int value)
+{
+  cString str;
+
+  switch (value) {
+    case SML_MINUS_3dB:   str = cString::sprintf("-3 %s", ctr("dB"));   break;
+    case SML_MINUS_6dB:   str = cString::sprintf("-6 %s", ctr("dB"));   break;
+    case SML_0_dB:        str = cString::sprintf("0 %s",  ctr("dB"));   break;
+    case SML_RESERVED:    str = cString(ctr("reserved")); break;
+    default:              str = cString("---");
+    }
+  return str;
+}
+
+static inline
+cString convAC3DolbySurroundMode(int value)
+{
+  cString str;
+
+  switch (value) {
+    case DSM_NOT_INDICATED:     str = cString(ctr("not indicated"));    break;
+    case DSM_NOT_DOLBYSURROUND: str = cString(ctr("no"));               break;
+    case DSM_DOLBYSURROUND:     str = cString(ctr("yes"));              break;
+    case DSM_RESERVED:          str = cString(ctr("reserved"));         break;
+    default:                    str = cString("---");
+    }
+  return str;
+}
+
+
+
+
+
+#endif // __FEMONCONV_H
--- femon-1.0.1/femonosd.c	2006-06-18 00:46:57.000000000 +0200
+++ femon-1.0.1.4/femonosd.c	2006-06-19 19:42:59.000000000 +0200
@@ -12,6 +12,7 @@ 
 #include "femonreceiver.h"
 #include "femontools.h"
 #include "femonosd.h"
+#include "femonconv.h"
 
 #include "symbols/device.xpm"
 #include "symbols/stereo.xpm"
@@ -412,69 +413,8 @@  void cFemonOsd::DrawInfoWindow(void)
         m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
         offset += OSDROWHEIGHT;
         m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("CA"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-        value = channel->Ca();
         if (femonConfig.showcasystem) {
-           /* http://www.dvb.org/index.php?id=174 */
-           switch (value) {
-             case 0x0000:
-                  /* Reserved */
-                  snprintf(buf, sizeof(buf), "%s", tr("Free to Air"));
-                  break;
-             case 0x0001 ... 0x00FF:
-                  /* Standardized systems */
-                  if ((value == 0x00A0) || (value == 0x00A1))
-                     snprintf(buf, sizeof(buf), "%s", tr("Analog"));
-                  else
-                     snprintf(buf, sizeof(buf), "%s", tr("Fixed"));
-                  break;
-             case 0x0100 ... 0x01FF:
-                  /* Canal Plus */
-                  snprintf(buf, sizeof(buf), "%s", tr("SECA/Mediaguard"));
-                  break;
-             case 0x0500 ... 0x05FF:
-                  /* France Telecom */
-                  snprintf(buf, sizeof(buf), "%s", tr("Viaccess"));
-                  break;
-             case 0x0600 ... 0x06FF:
-                  /* Irdeto */
-                  snprintf(buf, sizeof(buf), "%s", tr("Irdeto"));
-                  break;
-             case 0x0900 ... 0x09FF:
-                  /* News Datacom */
-                  snprintf(buf, sizeof(buf), "%s", tr("NDS/Videoguard"));
-                  break;
-             case 0x0B00 ... 0x0BFF:
-                  /* Norwegian Telekom */
-                  snprintf(buf, sizeof(buf), "%s", tr("Conax"));
-                  break;
-             case 0x0D00 ... 0x0DFF:
-                  /* Philips */
-                  snprintf(buf, sizeof(buf), "%s", tr("CryptoWorks"));
-                  break;
-             case 0x0E00 ... 0x0EFF:
-                  /* Scientific Atlanta */
-                  snprintf(buf, sizeof(buf), "%s", tr("PowerVu"));
-                  break;
-             case 0x1200 ... 0x12FF:
-                  /* BellVu Express */
-                  snprintf(buf, sizeof(buf), "%s", tr("NagraVision"));
-                  break;
-             case 0x1700 ... 0x17FF:
-                  /* BetaTechnik */
-                  snprintf(buf, sizeof(buf), "%s", tr("BetaCrypt"));
-                  break;
-             case 0x1800 ... 0x18FF:
-                  /* Kudelski SA */
-                  snprintf(buf, sizeof(buf), "%s", tr("NagraVision"));
-                  break;
-             case 0x4A60 ... 0x4A6F:
-                  /* @Sky */
-                  snprintf(buf, sizeof(buf), "%s", tr("SkyCrypt"));
-                  break;
-             default:
-                  snprintf(buf, sizeof(buf), "%X", value);
-                  break;
-             }
+           snprintf(buf, sizeof(buf), "%s", *convCA(channel->Ca()));
            }
         else {
            snprintf(buf, sizeof(buf), "%X", value);
@@ -525,23 +465,10 @@  void cFemonOsd::DrawInfoWindow(void)
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                offset += OSDROWHEIGHT;
                m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Inversion"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Inversion();
-               if      (value == INVERSION_OFF)   snprintf(buf, sizeof(buf), tr("Off"));
-               else if (value == INVERSION_ON)    snprintf(buf, sizeof(buf), tr("On"));
-               else            /*INVERSION_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convInversion(channel->Inversion()));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("CoderateH"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->CoderateH();
-               if      (value == FEC_NONE)  snprintf(buf, sizeof(buf), tr("None"));
-               else if (value == FEC_1_2)   snprintf(buf, sizeof(buf), "1/2");
-               else if (value == FEC_2_3)   snprintf(buf, sizeof(buf), "2/3");
-               else if (value == FEC_3_4)   snprintf(buf, sizeof(buf), "3/4");
-               else if (value == FEC_4_5)   snprintf(buf, sizeof(buf), "4/5");
-               else if (value == FEC_5_6)   snprintf(buf, sizeof(buf), "5/6");
-               else if (value == FEC_6_7)   snprintf(buf, sizeof(buf), "6/7");
-               else if (value == FEC_7_8)   snprintf(buf, sizeof(buf), "7/8");
-               else if (value == FEC_8_9)   snprintf(buf, sizeof(buf), "8/9");
-               else            /*FEC_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convCoderate(channel->CoderateH()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                break;
 
@@ -562,34 +489,14 @@  void cFemonOsd::DrawInfoWindow(void)
                snprintf(buf, sizeof(buf), "%d", channel->Srate());
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("Modulation"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Modulation();
-               if      (value == QPSK)      snprintf(buf, sizeof(buf), "QPSK");
-               else if (value == QAM_16)    snprintf(buf, sizeof(buf), "QAM 16");
-               else if (value == QAM_32)    snprintf(buf, sizeof(buf), "QAM 32");
-               else if (value == QAM_64)    snprintf(buf, sizeof(buf), "QAM 64");
-               else if (value == QAM_128)   snprintf(buf, sizeof(buf), "QAM 128");
-               else if (value == QAM_256)   snprintf(buf, sizeof(buf), "QAM 256");
-               else            /*QAM_AUTO*/ snprintf(buf, sizeof(buf), "QAM %s", tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convModulation(channel->Modulation()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                offset += OSDROWHEIGHT;
                m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Inversion"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Inversion();
-               if      (value == INVERSION_OFF)   snprintf(buf, sizeof(buf), tr("Off"));
-               else if (value == INVERSION_ON)    snprintf(buf, sizeof(buf), tr("On"));
-               else            /*INVERSION_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convInversion(channel->Inversion()));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("CoderateH"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->CoderateH();
-               if      (value == FEC_NONE)  snprintf(buf, sizeof(buf), tr("None"));
-               else if (value == FEC_1_2)   snprintf(buf, sizeof(buf), "1/2");
-               else if (value == FEC_2_3)   snprintf(buf, sizeof(buf), "2/3");
-               else if (value == FEC_3_4)   snprintf(buf, sizeof(buf), "3/4");
-               else if (value == FEC_4_5)   snprintf(buf, sizeof(buf), "4/5");
-               else if (value == FEC_5_6)   snprintf(buf, sizeof(buf), "5/6");
-               else if (value == FEC_6_7)   snprintf(buf, sizeof(buf), "6/7");
-               else if (value == FEC_7_8)   snprintf(buf, sizeof(buf), "7/8");
-               else if (value == FEC_8_9)   snprintf(buf, sizeof(buf), "8/9");
-               else            /*FEC_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convCoderate(channel->CoderateH()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                break;
 
@@ -603,77 +510,28 @@  void cFemonOsd::DrawInfoWindow(void)
                snprintf(buf, sizeof(buf), "%d %s", value, tr("MHz"));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("Transmission"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Transmission();
-               if      (value == TRANSMISSION_MODE_2K)    snprintf(buf, sizeof(buf), "2K");
-               else if (value == TRANSMISSION_MODE_8K)    snprintf(buf, sizeof(buf), "8K");
-               else            /*TRANSMISSION_MODE_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convTransmission(channel->Transmission()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                offset += OSDROWHEIGHT;
                m_Osd->DrawText( OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Bandwidth"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Bandwidth();
-               if      (value == BANDWIDTH_8_MHZ) snprintf(buf, sizeof(buf), "8 %s", tr("MHz"));
-               else if (value == BANDWIDTH_7_MHZ) snprintf(buf, sizeof(buf), "7 %s", tr("MHz"));
-               else if (value == BANDWIDTH_6_MHZ) snprintf(buf, sizeof(buf), "6 %s", tr("MHz"));
-               else            /*BANDWIDTH_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convBandwidth(channel->Bandwidth()));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("Modulation"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Modulation();
-               if      (value == QPSK)      snprintf(buf, sizeof(buf), "QPSK");
-               else if (value == QAM_16)    snprintf(buf, sizeof(buf), "QAM 16");
-               else if (value == QAM_32)    snprintf(buf, sizeof(buf), "QAM 32");
-               else if (value == QAM_64)    snprintf(buf, sizeof(buf), "QAM 64");
-               else if (value == QAM_128)   snprintf(buf, sizeof(buf), "QAM 128");
-               else if (value == QAM_256)   snprintf(buf, sizeof(buf), "QAM 256");
-               else            /*QAM_AUTO*/ snprintf(buf, sizeof(buf), "QAM %s", tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convModulation(channel->Modulation()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                offset += OSDROWHEIGHT;
                m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Inversion"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Inversion();
-               if      (value == INVERSION_OFF)   snprintf(buf, sizeof(buf), tr("Off"));
-               else if (value == INVERSION_ON)    snprintf(buf, sizeof(buf), tr("On"));
-               else            /*INVERSION_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convInversion(channel->Inversion()));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("Coderate"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->CoderateH();
-               if      (value == FEC_NONE)  snprintf(buf, sizeof(buf), "%s (H)", tr("None"));
-               else if (value == FEC_1_2)   snprintf(buf, sizeof(buf), "1/2 (H)");
-               else if (value == FEC_2_3)   snprintf(buf, sizeof(buf), "2/3 (H)");
-               else if (value == FEC_3_4)   snprintf(buf, sizeof(buf), "3/4 (H)");
-               else if (value == FEC_4_5)   snprintf(buf, sizeof(buf), "4/5 (H)");
-               else if (value == FEC_5_6)   snprintf(buf, sizeof(buf), "5/6 (H)");
-               else if (value == FEC_6_7)   snprintf(buf, sizeof(buf), "6/7 (H)");
-               else if (value == FEC_7_8)   snprintf(buf, sizeof(buf), "7/8 (H)");
-               else if (value == FEC_8_9)   snprintf(buf, sizeof(buf), "8/9 (H)");
-               else            /*FEC_AUTO*/ snprintf(buf, sizeof(buf), "%s (H)", tr("Auto"));
-               value = channel->CoderateL();
-               if      (value == FEC_NONE)  snprintf(buf2, sizeof(buf2), " %s (L)", tr("None"));
-               else if (value == FEC_1_2)   snprintf(buf2, sizeof(buf2), " 1/2 (L)");
-               else if (value == FEC_2_3)   snprintf(buf2, sizeof(buf2), " 2/3 (L)");
-               else if (value == FEC_3_4)   snprintf(buf2, sizeof(buf2), " 3/4 (L)");
-               else if (value == FEC_4_5)   snprintf(buf2, sizeof(buf2), " 4/5 (L)");
-               else if (value == FEC_5_6)   snprintf(buf2, sizeof(buf2), " 5/6 (L)");
-               else if (value == FEC_6_7)   snprintf(buf2, sizeof(buf2), " 6/7 (L)");
-               else if (value == FEC_7_8)   snprintf(buf2, sizeof(buf2), " 7/8 (L)");
-               else if (value == FEC_8_9)   snprintf(buf2, sizeof(buf2), " 8/9 (L)");
-               else            /*FEC_AUTO*/ snprintf(buf2, sizeof(buf2), " %s (L)", tr("Auto"));
-               strncat(buf, buf2, sizeof(buf));
+               snprintf(buf, sizeof(buf), "%s (H) %s (L)", *convCoderate(channel->CoderateH()), *convCoderate(channel->CoderateL()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                offset += OSDROWHEIGHT;
                m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Hierarchy"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Hierarchy();
-               if      (value == HIERARCHY_NONE)  snprintf(buf, sizeof(buf), tr("None"));
-               else if (value == HIERARCHY_1)     snprintf(buf, sizeof(buf), "1");
-               else if (value == HIERARCHY_2)     snprintf(buf, sizeof(buf), "2");
-               else if (value == HIERARCHY_4)     snprintf(buf, sizeof(buf), "4");
-               else            /*HIERARCHY_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convHierarchy(channel->Hierarchy()));
                m_Osd->DrawText(OSDINFOWIN_X(2), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), tr("Guard"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-               value = channel->Guard();
-               if      (value == GUARD_INTERVAL_1_32)  snprintf(buf, sizeof(buf), "1/32");
-               else if (value == GUARD_INTERVAL_1_16)  snprintf(buf, sizeof(buf), "1/16");
-               else if (value == GUARD_INTERVAL_1_8)   snprintf(buf, sizeof(buf), "1/8");
-               else if (value == GUARD_INTERVAL_1_4)   snprintf(buf, sizeof(buf), "1/4");
-               else            /*GUARD_INTERVAL_AUTO*/ snprintf(buf, sizeof(buf), tr("Auto"));
+               snprintf(buf, sizeof(buf), "%s", *convGuard(channel->Guard()));
                m_Osd->DrawText(OSDINFOWIN_X(4), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
                break;
           }
@@ -701,15 +559,10 @@  void cFemonOsd::DrawInfoWindow(void)
         m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
         offset += OSDROWHEIGHT;
         m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Aspect Ratio"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-        if (m_Receiver) {
-           value = m_Receiver->VideoAspectRatio();
-           if      (value == AR_1_1)    snprintf(buf, sizeof(buf), "1:1");
-           else if (value == AR_4_3)    snprintf(buf, sizeof(buf), "4:3");
-           else if (value == AR_16_9)   snprintf(buf, sizeof(buf), "16:9");
-           else if (value == AR_2_21_1) snprintf(buf, sizeof(buf), "2.21:1");
-           else                         snprintf(buf, sizeof(buf), "%s", tr("reserved"));
-           }
-        else                            snprintf(buf, sizeof(buf), "---");
+        if (m_Receiver)
+           snprintf(buf, sizeof(buf), "%s", *convAspectRatio(m_Receiver->VideoAspectRatio()));
+        else
+           snprintf(buf, sizeof(buf), "---");
         m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
         offset += OSDROWHEIGHT;
         m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Frame Rate"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
@@ -718,13 +571,10 @@  void cFemonOsd::DrawInfoWindow(void)
         m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
         offset += OSDROWHEIGHT;
         m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Video Format"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-        if (m_Receiver) {
-           value = m_Receiver->VideoFormat();
-           if      (value == VF_PAL)  snprintf(buf, sizeof(buf), "%s", tr("PAL"));
-           else if (value == VF_NTSC) snprintf(buf, sizeof(buf), "%s", tr("NTSC"));
-           else                       snprintf(buf, sizeof(buf), "%s", tr("unknown"));
-           }
-        else                          snprintf(buf, sizeof(buf), "---");
+        if (m_Receiver)
+           snprintf(buf, sizeof(buf), "%s", *convVideoFormat(m_Receiver->VideoFormat()));
+        else
+           snprintf(buf, sizeof(buf), "---");
         m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
         offset += OSDROWHEIGHT;
         m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Resolution"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
@@ -788,64 +638,25 @@  void cFemonOsd::DrawInfoWindow(void)
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Bit Stream Mode"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-           switch (m_Receiver->AC3BitStreamMode()) {
-             case 0: snprintf(buf, sizeof(buf), tr("Complete Main (CM)"));     break;
-             case 1: snprintf(buf, sizeof(buf), tr("Music and Effects (ME)")); break;
-             case 2: snprintf(buf, sizeof(buf), tr("Visually Impaired (VI)")); break;
-             case 3: snprintf(buf, sizeof(buf), tr("Hearing Impaired (HI)"));  break;
-             case 4: snprintf(buf, sizeof(buf), tr("Dialogue (D)"));           break;
-             case 5: snprintf(buf, sizeof(buf), tr("Commentary (C)"));         break;
-             case 6: snprintf(buf, sizeof(buf), tr("Emergency (E)"));          break;
-             case 7: (m_Receiver->AC3AudioCodingMode() == 1) ? snprintf(buf, sizeof(buf), tr("Voice Over (VO)")) : snprintf(buf, sizeof(buf), tr("Karaoke")); break;
-             default: snprintf(buf, sizeof(buf), "---");
-             }
+           snprintf(buf, sizeof(buf), "%s", *convAC3BitStreamMode(m_Receiver->AC3BitStreamMode(), m_Receiver->AC3AudioCodingMode()));
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Audio Coding Mode"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-           if (m_Receiver->AC3BitStreamMode() != 7) {
-              switch (m_Receiver->AC3AudioCodingMode()) {
-                case 0:  snprintf(buf, sizeof(buf), "1+1 - %s, %s",             tr("Ch1"), tr("Ch2"));                           break;
-                case 1:  snprintf(buf, sizeof(buf), "1/0 - %s",                 tr("C"));                                        break;
-                case 2:  snprintf(buf, sizeof(buf), "2/0 - %s, %s",             tr("L"), tr("R"));                               break;
-                case 3:  snprintf(buf, sizeof(buf), "3/0 - %s, %s, %s",         tr("L"), tr("C"), tr("R"));                      break;
-                case 4:  snprintf(buf, sizeof(buf), "2/1 - %s, %s, %s",         tr("L"), tr("R"), tr("S"));                      break;
-                case 5:  snprintf(buf, sizeof(buf), "3/1 - %s, %s, %s, %s",     tr("L"), tr("C"), tr("R"),  tr("S"));            break;
-                case 6:  snprintf(buf, sizeof(buf), "2/2 - %s, %s, %s, %s",     tr("L"), tr("R"), tr("SL"), tr("SR"));           break;
-                case 7:  snprintf(buf, sizeof(buf), "3/2 - %s, %s, %s, %s, %s", tr("L"), tr("C"), tr("R"),  tr("SL"), tr("SR")); break;
-                default: snprintf(buf, sizeof(buf), "---");
-                }
-             }
-	   else snprintf(buf, sizeof(buf), "---");
+           if (m_Receiver->AC3BitStreamMode() != 7)
+              snprintf(buf, sizeof(buf), "%s", *convAC3AudioCodingMode(m_Receiver->AC3AudioCodingMode()));
+           else snprintf(buf, sizeof(buf), "---");
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Center Mix Level"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-           switch (m_Receiver->AC3CenterMixLevel()) {
-             case CML_MINUS_3dB:   snprintf(buf, sizeof(buf), "-3.0 %s", tr("dB"));  break;
-             case CML_MINUS_4_5dB: snprintf(buf, sizeof(buf), "-4.5 %s", tr("dB"));  break;
-             case CML_MINUS_6dB:   snprintf(buf, sizeof(buf), "-6.0 %s", tr("dB"));  break;
-             case CML_RESERVED:    snprintf(buf, sizeof(buf), "%s", tr("reserved")); break;
-             default:              snprintf(buf, sizeof(buf), "---");
-             }
+           snprintf(buf, sizeof(buf), "%s", *convAC3CenterMixLevel(m_Receiver->AC3CenterMixLevel()));
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Surround Mix Level"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-           switch (m_Receiver->AC3SurroundMixLevel()) {
-             case SML_MINUS_3dB: snprintf(buf, sizeof(buf), "-3 %s", tr("dB"));    break;
-             case SML_MINUS_6dB: snprintf(buf, sizeof(buf), "-6 %s", tr("dB"));    break;
-             case SML_0_dB:      snprintf(buf, sizeof(buf), "0 %s", tr("dB"));     break;
-             case SML_RESERVED:  snprintf(buf, sizeof(buf), "%s", tr("reserved")); break;
-             default:            snprintf(buf, sizeof(buf), "---");
-             }
+           snprintf(buf, sizeof(buf), "%s", *convAC3SurroundMixLevel(m_Receiver->AC3SurroundMixLevel()));
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Dolby Surround Mode"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
-           switch (m_Receiver->AC3DolbySurroundMode()) {
-             case DSM_NOT_INDICATED:     snprintf(buf, sizeof(buf), "%s", tr("not indicated")); break;
-             case DSM_NOT_DOLBYSURROUND: snprintf(buf, sizeof(buf), "%s", tr("no"));            break;
-             case DSM_DOLBYSURROUND:     snprintf(buf, sizeof(buf), "%s", tr("yes"));           break;
-             case DSM_RESERVED:          snprintf(buf, sizeof(buf), "%s", tr("reserved"));      break;
-             default:                    snprintf(buf, sizeof(buf), "---");
-             }
+           snprintf(buf, sizeof(buf), "%s", *convAC3DolbySurroundMode(m_Receiver->AC3DolbySurroundMode()));
            m_Osd->DrawText(OSDINFOWIN_X(3), OSDINFOWIN_Y(offset), buf, femonTheme[femonConfig.theme].clrActiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
            offset += OSDROWHEIGHT;
            m_Osd->DrawText(OSDINFOWIN_X(1), OSDINFOWIN_Y(offset), tr("Low Frequency Effects"), femonTheme[femonConfig.theme].clrInactiveText, femonTheme[femonConfig.theme].clrBackground, m_Font);
--- femon-1.0.1/femontools.c	2006-06-18 00:46:57.000000000 +0200
+++ femon-1.0.1.4/femontools.c	2006-06-19 20:10:12.000000000 +0200
@@ -6,11 +6,18 @@ 
  * $Id$
  */
 
+#include <ctype.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <linux/dvb/frontend.h>
 #include "femontools.h"
+#include "femoncfg.h"
+#include "femoni18n.h"
+#include "femonreceiver.h"
+
+#define ctr
+#include "femonconv.h"
 
 cString getFrontendName(int cardIndex)
 {
@@ -28,6 +35,90 @@  cString getFrontendName(int cardIndex)
   return (cString::sprintf("%s on device #%d", value.name, cardIndex));
 }
 
+cString getFrontendInfo(int cardIndex)
+{
+  cString str;
+  int value;
+
+  cDevice *device = cDevice::GetDevice(cardIndex);
+  if (!device) return 0;
+  cChannel *channel = Channels.GetByNumber(device->CurrentChannel());
+
+  char *dev = NULL;
+  asprintf(&dev, FRONTEND_DEVICE, cardIndex, 0);
+  int frontend = open(dev, O_RDONLY | O_NONBLOCK);
+  free(dev);
+
+  struct dvb_frontend_info frontendInfo;
+  if (frontend >= 0) {
+    if (ioctl(frontend, FE_GET_INFO, &frontendInfo) < 0)
+      frontend = 0;
+    close(frontend);
+    }
+  else frontend = 0;
+
+  int freq = channel->Frequency();
+  while (freq > 20000) freq /= 1000;
+
+  cString apid_str = cString::sprintf("%5d", channel->Apid(value=0));
+  while (channel->Apid(++value) && (value < MAXAPIDS))
+    apid_str = cString::sprintf("%s, %d", *apid_str, channel->Apid(value));
+
+  cString dpid_str = cString::sprintf("%5d", channel->Dpid(value=0));
+  while (channel->Dpid(++value) && (value < MAXDPIDS))
+    dpid_str = cString::sprintf("%s, %d", *dpid_str, channel->Dpid(value));
+
+  cString ca_str = cString::sprintf(" %04x", channel->Ca(value=0));
+  while (channel->Ca(++value) && (value < MAXCAIDS))
+    ca_str = cString::sprintf("%s, %04x", *ca_str, channel->Ca(value));
+
+  str = cString::sprintf("#%d - %s\n"
+     " Vpid: %5d  Ppid: %5d  Tpid: %5d\n"
+     " Sid:  %5d  Nid:  %5d  Tid:  %5d  Rid: %5d\n"
+     " Apid: %s\n Dpid: %s\n CA:   %s",
+     device->CardIndex(), frontend?frontendInfo.name:"(unknown)",
+     channel->Vpid(), channel->Ppid(), channel->Tpid(),
+     channel->Sid(), channel->Nid(), channel->Tid(), channel->Rid(),
+     *apid_str, *dpid_str, *ca_str);
+
+  switch (frontendInfo.type) {
+    case FE_QPSK:
+      return cString::sprintf("Satellite Card %s\n\n"
+        " Frequency:   %5d Mhz    Source:       %s\n"
+        " Srate:       %5d        Polarization: %c\n"
+        " Inversion:   %-9s    Coderate:     %s\n",
+        *str, freq, *cSource::ToString(channel->Source()),
+        channel->Srate(), toupper(channel->Polarization()),
+        *convInversion(channel->Inversion()), 
+        *convCoderate(channel->CoderateH()));
+
+    case FE_QAM:
+      return cString::sprintf("Cable Card %s\n\n"
+        " Frequency:   %5d Mhz    Source:       %s\n"
+        " Srate:       %5d        Modulation:   %s\n"
+        " Inversion:   %-9s    Coderate:     %s\n",
+        *str, freq, *cSource::ToString(channel->Source()),
+        channel->Srate(), *convModulation(channel->Modulation()),
+        *convInversion(channel->Inversion()), 
+        *convCoderate(channel->CoderateH()));
+
+    default:
+      return cString::sprintf("Terrestrial Card %s\n\n"
+        " Frequency:   %5d Mhz    Transmission: %s\n"
+        " Bandwidth:   %-9s    Modulation:   %s\n"
+        " Inversion:   %-9s    Coderate:     %s (H), %s (L)\n"
+        " Hierarchy:   %-9s    Guard:    %s\n",
+        *str, freq, *convTransmission(channel->Transmission()),
+        *convBandwidth(channel->Bandwidth()),
+        *convModulation(channel->Modulation()),
+        *convInversion(channel->Inversion()), 
+        *convCoderate(channel->CoderateH()),
+        *convCoderate(channel->CoderateL()),
+        *convHierarchy(channel->Hierarchy()),
+        *convGuard(channel->Guard()));
+    }
+}
+
 cString getFrontendStatus(int cardIndex)
 {
   fe_status_t value;
--- femon-1.0.1/femontools.h	2006-06-18 00:46:57.000000000 +0200
+++ femon-1.0.1.4/femontools.h	2006-06-19 18:25:29.000000000 +0200
@@ -21,6 +21,7 @@ 
 #define FRONTEND_DEVICE "/dev/dvb/adapter%d/frontend%d"
 
 cString getFrontendName(int cardIndex = 0);
+cString getFrontendInfo(int cardIndex = 0);
 cString getFrontendStatus(int cardIndex = 0);
 uint16_t getSNR(int cardIndex = 0);
 uint16_t getSignal(int cardIndex = 0);