From a2296c6a0e5dbce963d5479ae394f9a62462569e Mon Sep 17 00:00:00 2001
From: Matthias Benesch <twoof7@freenet.de>
Date: Sat, 7 May 2011 19:49:13 +0200
Subject: [PATCH] libmythtv: Unicable / SCR / DIN EN 50494

Add support for Unicable / Satellite Channel Router / DIN EN 50494 standard.
---
 mythtv/libs/libmythtv/diseqc.cpp         |  194 ++++++++++++++++++++++++++----
 mythtv/libs/libmythtv/diseqc.h           |   55 +++++++--
 mythtv/libs/libmythtv/diseqcsettings.cpp |  168 +++++++++++++++++++++++++-
 mythtv/libs/libmythtv/diseqcsettings.h   |    8 ++
 4 files changed, 392 insertions(+), 33 deletions(-)

diff --git a/mythtv/libs/libmythtv/diseqc.cpp b/mythtv/libs/libmythtv/diseqc.cpp
index 7446a8f..98ed73a 100644
--- a/mythtv/libs/libmythtv/diseqc.cpp
+++ b/mythtv/libs/libmythtv/diseqc.cpp
@@ -68,6 +68,8 @@
 #define DISEQC_CMD_WRITE_N0   0x38
 #define DISEQC_CMD_WRITE_N1   0x39
 #define DISEQC_CMD_WRITE_FREQ 0x58
+#define DISEQC_CMD_ODU        0x5A
+#define DISEQC_CMD_ODU_MDU    0x5C
 #define DISEQC_CMD_HALT       0x60
 #define DISEQC_CMD_LMT_OFF    0x63
 #define DISEQC_CMD_LMT_E      0x66
@@ -2066,20 +2068,34 @@ void DiSEqCDevRotor::RotationComplete(void) const
  *  \brief LNB Class.
  */
 
-const DiSEqCDevDevice::TypeTable DiSEqCDevLNB::LNBTypeTable[5] =
+const DiSEqCDevDevice::TypeTable DiSEqCDevLNB::LNBTypeTable[6] =
 {
     { "fixed",        kTypeFixed                 },
     { "voltage",      kTypeVoltageControl        },
     { "voltage_tone", kTypeVoltageAndToneControl },
     { "bandstacked",  kTypeBandstacked           },
+    { "scr",          kTypeSCR                   },
     { QString::null,  kTypeVoltageAndToneControl },
 };
 
+const DiSEqCDevDevice::TypeTable DiSEqCDevLNB::SCRPositionTable[3] =
+{
+    { "A",            kTypeScrPosA },
+    { "B",            kTypeScrPosB },
+    { QString::null,  kTypeScrPosA },
+};
+
 DiSEqCDevLNB::DiSEqCDevLNB(DiSEqCDevTree &tree, uint devid)
-    : DiSEqCDevDevice(tree, devid),
-      m_type(kTypeVoltageAndToneControl), m_lof_switch(11700000),
-      m_lof_hi(10600000),       m_lof_lo(9750000),
-      m_pol_inv(false)
+    : DiSEqCDevDevice(tree, devid)
+    , m_type(kTypeVoltageAndToneControl)
+    , m_lof_switch(11700000)
+    , m_lof_hi(10600000)
+    , m_lof_lo(9750000)
+    , m_pol_inv(false)
+    , m_scr_userband(0)
+    , m_scr_frequency(1400)
+    , m_scr_position(kTypeScrPosA)
+    , m_scr_pin(-1)
 {
     Reset();
 }
@@ -2090,6 +2106,9 @@ bool DiSEqCDevLNB::Execute(const DiSEqCDevSettings&, const DTVMultiplex &tuning)
     if (m_type == kTypeVoltageAndToneControl)
         m_tree.SetTone(IsHighBand(tuning));
 
+    if (m_type == kTypeSCR)
+        return ExecuteSCR(tuning);
+
     return true;
 }
 
@@ -2103,6 +2122,10 @@ uint DiSEqCDevLNB::GetVoltage(const DiSEqCDevSettings&,
     {
         voltage = (IsHorizontal(tuning) ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13);
     }
+    else if (kTypeSCR == m_type)
+    {
+        voltage = SEC_VOLTAGE_13;
+    }
 
     return voltage;
 }
@@ -2114,7 +2137,9 @@ bool DiSEqCDevLNB::Load(void)
     query.prepare(
         "SELECT subtype,         lnb_lof_switch, "
         "       lnb_lof_hi,      lnb_lof_lo, "
-        "       lnb_pol_inv,     cmd_repeat "
+        "       lnb_pol_inv,     cmd_repeat, "
+        "       scr_userband,    scr_frequency, "
+        "       scr_position,    scr_pin "
         "FROM diseqc_tree "
         "WHERE diseqcid = :DEVID");
     query.bindValue(":DEVID", GetDeviceID());
@@ -2126,12 +2151,16 @@ bool DiSEqCDevLNB::Load(void)
     }
     else if (query.next())
     {
-        m_type       = LNBTypeFromString(query.value(0).toString());
-        m_lof_switch = query.value(1).toInt();
-        m_lof_hi     = query.value(2).toInt();
-        m_lof_lo     = query.value(3).toInt();
-        m_pol_inv    = query.value(4).toUInt();
-        m_repeat     = query.value(5).toUInt();
+        m_type          = LNBTypeFromString(query.value(0).toString());
+        m_lof_switch    = query.value(1).toInt();
+        m_lof_hi        = query.value(2).toInt();
+        m_lof_lo        = query.value(3).toInt();
+        m_pol_inv       = query.value(4).toUInt();
+        m_repeat        = query.value(5).toUInt();
+        m_scr_userband  = query.value(6).toUInt();
+        m_scr_frequency = query.value(7).toUInt();
+        m_scr_position  = SCRPositionFromString(query.value(8).toString());
+        m_scr_pin       = query.value(9).toInt();
     }
 
     return true;
@@ -2156,7 +2185,11 @@ bool DiSEqCDevLNB::Store(void) const
             "    lnb_lof_lo      = :LOFLO,   "
             "    lnb_lof_hi      = :LOFHI,   "
             "    lnb_pol_inv     = :POLINV,  "
-            "    cmd_repeat      = :REPEAT   "
+            "    cmd_repeat      = :REPEAT,   "
+            "    scr_userband    = :USERBAND, "
+            "    scr_frequency   = :FREQUENCY, "
+            "    scr_position    = :POSITION, "
+            "    scr_pin         = :PIN "
             "WHERE diseqcid = :DEVID");
         query.bindValue(":DEVID",   GetDeviceID());
     }
@@ -2167,25 +2200,31 @@ bool DiSEqCDevLNB::Store(void) const
             " ( parentid,      ordinal,         type, "
             "   description,   subtype,         lnb_lof_switch, "
             "   lnb_lof_lo,    lnb_lof_hi,      lnb_pol_inv, "
-            "   cmd_repeat ) "
+            "   cmd_repeat,    scr_userband,    scr_frequency, "
+            "   scr_position,  scr_pin) "
             "VALUES "
             " (:PARENT,       :ORDINAL,         'lnb', "
             "  :DESC,         :TYPE,            :LOFSW, "
             "  :LOFLO,        :LOFHI,           :POLINV, "
-            "  :REPEAT ) ");
+            "  :REPEAT,       :USERBAND,        :FREQUENCY,"
+            "  :POSITION,     :PIN ) ");
     }
 
     if (m_parent)
         query.bindValue(":PARENT", m_parent->GetDeviceID());
 
-    query.bindValue(":ORDINAL", m_ordinal);
-    query.bindValue(":DESC",    GetDescription());
-    query.bindValue(":TYPE",    type);
-    query.bindValue(":LOFSW",   m_lof_switch);
-    query.bindValue(":LOFLO",   m_lof_lo);
-    query.bindValue(":LOFHI",   m_lof_hi);
-    query.bindValue(":POLINV",  m_pol_inv);
-    query.bindValue(":REPEAT",  m_repeat);
+    query.bindValue(":ORDINAL",   m_ordinal);
+    query.bindValue(":DESC",      GetDescription());
+    query.bindValue(":TYPE",      type);
+    query.bindValue(":LOFSW",     m_lof_switch);
+    query.bindValue(":LOFLO",     m_lof_lo);
+    query.bindValue(":LOFHI",     m_lof_hi);
+    query.bindValue(":POLINV",    m_pol_inv);
+    query.bindValue(":REPEAT",    m_repeat);
+    query.bindValue(":USERBAND",  m_scr_userband);
+    query.bindValue(":FREQUENCY", m_scr_frequency);
+    query.bindValue(":POSITION",  SCRPositionToString(m_scr_position));
+    query.bindValue(":PIN",       m_scr_pin);
 
     // update dev_id
     if (!query.exec())
@@ -2211,6 +2250,7 @@ bool DiSEqCDevLNB::IsHighBand(const DTVMultiplex &tuning) const
 {
     switch (m_type)
     {
+        case kTypeSCR:
         case kTypeVoltageAndToneControl:
             return (tuning.frequency > m_lof_switch);
         case kTypeBandstacked:
@@ -2244,6 +2284,19 @@ bool DiSEqCDevLNB::IsHorizontal(const DTVMultiplex &tuning) const
 uint32_t DiSEqCDevLNB::GetIntermediateFrequency(
     const DiSEqCDevSettings&, const DTVMultiplex &tuning) const
 {
+    uint32_t frequency = GetFrequency(tuning);
+
+    if (m_type == kTypeSCR)
+    {
+        uint t = (frequency / 1000 + m_scr_frequency + 2) / 4 - 350;
+        frequency = ((t + 350) * 4) * 1000 - frequency;
+    }
+
+    return frequency;
+}
+
+uint32_t DiSEqCDevLNB::GetFrequency(const DTVMultiplex& tuning) const
+{
     (void) tuning;
 
     uint64_t abs_freq = tuning.frequency;
@@ -2251,3 +2304,98 @@ uint32_t DiSEqCDevLNB::GetIntermediateFrequency(
 
     return (lof > abs_freq) ? (lof - abs_freq) : (abs_freq - lof);
 }
+
+bool DiSEqCDevLNB::ExecuteSCR(const DTVMultiplex &tuning) const
+{
+    VERBOSE(VB_CHANNEL, LOC + QString("SCR: Tuning to %1kHz, %2, %3 using UB=%4, FREQ=%5MHz, POS=%6%7")
+            .arg(tuning.frequency)
+            .arg(IsHighBand(tuning) ? "HiBand" : "LoBand")
+            .arg(IsHorizontal(tuning) ? "H" : "V")
+            .arg(m_scr_userband)
+            .arg(m_scr_frequency)
+            .arg((m_scr_position == kTypeScrPosA) ? "A" : "B")
+            .arg((m_scr_pin >= 0 && m_scr_pin <= 255) ? QString(", PIN=%1").arg(m_scr_pin) : QString("")));
+
+    if (m_scr_userband > 7)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "SCR: Userband ID configuration out of range!");
+        return false;
+    }
+
+    uint32_t frequency = GetFrequency(tuning);
+    uint t = (frequency / 1000 + m_scr_frequency + 2) / 4 - 350;
+    if (t >= 1024)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "SCR: T out of range!");
+        return false;
+    }
+
+    // build command
+    unsigned char data[3];
+    data[0] = t >> 8 | m_scr_userband << 5;
+    data[1] = t & 0x00FF;
+
+    if (IsHighBand(tuning))
+        data[0] |= (1 << 2);
+
+    if (IsHorizontal(tuning))
+        data[0] |= (1 << 3);
+
+    if (m_scr_position == kTypeScrPosB)
+        data[0] |= (1 << 4);
+
+    // send command
+    if (m_scr_pin >= 0 && m_scr_pin <= 255)
+    {
+        data[2] = m_scr_pin;
+        return SendSCRCommand(DISEQC_CMD_ODU_MDU, 3, data);
+    } else {
+        return SendSCRCommand(DISEQC_CMD_ODU, 2, data);
+    }
+}
+
+bool DiSEqCDevLNB::PowerOffSCR() const
+{
+    VERBOSE(VB_CHANNEL, LOC + QString("SCR: Power off UB=%1%7")
+            .arg(m_scr_userband)
+            .arg((m_scr_pin >= 0 && m_scr_pin <= 255)
+                 ? QString(", PIN=%1").arg(m_scr_pin)
+                 : QString("")));
+
+    if (m_scr_userband > 7)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "SCR: Userband ID configuration out of range!");
+        return false;
+    }
+
+    // build command
+    unsigned char data[3];
+    data[0] = (uint8_t) (m_scr_userband << 5);
+    data[1] = 0x00;
+
+    // send command
+    if (m_scr_pin >= 0 && m_scr_pin <= 255)
+    {
+        data[2] = m_scr_pin;
+        return SendSCRCommand(DISEQC_CMD_ODU_MDU, 3, data);
+    } else {
+        return SendSCRCommand(DISEQC_CMD_ODU, 2, data);
+    }
+}
+
+bool DiSEqCDevLNB::SendSCRCommand(uint cmd, uint data_len, unsigned char *data) const
+{
+    // power on bus
+    if (!m_tree.SetVoltage(SEC_VOLTAGE_18))
+        return false;
+    usleep(DISEQC_SHORT_WAIT);
+
+    // send command
+    bool ret = m_tree.SendCommand(DISEQC_ADR_SW_ALL, cmd, 0, data_len, data);
+
+    // power off bus
+    if (!m_tree.SetVoltage(SEC_VOLTAGE_13))
+        return false;
+
+    return ret;
+}
diff --git a/mythtv/libs/libmythtv/diseqc.h b/mythtv/libs/libmythtv/diseqc.h
index 643dcc8..f418dfd 100644
--- a/mythtv/libs/libmythtv/diseqc.h
+++ b/mythtv/libs/libmythtv/diseqc.h
@@ -142,7 +142,12 @@ class DiSEqCDevDevice
     virtual bool Store(void) const = 0;
 
     // Sets
-    enum dvbdev_t { kTypeSwitch = 0, kTypeRotor = 1, kTypeLNB = 2, };
+    enum dvbdev_t 
+    {
+        kTypeSwitch = 0,
+        kTypeRotor = 1,
+        kTypeLNB = 2,
+    };
     void SetDeviceType(dvbdev_t type)        { m_dev_type = type;    }
     void SetParent(DiSEqCDevDevice* parent)  { m_parent   = parent;  }
     void SetOrdinal(uint ordinal)            { m_ordinal  = ordinal; }
@@ -376,12 +381,22 @@ class DiSEqCDevLNB : public DiSEqCDevDevice
         kTypeVoltageControl        = 1,
         kTypeVoltageAndToneControl = 2,
         kTypeBandstacked           = 3,
+        kTypeSCR                   = 4,
     };
-    void SetType(dvbdev_lnb_t type)       { m_type       = type;       }
-    void SetLOFSwitch(uint lof_switch)    { m_lof_switch = lof_switch; }
-    void SetLOFHigh(  uint lof_hi)        { m_lof_hi     = lof_hi;     }
-    void SetLOFLow(   uint lof_lo)        { m_lof_lo     = lof_lo;     }
-    void SetPolarityInverted(bool inv)    { m_pol_inv    = inv;        }
+    enum dvbdev_pos_t
+    {
+        kTypeScrPosA               = 0,
+        kTypeScrPosB               = 1,
+    };
+    void SetType(dvbdev_lnb_t type)       { m_type          = type;       }
+    void SetLOFSwitch(uint lof_switch)    { m_lof_switch    = lof_switch; }
+    void SetLOFHigh(  uint lof_hi)        { m_lof_hi        = lof_hi;     }
+    void SetLOFLow(   uint lof_lo)        { m_lof_lo        = lof_lo;     }
+    void SetPolarityInverted(bool inv)    { m_pol_inv       = inv;        }
+    void SetUserBand(uint userband)       { m_scr_userband  = userband;   }
+    void SetFrequency(uint freq)          { m_scr_frequency = freq;       }
+    void SetPosition(dvbdev_pos_t pos)    { m_scr_position  = pos;        }
+    void SetPIN(int pin)                  { m_scr_pin       = pin;        }
 
     // Gets
     dvbdev_lnb_t GetType(void)      const { return m_type;             }
@@ -389,6 +404,11 @@ class DiSEqCDevLNB : public DiSEqCDevDevice
     uint         GetLOFHigh(void)   const { return m_lof_hi;           }
     uint         GetLOFLow(void)    const { return m_lof_lo;           }
     bool         IsPolarityInverted(void) const { return m_pol_inv;    }
+    uint         GetUserBand(void) const  { return m_scr_userband;     }
+    uint         GetFrequency(void) const { return m_scr_frequency;    }
+    dvbdev_pos_t GetPosition(void) const  { return m_scr_position;     }
+    int          GetPIN(void) const       { return m_scr_pin;          }
+
     bool         IsHighBand(const DTVMultiplex&) const;
     bool         IsHorizontal(const DTVMultiplex&) const;
     uint32_t     GetIntermediateFrequency(const DiSEqCDevSettings&,
@@ -403,6 +423,19 @@ class DiSEqCDevLNB : public DiSEqCDevDevice
     static dvbdev_lnb_t LNBTypeFromString(const QString &type)
         { return (dvbdev_lnb_t) TableFromString(type, LNBTypeTable); }
 
+    static QString SCRPositionToString(dvbdev_pos_t pos)
+        { return TableToString((uint)pos, SCRPositionTable); }
+
+    static dvbdev_pos_t SCRPositionFromString(const QString &pos)
+        { return (dvbdev_pos_t) TableFromString(pos, SCRPositionTable); }
+
+  protected:
+    uint32_t     GetFrequency(const DTVMultiplex&) const;
+    bool         ExecuteSCR(const DTVMultiplex&) const;
+    bool         PowerOffSCR() const;
+    bool         SendSCRCommand(uint cmd, uint data_len = 0,
+                                unsigned char *data = NULL) const;
+
   private:
     dvbdev_lnb_t m_type;
     uint         m_lof_switch;
@@ -412,8 +445,14 @@ class DiSEqCDevLNB : public DiSEqCDevDevice
     /// on each reflection, so antenna systems with an even number
     /// of reflectors will need to set this value.
     bool         m_pol_inv;
-
-    static const TypeTable LNBTypeTable[5];
+    /// Satellite channel router (SCR)
+    uint         m_scr_userband;  /* 0-7 */
+    uint         m_scr_frequency;
+    dvbdev_pos_t m_scr_position;  /* A|B */
+    int          m_scr_pin;       /* 0-255, -1=disabled */
+
+    static const TypeTable LNBTypeTable[6];
+    static const TypeTable SCRPositionTable[3];
 };
 
 #endif // _DISEQC_H_
diff --git a/mythtv/libs/libmythtv/diseqcsettings.cpp b/mythtv/libs/libmythtv/diseqcsettings.cpp
index f01b857..32d5046 100644
--- a/mythtv/libs/libmythtv/diseqcsettings.cpp
+++ b/mythtv/libs/libmythtv/diseqcsettings.cpp
@@ -668,6 +668,8 @@ class LNBTypeSetting : public ComboBoxSetting, public Storage
                                      kTypeVoltageAndToneControl));
         addSelection(DeviceTree::tr("Bandstacked"),
                      QString::number((uint) DiSEqCDevLNB::kTypeBandstacked));
+        addSelection(DeviceTree::tr("Unicable / SCR"),
+                     QString::number((uint) DiSEqCDevLNB::kTypeSCR));
     }
 
     virtual void Load(void)
@@ -809,6 +811,127 @@ class LNBPolarityInvertedSetting : public CheckBoxSetting, public Storage
     DiSEqCDevLNB &m_lnb;
 };
 
+//////////////////////////////////////// LNBSCRUserBandSetting
+
+class LNBSCRUserBandSetting : public SpinBoxSetting, public Storage
+{
+  public:
+    LNBSCRUserBandSetting(DiSEqCDevLNB &lnb) :
+        SpinBoxSetting(this, 0, 7, 1), m_lnb(lnb)
+    {
+        setLabel(DeviceTree::tr("SCR ID"));
+        QString help = DeviceTree::tr(
+            "Unicable / SCR userband ID (0-7)");
+        setHelpText(help);
+    }
+
+    virtual void Load(void)
+    {
+        setValue(m_lnb.GetUserBand());
+    }
+
+    virtual void Save(void)
+    {
+        m_lnb.SetUserBand(intValue());
+    }
+
+    virtual void Save(QString /*destination*/) { }
+
+  private:
+    DiSEqCDevLNB &m_lnb;
+};
+
+//////////////////////////////////////// LNBSCRFrequencySetting
+
+class LNBSCRFrequencySetting : public LineEditSetting, public Storage
+{
+  public:
+    LNBSCRFrequencySetting(DiSEqCDevLNB &lnb) : LineEditSetting(this), m_lnb(lnb)
+    {
+        setLabel(DeviceTree::tr("SCR frequency (MHz)"));
+        QString help = DeviceTree::tr(
+            "Unicable / SCR userband frequency (950 - 2150MHz)");
+        setHelpText(help);
+    }
+
+    virtual void Load(void)
+    {
+        setValue(QString::number(m_lnb.GetFrequency()));
+    }
+
+    virtual void Save(void)
+    {
+        m_lnb.SetFrequency(getValue().toUInt());
+    }
+
+    virtual void Save(QString /*destination*/) { }
+
+  private:
+    DiSEqCDevLNB &m_lnb;
+};
+
+//////////////////////////////////////// LNBSCRPositionSetting
+
+class LNBSCRPositionSetting : public ComboBoxSetting, public Storage
+{
+  public:
+    LNBSCRPositionSetting(DiSEqCDevLNB &lnb) : ComboBoxSetting(this), m_lnb(lnb)
+    {
+        setLabel(DeviceTree::tr("SCR Position"));
+        QString help = DeviceTree::tr(
+            "Unicable / SCR userband satellite position (A/B)");
+        setHelpText(help);
+        addSelection(DiSEqCDevLNB::SCRPositionToString(DiSEqCDevLNB::kTypeScrPosA),
+                     QString::number((uint) DiSEqCDevLNB::kTypeScrPosA));
+        addSelection(DiSEqCDevLNB::SCRPositionToString(DiSEqCDevLNB::kTypeScrPosB),
+                     QString::number((uint) DiSEqCDevLNB::kTypeScrPosB));
+    }
+
+    virtual void Load(void)
+    {
+        setValue(getValueIndex(QString::number((uint)m_lnb.GetPosition())));
+    }
+
+    virtual void Save(void)
+    {
+        m_lnb.SetPosition((DiSEqCDevLNB::dvbdev_pos_t)getValue().toUInt());
+    }
+
+    virtual void Save(QString /*destination*/) { }
+
+  private:
+    DiSEqCDevLNB &m_lnb;
+};
+
+//////////////////////////////////////// LNBSCRPINSetting
+
+class LNBSCRPINSetting : public LineEditSetting, public Storage
+{
+  public:
+    LNBSCRPINSetting(DiSEqCDevLNB &lnb) : LineEditSetting(this), m_lnb(lnb)
+    {
+        setLabel(DeviceTree::tr("SCR PIN code"));
+        QString help = DeviceTree::tr(
+            "Unicable / SCR PIN code (-1 disabled, 0 - 255)");
+        setHelpText(help);
+    }
+
+    virtual void Load(void)
+    {
+        setValue(QString::number(m_lnb.GetPIN()));
+    }
+
+    virtual void Save(void)
+    {
+        m_lnb.SetPIN(getValue().toInt());
+    }
+
+    virtual void Save(QString /*destination*/) { }
+
+  private:
+    DiSEqCDevLNB &m_lnb;
+};
+
 //////////////////////////////////////// LNBConfig
 
 LNBConfig::LNBConfig(DiSEqCDevLNB &lnb)
@@ -830,6 +953,15 @@ LNBConfig::LNBConfig(DiSEqCDevLNB &lnb)
     group->addChild(m_lof_hi);
     m_pol_inv = new LNBPolarityInvertedSetting(lnb);
     group->addChild(m_pol_inv);
+    m_scr_ub = new LNBSCRUserBandSetting(lnb);
+    group->addChild(m_scr_ub);
+    m_scr_freq = new LNBSCRFrequencySetting(lnb);
+    group->addChild(m_scr_freq);
+    m_scr_pos = new LNBSCRPositionSetting(lnb);
+    group->addChild(m_scr_pos);
+    m_scr_pin = new LNBSCRPINSetting(lnb);
+    group->addChild(m_scr_pin);
+
     connect(m_type, SIGNAL(valueChanged(const QString&)),
             this,   SLOT(  UpdateType(  void)));
     connect(preset, SIGNAL(valueChanged(const QString&)),
@@ -862,6 +994,10 @@ void LNBConfig::SetPreset(const QString &value)
         m_lof_hi->setEnabled(false);
         m_lof_lo->setEnabled(false);
         m_pol_inv->setEnabled(false);
+        m_scr_ub->setEnabled(false);
+        m_scr_freq->setEnabled(false);
+        m_scr_pos->setEnabled(false);
+        m_scr_pin->setEnabled(false);
     }
 }
 
@@ -878,18 +1014,40 @@ void LNBConfig::UpdateType(void)
             m_lof_hi->setEnabled(false);
             m_lof_lo->setEnabled(true);
             m_pol_inv->setEnabled(true);
+            m_scr_ub->setEnabled(false);
+            m_scr_freq->setEnabled(false);
+            m_scr_pos->setEnabled(false);
+            m_scr_pin->setEnabled(false);
             break;
         case DiSEqCDevLNB::kTypeVoltageAndToneControl:
             m_lof_switch->setEnabled(true);
             m_lof_hi->setEnabled(true);
             m_lof_lo->setEnabled(true);
             m_pol_inv->setEnabled(true);
+            m_scr_ub->setEnabled(false);
+            m_scr_freq->setEnabled(false);
+            m_scr_pos->setEnabled(false);
+            m_scr_pin->setEnabled(false);
             break;
         case DiSEqCDevLNB::kTypeBandstacked:
             m_lof_switch->setEnabled(false);
             m_lof_hi->setEnabled(true);
             m_lof_lo->setEnabled(true);
             m_pol_inv->setEnabled(true);
+            m_scr_ub->setEnabled(false);
+            m_scr_freq->setEnabled(false);
+            m_scr_pos->setEnabled(false);
+            m_scr_pin->setEnabled(false);
+            break;
+        case DiSEqCDevLNB::kTypeSCR:
+            m_lof_switch->setEnabled(true);
+            m_lof_hi->setEnabled(true);
+            m_lof_lo->setEnabled(true);
+            m_pol_inv->setEnabled(true);
+            m_scr_ub->setEnabled(true);
+            m_scr_freq->setEnabled(true);
+            m_scr_pos->setEnabled(true);
+            m_scr_pin->setEnabled(true);
             break;
     }
 }
@@ -1397,8 +1555,10 @@ bool convert_diseqc_db(void)
 
     MSqlQuery iquery(MSqlQuery::InitCon());
     iquery.prepare(
-        "SELECT cardinputid,    diseqc_port, diseqc_pos, "
-        "       lnb_lof_switch, lnb_lof_hi,  lnb_lof_lo  "
+        "SELECT cardinputid,    diseqc_port,   diseqc_pos, "
+        "       lnb_lof_switch, lnb_lof_hi,    lnb_lof_lo,  "
+        "       scr_userband,   scr_frequency, scr_position,"
+        "       scr_pin "
         "FROM cardinput "
         "WHERE cardinput.cardid = :CARDID");
 
@@ -1628,6 +1788,10 @@ bool convert_diseqc_db(void)
                 lnb->SetLOFSwitch(iquery.value(3).toUInt());
                 lnb->SetLOFHigh(iquery.value(4).toUInt());
                 lnb->SetLOFLow(iquery.value(5).toUInt());
+                lnb->SetUserBand(iquery.value(6).toUInt());
+                lnb->SetFrequency(iquery.value(7).toUInt());
+                lnb->SetPosition(DiSEqCDevLNB::SCRPositionFromString(iquery.value(8).toString()));
+                lnb->SetPIN(iquery.value(9).toInt());
             }
 
             // save settings
diff --git a/mythtv/libs/libmythtv/diseqcsettings.h b/mythtv/libs/libmythtv/diseqcsettings.h
index de78a71..973efea 100644
--- a/mythtv/libs/libmythtv/diseqcsettings.h
+++ b/mythtv/libs/libmythtv/diseqcsettings.h
@@ -78,6 +78,10 @@ class LNBLOFSwitchSetting;
 class LNBLOFLowSetting;
 class LNBLOFHighSetting;
 class LNBPolarityInvertedSetting;
+class LNBSCRUserBandSetting;
+class LNBSCRFrequencySetting;
+class LNBSCRPositionSetting;
+class LNBSCRPINSetting;
 
 class LNBConfig : public QObject, public ConfigurationWizard
 {
@@ -96,6 +100,10 @@ class LNBConfig : public QObject, public ConfigurationWizard
     LNBLOFLowSetting    *m_lof_lo;
     LNBLOFHighSetting   *m_lof_hi;
     LNBPolarityInvertedSetting *m_pol_inv;
+    LNBSCRUserBandSetting  *m_scr_ub;
+    LNBSCRFrequencySetting *m_scr_freq;
+    LNBSCRPositionSetting  *m_scr_pos;
+    LNBSCRPINSetting       *m_scr_pin;
 };
 
 class DeviceTree : public ListBoxSetting, public Storage
-- 
1.7.4.1

