+ long freq_offset=0;
+ const char *tmp=0;
+ fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
+ int frequency = parm_frequency + freq_offset;
+ PutToDict(dict, "frequency", frequency);
+ PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
+ switch(parm_u_qpsk_fec_inner)
+ {
+ case FEC_1_2:
+ tmp = "FEC_1_2";
+ break;
+ case FEC_2_3:
+ tmp = "FEC_2_3";
+ break;
+ case FEC_3_4:
+ tmp = "FEC_3_4";
+ break;
+ case FEC_5_6:
+ tmp = "FEC_5_6";
+ break;
+ case FEC_7_8:
+ tmp = "FEC_7_8";
+ break;
+ case FEC_NONE:
+ tmp = "FEC_NONE";
+ default:
+ case FEC_AUTO:
+ tmp = "FEC_AUTO";
+ break;
+#if HAVE_DVB_API_VERSION >=3
+ case FEC_S2_8PSK_1_2:
+ case FEC_S2_QPSK_1_2:
+ tmp = "FEC_1_2";
+ break;
+ case FEC_S2_8PSK_2_3:
+ case FEC_S2_QPSK_2_3:
+ tmp = "FEC_2_3";
+ break;
+ case FEC_S2_8PSK_3_4:
+ case FEC_S2_QPSK_3_4:
+ tmp = "FEC_3_4";
+ break;
+ case FEC_S2_8PSK_5_6:
+ case FEC_S2_QPSK_5_6:
+ tmp = "FEC_5_6";
+ break;
+ case FEC_S2_8PSK_7_8:
+ case FEC_S2_QPSK_7_8:
+ tmp = "FEC_7_8";
+ break;
+ case FEC_S2_8PSK_8_9:
+ case FEC_S2_QPSK_8_9:
+ tmp = "FEC_8_9";
+ break;
+ case FEC_S2_8PSK_3_5:
+ case FEC_S2_QPSK_3_5:
+ tmp = "FEC_3_5";
+ break;
+ case FEC_S2_8PSK_4_5:
+ case FEC_S2_QPSK_4_5:
+ tmp = "FEC_4_5";
+ break;
+ case FEC_S2_8PSK_9_10:
+ case FEC_S2_QPSK_9_10:
+ tmp = "FEC_9_10";
+ break;
+#endif
+ }
+ PutToDict(dict, "fec_inner", tmp);
+#if HAVE_DVB_API_VERSION >=3
+ PutToDict(dict, "modulation",
+ parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
+ if (parm_u_qpsk_fec_inner > FEC_AUTO)
+ {
+ switch(parm_inversion & 0xc)
+ {
+ default: // unknown rolloff
+ case 0: // 0.35
+ tmp = "ROLLOFF_0_35";
+ break;
+ case 4: // 0.25
+ tmp = "ROLLOFF_0_25";
+ break;
+ case 8: // 0.20
+ tmp = "ROLLOFF_0_20";
+ break;
+ }
+ PutToDict(dict, "rolloff", tmp);
+ if (parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10)
+ {
+ switch(parm_inversion & 0x30)
+ {
+ case 0: // pilot off
+ tmp = "PILOT_OFF";
+ break;
+ case 0x10: // pilot on
+ tmp = "PILOT_ON";
+ break;
+ case 0x20: // pilot auto
+ tmp = "PILOT_AUTO";
+ break;
+ }
+ PutToDict(dict, "pilot", tmp);
+ }
+ tmp = "DVB-S2";
+ }
+ else
+ tmp = "DVB-S";
+#else
+ PutToDict(dict, "modulation", "QPSK" );
+ tmp = "DVB-S";
+#endif
+ PutToDict(dict, "system", tmp);
+}
+
+void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
+{
+ const char *tmp=0;
+#if HAVE_DVB_API_VERSION < 3
+ PutToDict(dict, "frequency", parm_frequency);
+#else
+ PutToDict(dict, "frequency", parm_frequency/1000);
+#endif
+ PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
+ switch(parm_u_qam_fec_inner)
+ {
+ case FEC_NONE:
+ tmp = "FEC_NONE";
+ break;
+ case FEC_1_2:
+ tmp = "FEC_1_2";
+ break;
+ case FEC_2_3:
+ tmp = "FEC_2_3";
+ break;
+ case FEC_3_4:
+ tmp = "FEC_3_4";
+ break;
+ case FEC_5_6:
+ tmp = "FEC_5_6";
+ break;
+ case FEC_7_8:
+ tmp = "FEC_7_8";
+ break;
+#if HAVE_DVB_API_VERSION >= 3
+ case FEC_8_9:
+ tmp = "FEC_8_9";
+ break;
+#endif
+ default:
+ case FEC_AUTO:
+ tmp = "FEC_AUTO";
+ break;
+ }
+ PutToDict(dict, "fec_inner", tmp);
+ switch(parm_u_qam_modulation)
+ {
+ case QAM_16:
+ tmp = "QAM_16";
+ break;
+ case QAM_32:
+ tmp = "QAM_32";
+ break;
+ case QAM_64:
+ tmp = "QAM_64";
+ break;
+ case QAM_128:
+ tmp = "QAM_128";
+ break;
+ case QAM_256:
+ tmp = "QAM_256";
+ break;
+ default:
+ case QAM_AUTO:
+ tmp = "QAM_AUTO";
+ break;
+ }
+ PutToDict(dict, "modulation", tmp);
+}
+
+void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
+{
+ const char *tmp=0;
+ PutToDict(dict, "frequency", parm_frequency);
+ switch (parm_u_ofdm_bandwidth)
+ {
+ case BANDWIDTH_8_MHZ:
+ tmp = "BANDWIDTH_8_MHZ";
+ break;
+ case BANDWIDTH_7_MHZ:
+ tmp = "BANDWIDTH_7_MHZ";
+ break;
+ case BANDWIDTH_6_MHZ:
+ tmp = "BANDWIDTH_6_MHZ";
+ break;
+ default:
+ case BANDWIDTH_AUTO:
+ tmp = "BANDWIDTH_AUTO";
+ break;
+ }
+ PutToDict(dict, "bandwidth", tmp);
+ switch (parm_u_ofdm_code_rate_LP)
+ {
+ case FEC_1_2:
+ tmp = "FEC_1_2";
+ break;
+ case FEC_2_3:
+ tmp = "FEC_2_3";
+ break;
+ case FEC_3_4:
+ tmp = "FEC_3_4";
+ break;
+ case FEC_5_6:
+ tmp = "FEC_5_6";
+ break;
+ case FEC_7_8:
+ tmp = "FEC_7_8";
+ break;
+ default:
+ case FEC_AUTO:
+ tmp = "FEC_AUTO";
+ break;
+ }
+ PutToDict(dict, "code_rate_lp", tmp);
+ switch (parm_u_ofdm_code_rate_HP)
+ {
+ case FEC_1_2:
+ tmp = "FEC_1_2";
+ break;
+ case FEC_2_3:
+ tmp = "FEC_2_3";
+ break;
+ case FEC_3_4:
+ tmp = "FEC_3_4";
+ break;
+ case FEC_5_6:
+ tmp = "FEC_5_6";
+ break;
+ case FEC_7_8:
+ tmp = "FEC_7_8";
+ break;
+ default:
+ case FEC_AUTO:
+ tmp = "FEC_AUTO";
+ break;
+ }
+ PutToDict(dict, "code_rate_hp", tmp);
+ switch (parm_u_ofdm_constellation)
+ {
+ case QPSK:
+ tmp = "QPSK";
+ break;
+ case QAM_16:
+ tmp = "QAM_16";
+ break;
+ case QAM_64:
+ tmp = "QAM_64";
+ break;
+ default:
+ case QAM_AUTO:
+ tmp = "QAM_AUTO";
+ break;
+ }
+ PutToDict(dict, "constellation", tmp);
+ switch (parm_u_ofdm_transmission_mode)
+ {
+ case TRANSMISSION_MODE_2K:
+ tmp = "TRANSMISSION_MODE_2K";
+ break;
+ case TRANSMISSION_MODE_8K:
+ tmp = "TRANSMISSION_MODE_8K";
+ break;
+ default:
+ case TRANSMISSION_MODE_AUTO:
+ tmp = "TRANSMISSION_MODE_AUTO";
+ break;
+ }
+ PutToDict(dict, "transmission_mode", tmp);
+ switch (parm_u_ofdm_guard_interval)
+ {
+ case GUARD_INTERVAL_1_32:
+ tmp = "GUARD_INTERVAL_1_32";
+ break;
+ case GUARD_INTERVAL_1_16:
+ tmp = "GUARD_INTERVAL_1_16";
+ break;
+ case GUARD_INTERVAL_1_8:
+ tmp = "GUARD_INTERVAL_1_8";
+ break;
+ case GUARD_INTERVAL_1_4:
+ tmp = "GUARD_INTERVAL_1_4";
+ break;
+ default:
+ case GUARD_INTERVAL_AUTO:
+ tmp = "GUARD_INTERVAL_AUTO";
+ break;
+ }
+ PutToDict(dict, "guard_interval", tmp);
+ switch (parm_u_ofdm_hierarchy_information)
+ {
+ case HIERARCHY_NONE:
+ tmp = "HIERARCHY_NONE";
+ break;
+ case HIERARCHY_1:
+ tmp = "HIERARCHY_1";
+ break;
+ case HIERARCHY_2:
+ tmp = "HIERARCHY_2";
+ break;
+ case HIERARCHY_4:
+ tmp = "HIERARCHY_4";
+ break;
+ default:
+ case HIERARCHY_AUTO:
+ tmp = "HIERARCHY_AUTO";
+ break;
+ }
+ PutToDict(dict, "hierarchy_information", tmp);
+}
+
+void eDVBFrontend::getFrontendStatus(ePyObject dest)
+{
+ if (dest && PyDict_Check(dest))
+ {
+ const char *tmp = "UNKNOWN";
+ switch(m_state)
+ {
+ case stateIdle:
+ tmp="IDLE";
+ break;
+ case stateTuning:
+ tmp="TUNING";
+ break;
+ case stateFailed:
+ tmp="FAILED";
+ break;
+ case stateLock:
+ tmp="LOCKED";
+ break;
+ case stateLostLock:
+ tmp="LOSTLOCK";
+ break;
+ default:
+ break;
+ }
+ PutToDict(dest, "tuner_state", tmp);
+ PutToDict(dest, "tuner_locked", readFrontendData(locked));
+ PutToDict(dest, "tuner_synced", readFrontendData(synced));
+ PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
+ PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
+ int sigQualitydB = readFrontendData(signalQualitydB);
+ if (sigQualitydB == 0x12345678) // not support yet
+ {
+ ePyObject obj=Py_None;
+ Py_INCREF(obj);
+ PutToDict(dest, "tuner_signal_quality_db", obj);
+ }
+ else
+ PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
+ PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
+ }
+}
+
+void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
+{
+ if (m_fd != -1 && dest && PyDict_Check(dest))
+ {
+ switch(m_type)
+ {
+ case feSatellite:
+ case feCable:
+ case feTerrestrial:
+ {
+ FRONTENDPARAMETERS front;
+ if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
+ eDebug("FE_GET_FRONTEND (%m)");
+ else
+ {
+ const FRONTENDPARAMETERS &parm = original ? this->parm : front;
+ const char *tmp = "INVERSION_AUTO";
+ switch(parm_inversion)
+ {
+ case INVERSION_ON:
+ tmp = "INVERSION_ON";
+ break;
+ case INVERSION_OFF:
+ tmp = "INVERSION_OFF";
+ break;
+ default:
+ break;
+ }
+ if (tmp)
+ PutToDict(dest, "inversion", tmp);
+
+ switch(m_type)
+ {
+ case feSatellite:
+ fillDictWithSatelliteData(dest, original?parm:front, this);
+ break;
+ case feCable:
+ fillDictWithCableData(dest, original?parm:front);
+ break;
+ case feTerrestrial:
+ fillDictWithTerrestrialData(dest, original?parm:front);
+ break;
+ }
+ }
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void eDVBFrontend::getFrontendData(ePyObject dest)
+{
+ if (dest && PyDict_Check(dest))
+ {
+ const char *tmp=0;
+ PutToDict(dest, "tuner_number", m_slotid);
+ switch(m_type)
+ {
+ case feSatellite:
+ tmp = "DVB-S";
+ break;
+ case feCable:
+ tmp = "DVB-C";
+ break;
+ case feTerrestrial:
+ tmp = "DVB-T";
+ break;
+ default:
+ tmp = "UNKNOWN";
+ break;
+ }
+ PutToDict(dest, "tuner_type", tmp);
+ }
+}
+
+#ifndef FP_IOCTL_GET_ID
+#define FP_IOCTL_GET_ID 0
+#endif
+int eDVBFrontend::readInputpower()
+{
+ int power=m_slotid; // this is needed for read inputpower from the correct tuner !
+ char proc_name[64];
+ sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
+ FILE *f=fopen(proc_name, "r");
+ if (f)
+ {
+ if (fscanf(f, "%d", &power) != 1)
+ eDebug("read %s failed!! (%m)", proc_name);
+ else
+ eDebug("%s is %d\n", proc_name, power);
+ fclose(f);
+ }
+ else
+ {
+ // open front prozessor
+ int fp=::open("/dev/dbox/fp0", O_RDWR);
+ if (fp < 0)
+ {
+ eDebug("couldn't open fp");
+ return -1;
+ }
+ static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
+ if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
+ {
+ eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
+ return -1;
+ }
+ ::close(fp);
+ }
+
+ return power;
+}
+
+bool eDVBFrontend::setSecSequencePos(int steps)
+{
+ eDebug("set sequence pos %d", steps);
+ if (!steps)
+ return false;
+ while( steps > 0 )
+ {
+ if (m_sec_sequence.current() != m_sec_sequence.end())
+ ++m_sec_sequence.current();
+ --steps;
+ }
+ while( steps < 0 )
+ {
+ if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
+ --m_sec_sequence.current();
+ ++steps;
+ }
+ return true;
+}
+
+void eDVBFrontend::tuneLoop() // called by m_tuneTimer
+{
+ int delay=0;
+ eDVBFrontend *sec_fe = this;
+ eDVBRegisteredFrontend *regFE = 0;
+ long tmp = m_data[LINKED_PREV_PTR];
+ while ( tmp != -1 )
+ {
+ eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
+ sec_fe = prev->m_frontend;
+ tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
+ if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
+ int state = sec_fe->m_state;
+ if (state != eDVBFrontend::stateIdle && state != stateClosed)
+ {
+ sec_fe->closeFrontend(true);
+ state = sec_fe->m_state;
+ }
+ if (state == eDVBFrontend::stateClosed)
+ {
+ regFE = prev;
+ prev->inc_use();
+ }
+ }
+ }
+
+ if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
+ {
+ long *sec_fe_data = sec_fe->m_data;
+// eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
+ switch (m_sec_sequence.current()->cmd)
+ {
+ case eSecCommand::SLEEP:
+ delay = m_sec_sequence.current()++->msec;
+ eDebug("[SEC] sleep %dms", delay);
+ break;
+ case eSecCommand::GOTO:
+ if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_VOLTAGE:
+ {
+ int voltage = m_sec_sequence.current()++->voltage;
+ eDebug("[SEC] setVoltage %d", voltage);
+ sec_fe->setVoltage(voltage);
+ break;
+ }
+ case eSecCommand::IF_VOLTAGE_GOTO:
+ {
+ eSecCommand::pair &compare = m_sec_sequence.current()->compare;
+ if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
+ break;
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::IF_NOT_VOLTAGE_GOTO:
+ {
+ eSecCommand::pair &compare = m_sec_sequence.current()->compare;
+ if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
+ break;
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::IF_TONE_GOTO:
+ {
+ eSecCommand::pair &compare = m_sec_sequence.current()->compare;
+ if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
+ break;
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::IF_NOT_TONE_GOTO:
+ {
+ eSecCommand::pair &compare = m_sec_sequence.current()->compare;
+ if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
+ break;
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::SET_TONE:
+ eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
+ sec_fe->setTone(m_sec_sequence.current()++->tone);
+ break;
+ case eSecCommand::SEND_DISEQC:
+ sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
+ eDebugNoNewLine("[SEC] sendDiseqc: ");
+ for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
+ eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
+ eDebug("");
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SEND_TONEBURST:
+ eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
+ sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
+ break;
+ case eSecCommand::SET_FRONTEND:
+ eDebug("[SEC] setFrontend");
+ setFrontend();
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::START_TUNE_TIMEOUT:
+ {
+ m_timeout->start(m_sec_sequence.current()->timeout, 1);
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::SET_TIMEOUT:
+ m_timeoutCount = m_sec_sequence.current()++->val;
+ eDebug("[SEC] set timeout %d", m_timeoutCount);
+ break;
+ case eSecCommand::IF_TIMEOUT_GOTO:
+ if (!m_timeoutCount)
+ {
+ eDebug("[SEC] rotor timout");
+ setSecSequencePos(m_sec_sequence.current()->steps);
+ }
+ else
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::MEASURE_IDLE_INPUTPOWER:
+ {
+ int idx = m_sec_sequence.current()++->val;
+ if ( idx == 0 || idx == 1 )
+ {
+ m_idleInputpower[idx] = sec_fe->readInputpower();
+ eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
+ }
+ else
+ eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
+ break;
+ }
+ case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
+ {
+ eSecCommand::pair &compare = m_sec_sequence.current()->compare;
+ int idx = compare.val;
+ if ( idx == 0 || idx == 1 )
+ {
+ int idle = sec_fe->readInputpower();
+ int diff = abs(idle-m_idleInputpower[idx]);
+ if ( diff > 0)
+ {
+ eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
+ setSecSequencePos(compare.steps);
+ break;
+ }
+ }
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::IF_TUNER_LOCKED_GOTO:
+ {
+ int signal = 0;
+ int isLocked = readFrontendData(locked);
+ m_idleInputpower[0] = m_idleInputpower[1] = 0;
+ eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
+ if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
+ {
+ if (cmd.lastSignal)
+ eDebug("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
+ else
+ {
+ eDebug("[SEC] locked step %d ok", cmd.okcount);
+ cmd.lastSignal = signal;
+ }
+ ++cmd.okcount;
+ if (cmd.okcount > 4)
+ {
+ eDebug("ok > 4 .. goto %d\n",cmd.steps);
+ setSecSequencePos(cmd.steps);
+ m_state = stateLock;
+ m_stateChanged(this);
+ feEvent(-1);
+ m_sn->start();
+ break;
+ }
+ }
+ else
+ {
+ if (isLocked)
+ eDebug("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
+ else
+ eDebug("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
+ --m_timeoutCount;
+ if (!m_timeoutCount && m_retryCount > 0)
+ --m_retryCount;
+ cmd.okcount=0;
+ cmd.lastSignal=0;
+ }
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
+ m_runningInputpower = sec_fe->readInputpower();
+ eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_ROTOR_MOVING:
+ m_sec->setRotorMoving(true);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_ROTOR_STOPPED:
+ m_sec->setRotorMoving(false);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
+ {
+ int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
+ eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
+ const char *txt = cmd.direction ? "running" : "stopped";
+ eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
+ txt,
+ m_runningInputpower,
+ idleInputpower,
+ cmd.deltaA);
+ if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
+ || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
+ {
+ ++cmd.okcount;
+ eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
+ if ( cmd.okcount > 6 )
+ {
+ eDebug("[SEC] rotor is %s", txt);
+ if (setSecSequencePos(cmd.steps))
+ break;
+ }
+ }
+ else
+ {
+ eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
+ --m_timeoutCount;
+ if (!m_timeoutCount && m_retryCount > 0)
+ --m_retryCount;
+ cmd.okcount=0;
+ }
+ ++m_sec_sequence.current();
+ break;
+ }
+ case eSecCommand::IF_ROTORPOS_VALID_GOTO:
+ if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
+ setSecSequencePos(m_sec_sequence.current()->steps);
+ else
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
+ eDebug("[SEC] invalidate current switch params");
+ sec_fe_data[CSW] = -1;
+ sec_fe_data[UCSW] = -1;
+ sec_fe_data[TONEBURST] = -1;
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
+ sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
+ sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
+ sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
+ eDebug("[SEC] update current switch params");
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
+ eDebug("[SEC] invalidate current rotorparams");
+ sec_fe_data[ROTOR_CMD] = -1;
+ sec_fe_data[ROTOR_POS] = -1;
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
+ sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
+ sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
+ eDebug("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
+ m_retryCount = m_sec_sequence.current()++->val;
+ eDebug("[SEC] set rotor retries %d", m_retryCount);
+ break;
+ case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
+ if (!m_retryCount)
+ {
+ eDebug("[SEC] no more rotor retrys");
+ setSecSequencePos(m_sec_sequence.current()->steps);
+ }
+ else
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_POWER_LIMITING_MODE:
+ {
+ char proc_name[64];
+ sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
+ FILE *f=fopen(proc_name, "w");
+ if (f) // new interface exist?
+ {
+ bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
+ if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
+ eDebug("write %s failed!! (%m)", proc_name);
+ else
+ eDebug("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
+ fclose(f);
+ }
+ else if (sec_fe->m_need_rotor_workaround)
+ {
+ char dev[16];
+ int slotid = sec_fe->m_slotid;
+ // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
+ if (slotid < 2)
+ sprintf(dev, "/dev/i2c/%d", slotid);
+ else if (slotid == 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
+ int fd = ::open(dev, O_RDWR);
+
+ unsigned char data[2];
+ ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
+ if(::read(fd, data, 1) != 1)
+ eDebug("[SEC] error read lnbp (%m)");
+ if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
+ {
+ data[0] |= 0x80; // enable static current limiting
+ eDebug("[SEC] set static current limiting");
+ }
+ else
+ {
+ data[0] &= ~0x80; // enable dynamic current limiting
+ eDebug("[SEC] set dynamic current limiting");
+ }
+ if(::write(fd, data, 1) != 1)
+ eDebug("[SEC] error write lnbp (%m)");
+ ::close(fd);
+ }
+ ++m_sec_sequence.current();
+ break;
+ }
+ default:
+ eDebug("[SEC] unhandled sec command %d",
+ ++m_sec_sequence.current()->cmd);
+ ++m_sec_sequence.current();
+ }
+ m_tuneTimer->start(delay,true);
+ }
+ if (regFE)
+ regFE->dec_use();
+}
+
+void eDVBFrontend::setFrontend()
+{
+ eDebug("setting frontend %d", m_dvbid);
+ m_sn->start();
+ feEvent(-1);
+ if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
+ {
+ perror("FE_SET_FRONTEND failed");
+ return;
+ }
+}
+
+RESULT eDVBFrontend::getFrontendType(int &t)
+{
+ if (m_type == -1)
+ return -ENODEV;
+ t = m_type;
+ return 0;
+}
+
+RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
+{
+ int res;
+ if (!m_sec)
+ {
+ eWarning("no SEC module active!");
+ return -ENOENT;
+ }
+ res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
+ if (!res)
+ {
+ eDebug("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
+ feparm.system,
+ feparm.frequency,
+ feparm.polarisation,
+ feparm.symbol_rate,
+ feparm.inversion,
+ feparm.fec,
+ feparm.orbital_position);
+ parm_u_qpsk_symbol_rate = feparm.symbol_rate;
+ switch (feparm.inversion)
+ {
+ case eDVBFrontendParametersSatellite::Inversion::On:
+ parm_inversion = INVERSION_ON;
+ break;
+ case eDVBFrontendParametersSatellite::Inversion::Off:
+ parm_inversion = INVERSION_OFF;
+ break;
+ default:
+ case eDVBFrontendParametersSatellite::Inversion::Unknown:
+ parm_inversion = INVERSION_AUTO;
+ break;
+ }
+ if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
+ switch (feparm.fec)
+ {
+ case eDVBFrontendParametersSatellite::FEC::fNone:
+ parm_u_qpsk_fec_inner = FEC_NONE;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f1_2:
+ parm_u_qpsk_fec_inner = FEC_1_2;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f2_3:
+ parm_u_qpsk_fec_inner = FEC_2_3;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f3_4:
+ parm_u_qpsk_fec_inner = FEC_3_4;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f5_6:
+ parm_u_qpsk_fec_inner = FEC_5_6;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f7_8:
+ parm_u_qpsk_fec_inner = FEC_7_8;
+ break;
+ default:
+ eDebug("no valid fec for DVB-S set.. assume auto");
+ case eDVBFrontendParametersSatellite::FEC::fAuto:
+ parm_u_qpsk_fec_inner = FEC_AUTO;
+ break;
+ }
+#if HAVE_DVB_API_VERSION >= 3
+ else // DVB_S2
+ {
+ switch (feparm.fec)
+ {
+ case eDVBFrontendParametersSatellite::FEC::f1_2:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f2_3:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f3_4:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f3_5:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f4_5:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f5_6:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f7_8:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f8_9:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
+ break;
+ case eDVBFrontendParametersSatellite::FEC::f9_10:
+ parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
+ break;
+ default:
+ eDebug("no valid fec for DVB-S2 set.. abort !!");
+ return -EINVAL;
+ }
+ parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
+ if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
+ parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
+ // 8PSK fec driver values are decimal 9 bigger
+ parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
+ }
+ }
+#endif
+ // FIXME !!! get frequency range from tuner
+ if ( parm_frequency < 900000 || parm_frequency > 2200000 )
+ {
+ eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
+ return -EINVAL;
+ }
+ eDebug("tuning to %d mhz", parm_frequency/1000);
+ }
+ return res;
+}
+
+RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
+{
+#if HAVE_DVB_API_VERSION < 3
+ parm_frequency = feparm.frequency;
+#else
+ parm_frequency = feparm.frequency * 1000;
+#endif
+ parm_u_qam_symbol_rate = feparm.symbol_rate;
+ switch (feparm.modulation)
+ {
+ case eDVBFrontendParametersCable::Modulation::QAM16:
+ parm_u_qam_modulation = QAM_16;
+ break;
+ case eDVBFrontendParametersCable::Modulation::QAM32:
+ parm_u_qam_modulation = QAM_32;
+ break;
+ case eDVBFrontendParametersCable::Modulation::QAM64:
+ parm_u_qam_modulation = QAM_64;
+ break;
+ case eDVBFrontendParametersCable::Modulation::QAM128:
+ parm_u_qam_modulation = QAM_128;
+ break;
+ case eDVBFrontendParametersCable::Modulation::QAM256:
+ parm_u_qam_modulation = QAM_256;
+ break;
+ default:
+ case eDVBFrontendParametersCable::Modulation::Auto:
+ parm_u_qam_modulation = QAM_AUTO;
+ break;
+ }
+ switch (feparm.inversion)
+ {
+ case eDVBFrontendParametersCable::Inversion::On:
+ parm_inversion = INVERSION_ON;
+ break;
+ case eDVBFrontendParametersCable::Inversion::Off:
+ parm_inversion = INVERSION_OFF;
+ break;
+ default:
+ case eDVBFrontendParametersCable::Inversion::Unknown:
+ parm_inversion = INVERSION_AUTO;
+ break;
+ }
+ switch (feparm.fec_inner)
+ {
+ case eDVBFrontendParametersCable::FEC::fNone:
+ parm_u_qam_fec_inner = FEC_NONE;
+ break;
+ case eDVBFrontendParametersCable::FEC::f1_2:
+ parm_u_qam_fec_inner = FEC_1_2;
+ break;
+ case eDVBFrontendParametersCable::FEC::f2_3:
+ parm_u_qam_fec_inner = FEC_2_3;
+ break;
+ case eDVBFrontendParametersCable::FEC::f3_4:
+ parm_u_qam_fec_inner = FEC_3_4;
+ break;
+ case eDVBFrontendParametersCable::FEC::f5_6:
+ parm_u_qam_fec_inner = FEC_5_6;
+ break;
+ case eDVBFrontendParametersCable::FEC::f7_8:
+ parm_u_qam_fec_inner = FEC_7_8;
+ break;
+#if HAVE_DVB_API_VERSION >= 3
+ case eDVBFrontendParametersCable::FEC::f8_9:
+ parm_u_qam_fec_inner = FEC_8_9;
+ break;
+#endif
+ default:
+ case eDVBFrontendParametersCable::FEC::fAuto:
+ parm_u_qam_fec_inner = FEC_AUTO;
+ break;
+ }
+ eDebug("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
+ parm_frequency/1000,
+ parm_u_qam_symbol_rate,
+ parm_u_qam_fec_inner,
+ parm_u_qam_modulation,
+ parm_inversion);
+ return 0;
+}
+
+RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
+{
+ parm_frequency = feparm.frequency;
+
+ switch (feparm.bandwidth)
+ {
+ case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
+ parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
+ break;
+ case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
+ parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
+ break;
+ case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
+ parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
+ parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
+ break;
+ }
+ switch (feparm.code_rate_LP)
+ {
+ case eDVBFrontendParametersTerrestrial::FEC::f1_2:
+ parm_u_ofdm_code_rate_LP = FEC_1_2;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f2_3:
+ parm_u_ofdm_code_rate_LP = FEC_2_3;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f3_4:
+ parm_u_ofdm_code_rate_LP = FEC_3_4;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f5_6:
+ parm_u_ofdm_code_rate_LP = FEC_5_6;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f7_8:
+ parm_u_ofdm_code_rate_LP = FEC_7_8;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::FEC::fAuto:
+ parm_u_ofdm_code_rate_LP = FEC_AUTO;
+ break;
+ }
+ switch (feparm.code_rate_HP)
+ {
+ case eDVBFrontendParametersTerrestrial::FEC::f1_2:
+ parm_u_ofdm_code_rate_HP = FEC_1_2;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f2_3:
+ parm_u_ofdm_code_rate_HP = FEC_2_3;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f3_4:
+ parm_u_ofdm_code_rate_HP = FEC_3_4;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f5_6:
+ parm_u_ofdm_code_rate_HP = FEC_5_6;
+ break;
+ case eDVBFrontendParametersTerrestrial::FEC::f7_8:
+ parm_u_ofdm_code_rate_HP = FEC_7_8;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::FEC::fAuto:
+ parm_u_ofdm_code_rate_HP = FEC_AUTO;
+ break;
+ }
+ switch (feparm.modulation)
+ {
+ case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
+ parm_u_ofdm_constellation = QPSK;
+ break;
+ case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
+ parm_u_ofdm_constellation = QAM_16;
+ break;
+ case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
+ parm_u_ofdm_constellation = QAM_64;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::Modulation::Auto:
+ parm_u_ofdm_constellation = QAM_AUTO;
+ break;
+ }
+ switch (feparm.transmission_mode)
+ {
+ case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
+ parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
+ parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
+ parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
+ break;
+ }
+ switch (feparm.guard_interval)
+ {
+ case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
+ parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
+ parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
+ parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
+ parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
+ parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
+ break;
+ }
+ switch (feparm.hierarchy)
+ {
+ case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
+ parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
+ break;
+ case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
+ parm_u_ofdm_hierarchy_information = HIERARCHY_1;
+ break;
+ case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
+ parm_u_ofdm_hierarchy_information = HIERARCHY_2;
+ break;
+ case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
+ parm_u_ofdm_hierarchy_information = HIERARCHY_4;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
+ parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
+ break;
+ }
+ switch (feparm.inversion)
+ {
+ case eDVBFrontendParametersTerrestrial::Inversion::On:
+ parm_inversion = INVERSION_ON;
+ break;
+ case eDVBFrontendParametersTerrestrial::Inversion::Off:
+ parm_inversion = INVERSION_OFF;
+ break;
+ default:
+ case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
+ parm_inversion = INVERSION_AUTO;
+ break;
+ }
+ return 0;
+}
+
+RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
+{
+ unsigned int timeout = 5000;
+ eDebug("(%d)tune", m_dvbid);
+
+ m_timeout->stop();
+
+ int res=0;
+
+ if (!m_sn)
+ {
+ eDebug("no frontend device opened... do not try to tune !!!");
+ res = -ENODEV;
+ goto tune_error;
+ }
+
+ if (m_type == -1)
+ {
+ res = -ENODEV;
+ goto tune_error;
+ }
+
+ m_sn->stop();
+ m_sec_sequence.clear();
+
+ where.calcLockTimeout(timeout);
+
+ switch (m_type)
+ {
+ case feSatellite:
+ {
+ eDVBFrontendParametersSatellite feparm;
+ if (where.getDVBS(feparm))
+ {
+ eDebug("no dvbs data!");
+ res = -EINVAL;
+ goto tune_error;
+ }
+ m_sec->setRotorMoving(false);
+ res=prepare_sat(feparm, timeout);
+ if (res)
+ goto tune_error;
+
+ break;
+ }
+ case feCable:
+ {
+ eDVBFrontendParametersCable feparm;
+ if (where.getDVBC(feparm))
+ {
+ res = -EINVAL;
+ goto tune_error;
+ }
+ res=prepare_cable(feparm);
+ if (res)
+ goto tune_error;
+
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
+ break;
+ }
+ case feTerrestrial:
+ {
+ eDVBFrontendParametersTerrestrial feparm;
+ if (where.getDVBT(feparm))
+ {
+ eDebug("no -T data");
+ res = -EINVAL;
+ goto tune_error;
+ }
+ res=prepare_terrestrial(feparm);
+ if (res)
+ goto tune_error;
+
+ std::string enable_5V;
+ char configStr[255];
+ snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
+ ePythonConfigQuery::getConfigValue(configStr, enable_5V);
+ if (enable_5V == "True")
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
+ else
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
+ m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
+
+ break;
+ }
+ }
+
+ m_tuneTimer->start(0,true);
+ m_sec_sequence.current() = m_sec_sequence.begin();
+
+ if (m_state != stateTuning)
+ {
+ m_tuning = 1;
+ m_state = stateTuning;
+ m_stateChanged(this);
+ }
+
+ return res;
+
+tune_error:
+ m_tuneTimer->stop();
+ return res;
+}
+
+RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
+{
+ connection = new eConnection(this, m_stateChanged.connect(stateChange));
+ return 0;
+}
+
+RESULT eDVBFrontend::setVoltage(int voltage)
+{
+ if (m_type == feCable)
+ return -1;
+#if HAVE_DVB_API_VERSION < 3