+int eDVBFrontend::readInputpower()
+{
+ if (m_simulate)
+ return 0;
+ 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)
+{
+ eDebugNoSimulate("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;
+ // workaround to put the kernel frontend thread into idle state!
+ if (state != eDVBFrontend::stateIdle && state != stateClosed)
+ {
+ sec_fe->closeFrontend(true);
+ state = sec_fe->m_state;
+ }
+ // sec_fe is closed... we must reopen it here..
+ 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;
+// eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
+ switch (m_sec_sequence.current()->cmd)
+ {
+ case eSecCommand::SLEEP:
+ delay = m_sec_sequence.current()++->msec;
+ eDebugNoSimulate("[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;
+ eDebugNoSimulate("[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:
+ eDebugNoSimulate("[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);
+ eDebugNoSimulateNoNewLine("[SEC] sendDiseqc: ");
+ for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
+ eDebugNoSimulateNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
+ if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x00", 3))
+ eDebugNoSimulate("(DiSEqC reset)");
+ else if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x03", 3))
+ eDebugNoSimulate("(DiSEqC peripherial power on)");
+ else
+ eDebugNoSimulate("");
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SEND_TONEBURST:
+ eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
+ sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
+ break;
+ case eSecCommand::SET_FRONTEND:
+ eDebugNoSimulate("[SEC] setFrontend");
+ setFrontend();
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::START_TUNE_TIMEOUT:
+ {
+ if (!m_simulate)
+ 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;
+ eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
+ break;
+ case eSecCommand::IF_TIMEOUT_GOTO:
+ if (!m_timeoutCount)
+ {
+ eDebugNoSimulate("[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();
+ eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
+ }
+ else
+ eDebugNoSimulate("[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 ( !m_simulate && (idx == 0 || idx == 1) )
+ {
+ int idle = sec_fe->readInputpower();
+ int diff = abs(idle-m_idleInputpower[idx]);
+ if ( diff > 0)
+ {
+ eDebugNoSimulate("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:
+ {
+ eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
+ if (m_simulate)
+ {
+ setSecSequencePos(cmd.steps);
+ break;
+ }
+ int signal = 0;
+ int isLocked = readFrontendData(locked);
+ m_idleInputpower[0] = m_idleInputpower[1] = 0;
+ if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
+ {
+ if (cmd.lastSignal)
+ eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
+ else
+ {
+ eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
+ cmd.lastSignal = signal;
+ }
+ ++cmd.okcount;
+ if (cmd.okcount > 4)
+ {
+ eDebugNoSimulate("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)
+ eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
+ else
+ eDebugNoSimulate("[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();
+ eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_ROTOR_MOVING:
+ if (!m_simulate)
+ m_sec->setRotorMoving(true);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_ROTOR_STOPPED:
+ if (!m_simulate)
+ m_sec->setRotorMoving(false);
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
+ {
+ eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
+ if (m_simulate)
+ {
+ setSecSequencePos(cmd.steps);
+ break;
+ }
+ int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
+ const char *txt = cmd.direction ? "running" : "stopped";
+ eDebugNoSimulate("[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;
+ eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
+ if ( cmd.okcount > 6 )
+ {
+ eDebugNoSimulate("[SEC] rotor is %s", txt);
+ if (setSecSequencePos(cmd.steps))
+ break;
+ }
+ }
+ else
+ {
+ eDebugNoSimulate("[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:
+ eDebugNoSimulate("[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];
+ eDebugNoSimulate("[SEC] update current switch params");
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
+ eDebugNoSimulate("[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];
+ eDebugNoSimulate("[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;
+ eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
+ break;
+ case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
+ if (!m_retryCount)
+ {
+ eDebugNoSimulate("[SEC] no more rotor retrys");
+ setSecSequencePos(m_sec_sequence.current()->steps);
+ }
+ else
+ ++m_sec_sequence.current();
+ break;
+ case eSecCommand::SET_POWER_LIMITING_MODE:
+ {
+ if (!m_simulate)
+ {
+ 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)
+ eDebugNoSimulate("write %s failed!! (%m)", proc_name);
+ else
+ eDebugNoSimulate("[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)
+ eDebugNoSimulate("[SEC] error read lnbp (%m)");
+ if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
+ {
+ data[0] |= 0x80; // enable static current limiting
+ eDebugNoSimulate("[SEC] set static current limiting");
+ }
+ else
+ {
+ data[0] &= ~0x80; // enable dynamic current limiting
+ eDebugNoSimulate("[SEC] set dynamic current limiting");
+ }
+ if(::write(fd, data, 1) != 1)
+ eDebugNoSimulate("[SEC] error write lnbp (%m)");
+ ::close(fd);
+ }
+ }
+ ++m_sec_sequence.current();
+ break;
+ }
+ default:
+ eDebugNoSimulate("[SEC] unhandled sec command %d",
+ ++m_sec_sequence.current()->cmd);
+ ++m_sec_sequence.current();
+ }
+ if (!m_simulate)
+ m_tuneTimer->start(delay,true);
+ }
+ if (regFE)
+ regFE->dec_use();
+ if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
+ tuneLoop();
+}
+
+void eDVBFrontend::setFrontend()
+{
+ if (!m_simulate)
+ {
+ 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)
+ {
+#if HAVE_DVB_API_VERSION >= 3
+ eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d system %d modulation %d pilot %d, rolloff %d",
+ feparm.system,
+ feparm.frequency,
+ feparm.polarisation,
+ feparm.symbol_rate,
+ feparm.inversion,
+ feparm.fec,
+ feparm.orbital_position,
+ feparm.system,
+ feparm.modulation,
+ feparm.pilot,
+ feparm.rolloff);