Merge remote-tracking branch 'origin/obi/master-20110412'
[enigma2.git] / lib / dvb / frontend.cpp
index 519b5fee87255b9874bb8da20eb8d99f1932d552..57188963cebd10f175d8425517f0b663b2ad26b9 100644 (file)
@@ -453,8 +453,8 @@ DEFINE_REF(eDVBFrontend);
 
 int eDVBFrontend::PriorityOrder=0;
 
-eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok, bool simulate)
-       :m_simulate(simulate), m_enabled(false), m_type(-1), m_dvbid(fe), m_slotid(fe)
+eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok, bool simulate, eDVBFrontend *simulate_fe)
+       :m_simulate(simulate), m_enabled(false), m_type(-1), m_simulate_fe(simulate_fe), m_dvbid(fe), m_slotid(fe)
        ,m_fd(-1), m_rotor_mode(false), m_need_rotor_workaround(false), m_can_handle_dvbs2(false)
        ,m_state(stateClosed), m_timeout(0), m_tuneTimer(0)
 #if HAVE_DVB_API_VERSION < 3
@@ -503,10 +503,10 @@ int eDVBFrontend::openFrontend()
 #else
        dvb_frontend_info fe_info;
 #endif
-       eDebugNoSimulate("opening frontend %d", m_dvbid);
-       if (m_fd < 0)
+       if (!m_simulate)
        {
-               if (!m_simulate || m_type == -1)
+               eDebug("opening frontend %d", m_dvbid);
+               if (m_fd < 0)
                {
                        m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
                        if (m_fd < 0)
@@ -515,74 +515,73 @@ int eDVBFrontend::openFrontend()
                                return -1;
                        }
                }
-       }
-       else
-               eWarning("frontend %d already opened", m_dvbid);
-       if (m_type == -1)
-       {
-               if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
+               else
+                       eWarning("frontend %d already opened", m_dvbid);
+               if (m_type == -1)
                {
-                       eWarning("ioctl FE_GET_INFO failed");
-                       ::close(m_fd);
-                       m_fd = -1;
-                       return -1;
-               }
+                       if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
+                       {
+                               eWarning("ioctl FE_GET_INFO failed");
+                               ::close(m_fd);
+                               m_fd = -1;
+                               return -1;
+                       }
 
-               switch (fe_info.type)
-               {
-               case FE_QPSK:
-                       m_type = iDVBFrontend::feSatellite;
-                       break;
-               case FE_QAM:
-                       m_type = iDVBFrontend::feCable;
-                       break;
-               case FE_OFDM:
-                       m_type = iDVBFrontend::feTerrestrial;
-                       break;
-               default:
-                       eWarning("unknown frontend type.");
-                       ::close(m_fd);
-                       m_fd = -1;
-                       return -1;
+                       switch (fe_info.type)
+                       {
+                       case FE_QPSK:
+                               m_type = iDVBFrontend::feSatellite;
+                               break;
+                       case FE_QAM:
+                               m_type = iDVBFrontend::feCable;
+                               break;
+                       case FE_OFDM:
+                               m_type = iDVBFrontend::feTerrestrial;
+                               break;
+                       default:
+                               eWarning("unknown frontend type.");
+                               ::close(m_fd);
+                               m_fd = -1;
+                               return -1;
+                       }
+                       if (m_simulate_fe)
+                               m_simulate_fe->m_type = m_type;
+                       eDebugNoSimulate("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
                }
-               eDebugNoSimulate("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
-       }
 
 #if HAVE_DVB_API_VERSION < 3
-       if (m_type == iDVBFrontend::feSatellite)
-       {
-                       if (m_secfd < 0)
-                       {
-                               if (!m_simulate)
+               if (m_type == iDVBFrontend::feSatellite)
+               {
+                               if (m_secfd < 0)
                                {
-                                       m_secfd = ::open(m_sec_filename, O_RDWR);
-                                       if (m_secfd < 0)
+                                       if (!m_simulate)
                                        {
-                                               eWarning("failed! (%s) %m", m_sec_filename);
-                                               ::close(m_fd);
-                                               m_fd=-1;
-                                               return -1;
+                                               m_secfd = ::open(m_sec_filename, O_RDWR);
+                                               if (m_secfd < 0)
+                                               {
+                                                       eWarning("failed! (%s) %m", m_sec_filename);
+                                                       ::close(m_fd);
+                                                       m_fd=-1;
+                                                       return -1;
+                                               }
                                        }
                                }
-                       }
-                       else
-                               eWarning("sec %d already opened", m_dvbid);
-       }
+                               else
+                                       eWarning("sec %d already opened", m_dvbid);
+               }
 #endif
 
-       setTone(iDVBFrontend::toneOff);
-       setVoltage(iDVBFrontend::voltageOff);
-
-       if (!m_simulate)
-       {
                m_sn = eSocketNotifier::create(eApp, m_fd, eSocketNotifier::Read, false);
                CONNECT(m_sn->activated, eDVBFrontend::feEvent);
        }
 
+       setTone(iDVBFrontend::toneOff);
+       setVoltage(iDVBFrontend::voltageOff);
+
        return 0;
 }
 
-int eDVBFrontend::closeFrontend(bool force)
+int eDVBFrontend::closeFrontend(bool force, bool no_delayed)
 {
        if (!force && m_data[CUR_VOLTAGE] != -1 && m_data[CUR_VOLTAGE] != iDVBFrontend::voltageOff)
        {
@@ -605,11 +604,34 @@ int eDVBFrontend::closeFrontend(bool force)
                eDebugNoSimulate("close frontend %d", m_dvbid);
                if (m_data[SATCR] != -1)
                {
-                       turnOffSatCR(m_data[SATCR]);
+                       if (!no_delayed)
+                       {
+                               m_sec->prepareTurnOffSatCR(*this, m_data[SATCR]);
+                               m_tuneTimer->start(0, true);
+                               if(!m_tuneTimer->isActive())
+                               {
+                                       int timeout=0;
+                                       eDebug("[turnOffSatCR] no mainloop");
+                                       while(true)
+                                       {
+                                               timeout = tuneLoopInt();
+                                               if (timeout == -1)
+                                                       break;
+                                               usleep(timeout*1000); // blockierendes wait.. eTimer gibts ja nicht mehr
+                                       }
+                               }
+                               else
+                                       eDebug("[turnOffSatCR] running mainloop");
+                               return 0;
+                       }
+                       else
+                               m_data[ROTOR_CMD] = -1;
                }
+
                setTone(iDVBFrontend::toneOff);
                setVoltage(iDVBFrontend::voltageOff);
                m_tuneTimer->stop();
+
                if (m_sec && !m_simulate)
                        m_sec->setRotorMoving(m_slotid, false);
                if (!::close(m_fd))
@@ -790,7 +812,7 @@ int eDVBFrontend::readFrontendData(int type)
                                        float fval1 = SDS_SNRE / 268435456.0,
                                                  fval2, fval3, fval4;
 
-                                       if (parm_u_qpsk_fec_inner <= FEC_S2_QPSK_9_10) // DVB-S2 QPSK
+                                       if (oparm.sat.modulation == eDVBFrontendParametersSatellite::Modulation_QPSK)
                                        {
                                                fval2 = 6.76;
                                                fval3 = 4.35;
@@ -883,6 +905,19 @@ int eDVBFrontend::readFrontendData(int type)
                        }
                        else if (strstr(m_description, "BCM4506") || strstr(m_description, "BCM4505"))
                                ret = (snr * 100) >> 8;
+                       else if (!strcmp(m_description, "CXD1981"))
+                       {
+                               int mse = (~snr) & 0xFF;
+                               switch (parm_u_qam_modulation) {
+                                       case QAM_16:
+                                       case QAM_64:
+                                       case QAM_256: ret = (int)(-950 * log(((double)mse) / 760)); break;
+                                       case QAM_32:
+                                       case QAM_128: ret = (int)(-875 * log(((double)mse) / 650)); break;
+
+                                       default: break;
+                               }
+                       }
 
                        if (type == signalQuality)
                        {
@@ -1489,9 +1524,14 @@ bool eDVBFrontend::setSecSequencePos(int steps)
        return true;
 }
 
-void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
+void eDVBFrontend::tuneLoop()
 {
-       int delay=0;
+       tuneLoopInt();
+}
+
+int eDVBFrontend::tuneLoopInt()  // called by m_tuneTimer
+{
+       int delay=-1;
        eDVBFrontend *sec_fe = this;
        eDVBRegisteredFrontend *regFE = 0;
        long tmp = m_data[LINKED_PREV_PTR];
@@ -1521,6 +1561,7 @@ void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
        {
                long *sec_fe_data = sec_fe->m_data;
 //             eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
+               delay = 0;
                switch (m_sec_sequence.current()->cmd)
                {
                        case eSecCommand::SLEEP:
@@ -1818,11 +1859,11 @@ void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
                                                int slotid = sec_fe->m_slotid;
                                                // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
                                                if (slotid < 2)
-                                                       sprintf(dev, "/dev/i2c/%d", slotid);
+                                                       sprintf(dev, "/dev/i2c-%d", slotid);
                                                else if (slotid == 2)
-                                                       sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
+                                                       sprintf(dev, "/dev/i2c-2"); // first nim socket on DM8000 use /dev/i2c-2
                                                else if (slotid == 3)
-                                                       sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
+                                                       sprintf(dev, "/dev/i2c-4"); // second nim socket on DM8000 use /dev/i2c-4
                                                int fd = ::open(dev, O_RDWR);
 
                                                unsigned char data[2];
@@ -1847,6 +1888,13 @@ void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
                                ++m_sec_sequence.current();
                                break;
                        }
+                       case eSecCommand::DELAYED_CLOSE_FRONTEND:
+                       {
+                               eDebugNoSimulate("[SEC] delayed close frontend");
+                               closeFrontend(false, true);
+                               ++m_sec_sequence.current();
+                               break;
+                       }
                        default:
                                eDebugNoSimulate("[SEC] unhandled sec command %d",
                                        ++m_sec_sequence.current()->cmd);
@@ -1859,6 +1907,7 @@ void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
                regFE->dec_use();
        if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
                tuneLoop();
+       return delay;
 }
 
 void eDVBFrontend::setFrontend(bool recvEvents)
@@ -2061,8 +2110,8 @@ RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm,
                                        return -EINVAL;
                        }
 #if HAVE_DVB_API_VERSION < 5
-                       parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
-                       parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
+                       parm_inversion = (fe_spectral_inversion_t)((feparm.rolloff << 2) | parm_inversion); // Hack.. we use bit 2..3 of inversion param for rolloff
+                       parm_inversion = (fe_spectral_inversion_t)((feparm.pilot << 4) | parm_inversion); // Hack.. we use bit 4..5 of inversion param for pilot
                        if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation_8PSK) 
                        {
                                parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
@@ -2594,9 +2643,12 @@ RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
        return 0;
 }
 
-RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
+RESULT eDVBFrontend::setSecSequence(eSecCommandList &list)
 {
-       m_sec_sequence = list;
+       if (m_data[SATCR] != -1 && m_sec_sequence.current() != m_sec_sequence.end())
+               m_sec_sequence.push_back(list);
+       else
+               m_sec_sequence = list;
        return 0;
 }
 
@@ -2647,17 +2699,23 @@ int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
 
 bool eDVBFrontend::setSlotInfo(ePyObject obj)
 {
-       ePyObject Id, Descr, Enabled, IsDVBS2;
-       if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
+       ePyObject Id, Descr, Enabled, IsDVBS2, frontendId;
+       if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 5)
                goto arg_error;
        Id = PyTuple_GET_ITEM(obj, 0);
        Descr = PyTuple_GET_ITEM(obj, 1);
        Enabled = PyTuple_GET_ITEM(obj, 2);
        IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
-       if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
+       frontendId = PyTuple_GET_ITEM(obj, 4);
+       m_slotid = PyInt_AsLong(Id);
+       if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2) || !PyInt_Check(frontendId))
                goto arg_error;
        strcpy(m_description, PyString_AS_STRING(Descr));
-       m_slotid = PyInt_AsLong(Id);
+       if (PyInt_AsLong(frontendId) == -1 || PyInt_AsLong(frontendId) != m_dvbid) {
+//             eDebugNoSimulate("skip slotinfo for slotid %d, descr %s",
+//                     m_slotid, m_description);
+               return false;
+       }
        m_enabled = Enabled == Py_True;
        // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
        m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
@@ -2673,42 +2731,3 @@ arg_error:
                "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
        return false;
 }
-
-RESULT eDVBFrontend::turnOffSatCR(int satcr)
-{
-       eSecCommandList sec_sequence;
-       // check if voltage is disabled
-       eSecCommand::pair compare;
-       compare.steps = +9;     //nothing to do
-       compare.voltage = iDVBFrontend::voltageOff;
-       sec_sequence.push_back( eSecCommand(eSecCommand::IF_NOT_VOLTAGE_GOTO, compare) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 50 ) );
-
-       sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage18_5) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SET_TONE, iDVBFrontend::toneOff) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 250) );
-
-       eDVBDiseqcCommand diseqc;
-       memset(diseqc.data, 0, MAX_DISEQC_LENGTH);
-       diseqc.len = 5;
-       diseqc.data[0] = 0xE0;
-       diseqc.data[1] = 0x10;
-       diseqc.data[2] = 0x5A;
-       diseqc.data[3] = satcr << 5;
-       diseqc.data[4] = 0x00;
-
-       sec_sequence.push_back( eSecCommand(eSecCommand::SEND_DISEQC, diseqc) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 50+20+14*diseqc.len) );
-       sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
-       setSecSequence(sec_sequence);
-       return 0;
-}
-
-RESULT eDVBFrontend::ScanSatCR()
-{
-       setFrontend();
-       usleep(20000);
-       setTone(iDVBFrontend::toneOff);
-       return 0;
-}