+ if (!instance)
+ instance = this;
+ clear();
+}
+
+#define eSecDebugNoSimulate(x...) \
+ do { \
+ if (!simulate) \
+ eSecDebug(x); \
+ } while(0)
+// else \
+// { \
+// eDebugNoNewLine("SIMULATE:"); \
+// eDebug(x); \
+// } \
+
+int eDVBSatelliteEquipmentControl::canTune(const eDVBFrontendParametersSatellite &sat, iDVBFrontend *fe, int slot_id, int *highest_score_lnb)
+{
+ bool simulate = ((eDVBFrontend*)fe)->is_simulate();
+ bool direct_connected = m_not_linked_slot_mask & slot_id;
+ int score=0, satcount=0;
+ long linked_prev_ptr=-1, linked_next_ptr=-1, linked_csw=-1, linked_ucsw=-1, linked_toneburst=-1,
+ fe_satpos_depends_ptr=-1, fe_rotor_pos=-1;
+ bool linked_in_use = false;
+
+ eSecDebugNoSimulate("direct_connected %d", !!direct_connected);
+
+ fe->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+ fe->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
+ fe->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, fe_satpos_depends_ptr);
+
+ // first we search the linkage base frontend and check if any tuner in prev direction is used
+ while (linked_prev_ptr != -1)
+ {
+ eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*) linked_prev_ptr;
+ if (linked_fe->m_inuse)
+ linked_in_use = true;
+ fe = linked_fe->m_frontend;
+ linked_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr);
+ }
+
+ fe->getData(eDVBFrontend::ROTOR_POS, fe_rotor_pos);
+
+ // now check also the linked tuners is in use
+ while (!linked_in_use && linked_next_ptr != -1)
+ {
+ eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*) linked_next_ptr;
+ if (linked_fe->m_inuse)
+ linked_in_use = true;
+ linked_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, (long&)linked_next_ptr);
+ }
+
+ // when a linked in use tuner is found we get the tuner data...
+ if (linked_in_use)
+ {
+ fe->getData(eDVBFrontend::CSW, linked_csw);
+ fe->getData(eDVBFrontend::UCSW, linked_ucsw);
+ fe->getData(eDVBFrontend::TONEBURST, linked_toneburst);
+ }
+
+ if (highest_score_lnb)
+ *highest_score_lnb = -1;
+
+ eSecDebugNoSimulate("canTune %d", slot_id);
+
+ for (int idx=0; idx <= m_lnbidx; ++idx )
+ {
+ bool rotor=false;
+ eDVBSatelliteLNBParameters &lnb_param = m_lnbs[idx];
+ if ( lnb_param.m_slot_mask & slot_id ) // lnb for correct tuner?
+ {
+ int ret = 0;
+ eDVBSatelliteDiseqcParameters &di_param = lnb_param.m_diseqc_parameters;
+
+ eSecDebugNoSimulate("lnb %d found", idx);
+
+ satcount += lnb_param.m_satellites.size();
+
+ std::map<int, eDVBSatelliteSwitchParameters>::iterator sit =
+ lnb_param.m_satellites.find(sat.orbital_position);
+ if ( sit != lnb_param.m_satellites.end())
+ {
+ bool diseqc=false;
+ long band=0,
+ satpos_depends_ptr=fe_satpos_depends_ptr,
+ csw = di_param.m_committed_cmd,
+ ucsw = di_param.m_uncommitted_cmd,
+ toneburst = di_param.m_toneburst_param,
+ rotor_pos = fe_rotor_pos;
+
+ eSecDebugNoSimulate("sat %d found", sat.orbital_position);
+
+ if ( sat.frequency > lnb_param.m_lof_threshold )
+ band |= 1;
+ if (!(sat.polarisation & eDVBFrontendParametersSatellite::Polarisation_Vertical))
+ band |= 2;
+
+ if (di_param.m_diseqc_mode >= eDVBSatelliteDiseqcParameters::V1_0)
+ {
+ diseqc=true;
+ if ( di_param.m_committed_cmd < eDVBSatelliteDiseqcParameters::SENDNO )
+ csw = 0xF0 | (csw << 2);
+
+ if (di_param.m_committed_cmd <= eDVBSatelliteDiseqcParameters::SENDNO)
+ csw |= band;
+
+ if ( di_param.m_diseqc_mode == eDVBSatelliteDiseqcParameters::V1_2 ) // ROTOR
+ rotor = true;
+
+ ret = 10000;
+ }
+ else
+ {
+ csw = band;
+ ret = 15000;
+ }
+
+ eSecDebugNoSimulate("ret1 %d", ret);
+
+ if (linked_in_use)
+ {
+ // compare tuner data
+ if ( (csw != linked_csw) ||
+ ( diseqc && (ucsw != linked_ucsw || toneburst != linked_toneburst) ) ||
+ ( rotor && rotor_pos != sat.orbital_position ) )
+ {
+ ret = 0;
+ }
+ else
+ ret += 15;
+ eSecDebugNoSimulate("ret2 %d", ret);
+ if (ret) // special case when this tuner is linked to a satpos dependent tuner
+ {
+ fe->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, satpos_depends_ptr);
+ if (satpos_depends_ptr != -1)
+ {
+ eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend*) satpos_depends_ptr;
+ satpos_depends_to_fe->m_frontend->getData(eDVBFrontend::ROTOR_POS, rotor_pos);
+ if (!rotor || rotor_pos == -1 /* we dont know the rotor position yet */
+ || rotor_pos != sat.orbital_position ) // not the same orbital position?
+ {
+ ret = 0;
+ }
+ }
+ }
+ eSecDebugNoSimulate("ret3 %d", ret);
+ }
+ else if (satpos_depends_ptr != -1)
+ {
+ eSecDebugNoSimulate("satpos depends");
+ eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend*) satpos_depends_ptr;
+ if (direct_connected) // current fe is direct connected.. (can turn the rotor)
+ {
+ if (satpos_depends_to_fe->m_inuse) // if the dependent frontend is in use?
+ {
+ if (!rotor || rotor_pos != sat.orbital_position) // new orbital position not equal to current orbital pos?
+ ret = 0;
+ else
+ ret += 10;
+ }
+ }
+ else // current fe is dependent of another tuner ... (so this fe can't turn the rotor!)
+ {
+ // get current orb pos of the tuner with rotor connection
+ satpos_depends_to_fe->m_frontend->getData(eDVBFrontend::ROTOR_POS, rotor_pos);
+ if (!rotor || rotor_pos == -1 /* we dont know the rotor position yet */
+ || rotor_pos != sat.orbital_position ) // not the same orbital position?
+ {
+ ret = 0;
+ }
+ }
+ eSecDebugNoSimulate("ret4 %d", ret);
+ }
+
+ if (ret && rotor && rotor_pos != -1)
+ ret -= abs(rotor_pos-sat.orbital_position);
+
+ eSecDebugNoSimulate("ret5 %d", ret);
+
+ if (ret)
+ {
+ int lof = sat.frequency > lnb_param.m_lof_threshold ?
+ lnb_param.m_lof_hi : lnb_param.m_lof_lo;
+ int tuner_freq = abs(sat.frequency - lof);
+ if (tuner_freq < 900000 || tuner_freq > 2200000)
+ ret = 0;
+ }
+
+ if (ret && lnb_param.m_prio != -1)
+ ret = lnb_param.m_prio;
+
+ eSecDebugNoSimulate("ret %d, score old %d", ret, score);
+ if (ret > score)
+ {
+ score = ret;
+ if (highest_score_lnb)
+ *highest_score_lnb = idx;
+ }
+ eSecDebugNoSimulate("score new %d", score);
+ }
+ }
+ }
+ if (score && satcount)
+ {
+ if (score > (satcount-1))
+ score -= (satcount-1);
+ else
+ score = 1; // min score
+ }
+ if (score && direct_connected)
+ score += 5; // increase score for tuners with direct sat connection
+ eSecDebugNoSimulate("final score %d", score);
+ return score;
+}
+
+bool need_turn_fast(int turn_speed)
+{
+ if (turn_speed == eDVBSatelliteRotorParameters::FAST)
+ return true;
+ else if (turn_speed != eDVBSatelliteRotorParameters::SLOW)
+ {
+ int begin = turn_speed >> 16; // high word is start time
+ int end = turn_speed&0xFFFF; // low word is end time
+ time_t now_time = ::time(0);
+ tm nowTime;
+ localtime_r(&now_time, &nowTime);
+ int now = (nowTime.tm_hour + 1) * 60 + nowTime.tm_min + 1;
+ bool neg = end <= begin;
+ if (neg) {
+ int tmp = begin;
+ begin = end;
+ end = tmp;
+ }
+ if ((now >= begin && now < end) ^ neg)
+ return true;
+ }
+ return false;
+}
+
+#define VOLTAGE(x) (lnb_param.m_increased_voltage ? iDVBFrontend::voltage##x##_5 : iDVBFrontend::voltage##x)
+
+#define eDebugNoSimulate(x...) \
+ do { \
+ if (!simulate) \
+ eDebug(x); \
+ } while(0)
+// else \
+// { \
+// eDebugNoNewLine("SIMULATE:"); \
+// eDebug(x); \
+// } \
+
+RESULT eDVBSatelliteEquipmentControl::prepare(iDVBFrontend &frontend, FRONTENDPARAMETERS &parm, const eDVBFrontendParametersSatellite &sat, int slot_id, unsigned int tunetimeout)
+{
+ bool simulate = ((eDVBFrontend*)&frontend)->is_simulate();
+ int lnb_idx = -1;
+ if (canTune(sat, &frontend, slot_id, &lnb_idx))
+ {
+ eDVBSatelliteLNBParameters &lnb_param = m_lnbs[lnb_idx];
+ eDVBSatelliteDiseqcParameters &di_param = lnb_param.m_diseqc_parameters;
+ eDVBSatelliteRotorParameters &rotor_param = lnb_param.m_rotor_parameters;
+
+ std::map<int, eDVBSatelliteSwitchParameters>::iterator sit =
+ lnb_param.m_satellites.find(sat.orbital_position);
+ if ( sit != lnb_param.m_satellites.end())
+ {
+ eSecCommandList sec_sequence;
+
+ lnb_param.guard_offset = 0; //HACK
+
+ frontend.setData(eDVBFrontend::SATCR, lnb_param.SatCR_idx);
+
+ eDVBSatelliteSwitchParameters &sw_param = sit->second;
+ bool doSetFrontend = true;
+ bool doSetVoltageToneFrontend = true;
+ bool forceChanged = false;
+ bool needDiSEqCReset = false;
+ long band=0,
+ voltage = iDVBFrontend::voltageOff,
+ tone = iDVBFrontend::toneOff,
+ csw = di_param.m_committed_cmd,
+ ucsw = di_param.m_uncommitted_cmd,
+ toneburst = di_param.m_toneburst_param,
+ lastcsw = -1,
+ lastucsw = -1,
+ lastToneburst = -1,
+ lastRotorCmd = -1,
+ curRotorPos = -1,
+ satposDependPtr = -1;
+ iDVBFrontend *sec_fe=&frontend;
+ eDVBRegisteredFrontend *linked_fe = 0;
+ eDVBSatelliteDiseqcParameters::t_diseqc_mode diseqc_mode = di_param.m_diseqc_mode;
+ eDVBSatelliteSwitchParameters::t_voltage_mode voltage_mode = sw_param.m_voltage_mode;
+ bool diseqc13V = voltage_mode == eDVBSatelliteSwitchParameters::HV_13;
+
+ if (diseqc13V)
+ voltage_mode = eDVBSatelliteSwitchParameters::HV;
+
+ frontend.getData(eDVBFrontend::SATPOS_DEPENDS_PTR, satposDependPtr);
+
+ if (!(m_not_linked_slot_mask & slot_id)) // frontend with direct connection?
+ {
+ long linked_prev_ptr;
+ frontend.getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
+ while (linked_prev_ptr != -1)
+ {
+ linked_fe = (eDVBRegisteredFrontend*) linked_prev_ptr;
+ sec_fe = linked_fe->m_frontend;
+ sec_fe->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr);
+ }
+ if (satposDependPtr != -1) // we dont need uncommitted switch and rotor cmds on second output of a rotor lnb
+ diseqc_mode = eDVBSatelliteDiseqcParameters::V1_0;
+ else {
+ // in eDVBFrontend::tuneLoop we call closeFrontend and ->inc_use() in this this condition (to put the kernel frontend thread into idle state)
+ // so we must resend all diseqc stuff (voltage is disabled when the frontend is closed)
+ int state;
+ sec_fe->getState(state);
+ if (!linked_fe->m_inuse && state != eDVBFrontend::stateIdle)
+ forceChanged = true;
+ }
+ }
+
+ sec_fe->getData(eDVBFrontend::CSW, lastcsw);
+ sec_fe->getData(eDVBFrontend::UCSW, lastucsw);
+ sec_fe->getData(eDVBFrontend::TONEBURST, lastToneburst);
+ sec_fe->getData(eDVBFrontend::ROTOR_CMD, lastRotorCmd);
+ sec_fe->getData(eDVBFrontend::ROTOR_POS, curRotorPos);
+
+ if (lastcsw == lastucsw && lastToneburst == lastucsw && lastucsw == -1)
+ needDiSEqCReset = true;
+
+ if ( sat.frequency > lnb_param.m_lof_threshold )
+ band |= 1;
+ if (!(sat.polarisation & eDVBFrontendParametersSatellite::Polarisation_Vertical))
+ band |= 2;
+
+ int lof = (band&1)?lnb_param.m_lof_hi:lnb_param.m_lof_lo;
+
+ int local=0;
+
+
+ if(lnb_param.SatCR_idx == -1)
+ {
+ // calc Frequency
+ local = abs(sat.frequency
+ - ((lof - (lof % 1000)) + ((lof % 1000)>500 ? 1000 : 0)) ); //TODO für den Mist mal ein Macro schreiben
+ parm.FREQUENCY = (local - (local % 125)) + ((local % 125)>62 ? 125 : 0);
+ frontend.setData(eDVBFrontend::FREQ_OFFSET, sat.frequency - parm.FREQUENCY);
+
+ if ( voltage_mode == eDVBSatelliteSwitchParameters::_14V
+ || ( sat.polarisation & eDVBFrontendParametersSatellite::Polarisation_Vertical
+ && voltage_mode == eDVBSatelliteSwitchParameters::HV ) )
+ voltage = VOLTAGE(13);
+ else if ( voltage_mode == eDVBSatelliteSwitchParameters::_18V
+ || ( !(sat.polarisation & eDVBFrontendParametersSatellite::Polarisation_Vertical)
+ && voltage_mode == eDVBSatelliteSwitchParameters::HV ) )
+ voltage = VOLTAGE(18);
+ if ( (sw_param.m_22khz_signal == eDVBSatelliteSwitchParameters::ON)
+ || ( sw_param.m_22khz_signal == eDVBSatelliteSwitchParameters::HILO && (band&1) ) )
+ tone = iDVBFrontend::toneOn;
+ else if ( (sw_param.m_22khz_signal == eDVBSatelliteSwitchParameters::OFF)
+ || ( sw_param.m_22khz_signal == eDVBSatelliteSwitchParameters::HILO && !(band&1) ) )
+ tone = iDVBFrontend::toneOff;
+ }
+ else
+ {
+ unsigned int tmp = abs(sat.frequency
+ - ((lof - (lof % 1000)) + ((lof % 1000)>500 ? 1000 : 0)) )
+ + lnb_param.SatCRvco
+ - 1400000
+ + lnb_param.guard_offset;
+ parm.FREQUENCY = (lnb_param.SatCRvco - (tmp % 4000))+((tmp%4000)>2000?4000:0)+lnb_param.guard_offset;
+ lnb_param.UnicableTuningWord = (((tmp / 4000)+((tmp%4000)>2000?1:0))
+ | ((band & 1) ? 0x400 : 0) //HighLow
+ | ((band & 2) ? 0x800 : 0) //VertHor
+ | ((lnb_param.LNBNum & 1) ? 0 : 0x1000) //Umschaltung LNB1 LNB2
+ | (lnb_param.SatCR_idx << 13)); //Adresse des SatCR
+ eDebug("[prepare] UnicableTuningWord %#04x",lnb_param.UnicableTuningWord);
+ eDebug("[prepare] guard_offset %d",lnb_param.guard_offset);
+ frontend.setData(eDVBFrontend::FREQ_OFFSET, sat.frequency - ((lnb_param.UnicableTuningWord & 0x3FF) *4000 + 1400000 - lnb_param.SatCRvco + lof));
+ }
+
+ if (diseqc_mode >= eDVBSatelliteDiseqcParameters::V1_0)
+ {
+ if ( di_param.m_committed_cmd < eDVBSatelliteDiseqcParameters::SENDNO )
+ csw = 0xF0 | (csw << 2);
+
+ if (di_param.m_committed_cmd <= eDVBSatelliteDiseqcParameters::SENDNO)
+ csw |= band;
+
+ bool send_csw =
+ (di_param.m_committed_cmd != eDVBSatelliteDiseqcParameters::SENDNO);
+ bool changed_csw = send_csw && (forceChanged || csw != lastcsw);
+
+ bool send_ucsw =
+ (di_param.m_uncommitted_cmd && diseqc_mode > eDVBSatelliteDiseqcParameters::V1_0);
+ bool changed_ucsw = send_ucsw && (forceChanged || ucsw != lastucsw);
+
+ bool send_burst =
+ (di_param.m_toneburst_param != eDVBSatelliteDiseqcParameters::NO);
+ bool changed_burst = send_burst && (forceChanged || toneburst != lastToneburst);
+
+ int send_mask = 0; /*
+ 1 must send csw
+ 2 must send ucsw
+ 4 send toneburst first
+ 8 send toneburst at end */
+ if (changed_burst) // toneburst first and toneburst changed
+ {
+ if (di_param.m_command_order&1)
+ {
+ send_mask |= 4;
+ if ( send_csw )
+ send_mask |= 1;
+ if ( send_ucsw )
+ send_mask |= 2;
+ }
+ else
+ send_mask |= 8;
+ }
+ if (changed_ucsw)
+ {
+ send_mask |= 2;
+ if ((di_param.m_command_order&4) && send_csw)
+ send_mask |= 1;
+ if (di_param.m_command_order==4 && send_burst)
+ send_mask |= 8;
+ }
+ if (changed_csw)
+ {
+ if ( di_param.m_use_fast
+ && di_param.m_committed_cmd < eDVBSatelliteDiseqcParameters::SENDNO
+ && (lastcsw & 0xF0)
+ && ((csw / 4) == (lastcsw / 4)) )
+ eDebugNoSimulate("dont send committed cmd (fast diseqc)");
+ else
+ {
+ send_mask |= 1;
+ if (!(di_param.m_command_order&4) && send_ucsw)
+ send_mask |= 2;
+ if (!(di_param.m_command_order&1) && send_burst)
+ send_mask |= 8;
+ }
+ }
+
+#if 0
+ eDebugNoNewLine("sendmask: ");
+ for (int i=3; i >= 0; --i)
+ if ( send_mask & (1<<i) )
+ eDebugNoNewLine("1");
+ else
+ eDebugNoNewLine("0");
+ eDebug("");
+#endif
+ if (doSetVoltageToneFrontend)
+ {
+ int RotorCmd=-1;
+ bool useGotoXX = false;
+ if ( diseqc_mode == eDVBSatelliteDiseqcParameters::V1_2
+ && !sat.no_rotor_command_on_tune )
+ {
+ if (sw_param.m_rotorPosNum) // we have stored rotor pos?
+ RotorCmd=sw_param.m_rotorPosNum;
+ else // we must calc gotoxx cmd
+ {
+ eDebugNoSimulate("Entry for %d,%d? not in Rotor Table found... i try gotoXX?", sat.orbital_position / 10, sat.orbital_position % 10 );
+ useGotoXX = true;