1 #include <lib/dvb/dvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/base/nconfig.h> // access to python config
9 #ifndef I2C_SLAVE_FORCE
10 #define I2C_SLAVE_FORCE 0x0706
13 #if HAVE_DVB_API_VERSION < 3
14 #include <ost/frontend.h>
16 #define QAM_AUTO (Modulation)6
17 #define TRANSMISSION_MODE_AUTO (TransmitMode)2
18 #define BANDWIDTH_AUTO (BandWidth)3
19 #define GUARD_INTERVAL_AUTO (GuardInterval)4
20 #define HIERARCHY_AUTO (Hierarchy)4
21 #define parm_frequency parm.Frequency
22 #define parm_inversion parm.Inversion
23 #define parm_u_qpsk_symbol_rate parm.u.qpsk.SymbolRate
24 #define parm_u_qpsk_fec_inner parm.u.qpsk.FEC_inner
25 #define parm_u_qam_symbol_rate parm.u.qam.SymbolRate
26 #define parm_u_qam_fec_inner parm.u.qam.FEC_inner
27 #define parm_u_qam_modulation parm.u.qam.QAM
28 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandWidth
29 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.LP_CodeRate
30 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.HP_CodeRate
31 #define parm_u_ofdm_constellation parm.u.ofdm.Constellation
32 #define parm_u_ofdm_transmission_mode parm.u.ofdm.TransmissionMode
33 #define parm_u_ofdm_guard_interval parm.u.ofdm.guardInterval
34 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.HierarchyInformation
36 #include <linux/dvb/frontend.h>
37 #define parm_frequency parm.frequency
38 #define parm_inversion parm.inversion
39 #define parm_u_qpsk_symbol_rate parm.u.qpsk.symbol_rate
40 #define parm_u_qpsk_fec_inner parm.u.qpsk.fec_inner
41 #define parm_u_qam_symbol_rate parm.u.qam.symbol_rate
42 #define parm_u_qam_fec_inner parm.u.qam.fec_inner
43 #define parm_u_qam_modulation parm.u.qam.modulation
44 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandwidth
45 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.code_rate_LP
46 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.code_rate_HP
47 #define parm_u_ofdm_constellation parm.u.ofdm.constellation
48 #define parm_u_ofdm_transmission_mode parm.u.ofdm.transmission_mode
49 #define parm_u_ofdm_guard_interval parm.u.ofdm.guard_interval
50 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.hierarchy_information
52 #warning "FEC_9_10 already exist in dvb api ... it seems it is now ready for DVB-S2"
54 #define FEC_S2_QPSK_1_2 (fe_code_rate_t)(FEC_AUTO+1)
55 #define FEC_S2_QPSK_2_3 (fe_code_rate_t)(FEC_S2_QPSK_1_2+1)
56 #define FEC_S2_QPSK_3_4 (fe_code_rate_t)(FEC_S2_QPSK_2_3+1)
57 #define FEC_S2_QPSK_5_6 (fe_code_rate_t)(FEC_S2_QPSK_3_4+1)
58 #define FEC_S2_QPSK_7_8 (fe_code_rate_t)(FEC_S2_QPSK_5_6+1)
59 #define FEC_S2_QPSK_8_9 (fe_code_rate_t)(FEC_S2_QPSK_7_8+1)
60 #define FEC_S2_QPSK_3_5 (fe_code_rate_t)(FEC_S2_QPSK_8_9+1)
61 #define FEC_S2_QPSK_4_5 (fe_code_rate_t)(FEC_S2_QPSK_3_5+1)
62 #define FEC_S2_QPSK_9_10 (fe_code_rate_t)(FEC_S2_QPSK_4_5+1)
63 #define FEC_S2_8PSK_1_2 (fe_code_rate_t)(FEC_S2_QPSK_9_10+1)
64 #define FEC_S2_8PSK_2_3 (fe_code_rate_t)(FEC_S2_8PSK_1_2+1)
65 #define FEC_S2_8PSK_3_4 (fe_code_rate_t)(FEC_S2_8PSK_2_3+1)
66 #define FEC_S2_8PSK_5_6 (fe_code_rate_t)(FEC_S2_8PSK_3_4+1)
67 #define FEC_S2_8PSK_7_8 (fe_code_rate_t)(FEC_S2_8PSK_5_6+1)
68 #define FEC_S2_8PSK_8_9 (fe_code_rate_t)(FEC_S2_8PSK_7_8+1)
69 #define FEC_S2_8PSK_3_5 (fe_code_rate_t)(FEC_S2_8PSK_8_9+1)
70 #define FEC_S2_8PSK_4_5 (fe_code_rate_t)(FEC_S2_8PSK_3_5+1)
71 #define FEC_S2_8PSK_9_10 (fe_code_rate_t)(FEC_S2_8PSK_4_5+1)
75 #include <dvbsi++/satellite_delivery_system_descriptor.h>
76 #include <dvbsi++/cable_delivery_system_descriptor.h>
77 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
79 #define eDebugNoSimulate(x...) \
86 // eDebugNoNewLine("SIMULATE:"); \
90 #define eDebugNoSimulateNoNewLine(x...) \
97 // eDebugNoNewLine("SIMULATE:"); \
98 // eDebugNoNewLine(x); \
101 void eDVBDiseqcCommand::setCommandString(const char *str)
106 int slen = strlen(str);
109 eDebug("invalid diseqc command string length (not 2 byte aligned)");
112 if (slen > MAX_DISEQC_LENGTH*2)
114 eDebug("invalid diseqc command string length (string is to long)");
118 for (int i=0; i < slen; ++i)
120 unsigned char c = str[i];
123 case '0' ... '9': c-=48; break;
124 case 'a' ... 'f': c-=87; break;
125 case 'A' ... 'F': c-=55; break;
127 eDebug("invalid character in hex string..ignore complete diseqc command !");
141 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
143 frequency = descriptor.getFrequency() * 10;
144 symbol_rate = descriptor.getSymbolRate() * 100;
145 polarisation = descriptor.getPolarization();
146 fec = descriptor.getFecInner();
147 if ( fec != FEC::fNone && fec > FEC::f9_10 )
149 inversion = Inversion::Unknown;
150 pilot = Pilot::Unknown;
151 orbital_position = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
152 orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
153 orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
154 orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
155 if (orbital_position && (!descriptor.getWestEastFlag()))
156 orbital_position = 3600 - orbital_position;
157 system = descriptor.getModulationSystem();
158 modulation = descriptor.getModulation();
159 if (system == System::DVB_S && modulation == Modulation::M8PSK)
161 eDebug("satellite_delivery_descriptor non valid modulation type.. force QPSK");
164 rolloff = descriptor.getRollOff();
165 if (system == System::DVB_S2)
167 eDebug("SAT DVB-S2 freq %d, %s, pos %d, sr %d, fec %d, modulation %d, rolloff %d",
169 polarisation ? "hor" : "vert",
177 eDebug("SAT DVB-S freq %d, %s, pos %d, sr %d, fec %d",
179 polarisation ? "hor" : "vert",
185 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
187 frequency = descriptor.getFrequency() / 10;
188 symbol_rate = descriptor.getSymbolRate() * 100;
189 fec_inner = descriptor.getFecInner();
190 if ( fec_inner == 0xF )
191 fec_inner = FEC::fNone;
192 modulation = descriptor.getModulation();
193 if ( modulation > 0x5 )
194 modulation = Modulation::Auto;
195 inversion = Inversion::Unknown;
196 eDebug("Cable freq %d, mod %d, sr %d, fec %d",
198 modulation, symbol_rate, fec_inner);
201 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &descriptor)
203 frequency = descriptor.getCentreFrequency() * 10;
204 bandwidth = descriptor.getBandwidth();
205 if ( bandwidth > 2 ) // 5Mhz forced to auto
206 bandwidth = Bandwidth::BwAuto;
207 code_rate_HP = descriptor.getCodeRateHpStream();
208 if (code_rate_HP > 4)
209 code_rate_HP = FEC::fAuto;
210 code_rate_LP = descriptor.getCodeRateLpStream();
211 if (code_rate_LP > 4)
212 code_rate_LP = FEC::fAuto;
213 transmission_mode = descriptor.getTransmissionMode();
214 if (transmission_mode > 1) // TM4k forced to auto
215 transmission_mode = TransmissionMode::TMAuto;
216 guard_interval = descriptor.getGuardInterval();
217 if (guard_interval > 3)
218 guard_interval = GuardInterval::GI_Auto;
219 hierarchy = descriptor.getHierarchyInformation()&3;
220 modulation = descriptor.getConstellation();
222 modulation = Modulation::Auto;
223 inversion = Inversion::Unknown;
224 eDebug("Terr freq %d, bw %d, cr_hp %d, cr_lp %d, tm_mode %d, guard %d, hierarchy %d, const %d",
225 frequency, bandwidth, code_rate_HP, code_rate_LP, transmission_mode,
226 guard_interval, hierarchy, modulation);
229 eDVBFrontendParameters::eDVBFrontendParameters()
230 :m_type(-1), m_flags(0)
234 DEFINE_REF(eDVBFrontendParameters);
236 RESULT eDVBFrontendParameters::getSystem(int &t) const
244 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
246 if (m_type != iDVBFrontend::feSatellite)
252 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
254 if (m_type != iDVBFrontend::feCable)
260 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
262 if (m_type != iDVBFrontend::feTerrestrial)
268 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p, bool no_rotor_command_on_tune)
271 sat.no_rotor_command_on_tune = no_rotor_command_on_tune;
272 m_type = iDVBFrontend::feSatellite;
276 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
279 m_type = iDVBFrontend::feCable;
283 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
286 m_type = iDVBFrontend::feTerrestrial;
290 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff, bool exact) const
295 if (parm->getSystem(type))
299 diff = 1<<30; // big difference
305 case iDVBFrontend::feSatellite:
307 eDVBFrontendParametersSatellite osat;
308 if (parm->getDVBS(osat))
311 if (sat.orbital_position != osat.orbital_position)
313 else if (sat.polarisation != osat.polarisation)
315 else if (exact && sat.fec != osat.fec && sat.fec != eDVBFrontendParametersSatellite::FEC::fAuto && osat.fec != eDVBFrontendParametersSatellite::FEC::fAuto)
317 else if (exact && sat.modulation != osat.modulation && sat.modulation != eDVBFrontendParametersSatellite::Modulation::Auto && osat.modulation != eDVBFrontendParametersSatellite::Modulation::Auto)
321 diff = abs(sat.frequency - osat.frequency);
322 diff += abs(sat.symbol_rate - osat.symbol_rate);
326 case iDVBFrontend::feCable:
327 eDVBFrontendParametersCable ocable;
328 if (parm->getDVBC(ocable))
331 if (exact && cable.modulation != ocable.modulation
332 && cable.modulation != eDVBFrontendParametersCable::Modulation::Auto
333 && ocable.modulation != eDVBFrontendParametersCable::Modulation::Auto)
335 else if (exact && cable.fec_inner != ocable.fec_inner && cable.fec_inner != eDVBFrontendParametersCable::FEC::fAuto && ocable.fec_inner != eDVBFrontendParametersCable::FEC::fAuto)
339 diff = abs(cable.frequency - ocable.frequency);
340 diff += abs(cable.symbol_rate - ocable.symbol_rate);
343 case iDVBFrontend::feTerrestrial:
344 eDVBFrontendParametersTerrestrial oterrestrial;
345 if (parm->getDVBT(oterrestrial))
348 if (exact && oterrestrial.bandwidth != terrestrial.bandwidth &&
349 oterrestrial.bandwidth != eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto &&
350 terrestrial.bandwidth != eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto)
352 else if (exact && oterrestrial.modulation != terrestrial.modulation &&
353 oterrestrial.modulation != eDVBFrontendParametersTerrestrial::Modulation::Auto &&
354 terrestrial.modulation != eDVBFrontendParametersTerrestrial::Modulation::Auto)
356 else if (exact && oterrestrial.transmission_mode != terrestrial.transmission_mode &&
357 oterrestrial.transmission_mode != eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto &&
358 terrestrial.transmission_mode != eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto)
360 else if (exact && oterrestrial.guard_interval != terrestrial.guard_interval &&
361 oterrestrial.guard_interval != eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto &&
362 terrestrial.guard_interval != eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto)
364 else if (exact && oterrestrial.hierarchy != terrestrial.hierarchy &&
365 oterrestrial.hierarchy != eDVBFrontendParametersTerrestrial::Hierarchy::HAuto &&
366 terrestrial.hierarchy != eDVBFrontendParametersTerrestrial::Hierarchy::HAuto)
368 else if (exact && oterrestrial.code_rate_LP != terrestrial.code_rate_LP &&
369 oterrestrial.code_rate_LP != eDVBFrontendParametersTerrestrial::FEC::fAuto &&
370 terrestrial.code_rate_LP != eDVBFrontendParametersTerrestrial::FEC::fAuto)
372 else if (exact && oterrestrial.code_rate_HP != terrestrial.code_rate_HP &&
373 oterrestrial.code_rate_HP != eDVBFrontendParametersTerrestrial::FEC::fAuto &&
374 terrestrial.code_rate_HP != eDVBFrontendParametersTerrestrial::FEC::fAuto)
377 diff = abs(terrestrial.frequency - oterrestrial.frequency);
385 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const
389 case iDVBFrontend::feSatellite:
391 hash = (sat.orbital_position << 16);
392 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
395 case iDVBFrontend::feCable:
397 hash |= (cable.frequency/1000)&0xFFFF;
399 case iDVBFrontend::feTerrestrial:
401 hash |= (terrestrial.frequency/1000)&0xFFFF;
408 RESULT eDVBFrontendParameters::calcLockTimeout(unsigned int &timeout) const
412 case iDVBFrontend::feSatellite:
414 /* high symbol rate transponders tune faster, due to
415 requiring less zigzag and giving more symbols faster.
417 5s are definitely not enough on really low SR when
418 zigzag has to find the exact frequency first.
420 if (sat.symbol_rate > 20000000)
422 else if (sat.symbol_rate > 10000000)
428 case iDVBFrontend::feCable:
431 case iDVBFrontend::feTerrestrial:
439 DEFINE_REF(eDVBFrontend);
441 int eDVBFrontend::PriorityOrder=0;
443 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok, bool simulate)
444 :m_simulate(simulate), m_enabled(false), m_type(-1), m_dvbid(fe), m_slotid(fe)
445 ,m_fd(-1), m_need_rotor_workaround(false), m_can_handle_dvbs2(false)
446 , m_timeout(0), m_tuneTimer(0)
447 #if HAVE_DVB_API_VERSION < 3
451 #if HAVE_DVB_API_VERSION < 3
452 sprintf(m_filename, "/dev/dvb/card%d/frontend%d", adap, fe);
453 sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
455 sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
458 m_timeout = eTimer::create(eApp);
459 CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
461 m_tuneTimer = eTimer::create(eApp);
462 CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
464 for (int i=0; i<eDVBFrontend::NUM_DATA_ENTRIES; ++i)
467 m_idleInputpower[0]=m_idleInputpower[1]=0;
469 ok = !openFrontend();
473 int eDVBFrontend::openFrontend()
476 return -1; // already opened
481 #if HAVE_DVB_API_VERSION < 3
482 FrontendInfo fe_info;
484 dvb_frontend_info fe_info;
486 eDebugNoSimulate("opening frontend %d", m_dvbid);
489 if (!m_simulate || m_type == -1)
491 m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
494 eWarning("failed! (%s) %m", m_filename);
500 eWarning("frontend %d already opened", m_dvbid);
503 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
505 eWarning("ioctl FE_GET_INFO failed");
511 switch (fe_info.type)
514 m_type = iDVBFrontend::feSatellite;
517 m_type = iDVBFrontend::feCable;
520 m_type = iDVBFrontend::feTerrestrial;
523 eWarning("unknown frontend type.");
528 eDebugNoSimulate("detected %s frontend", "satellite\0cable\0 terrestrial"+fe_info.type*10);
531 #if HAVE_DVB_API_VERSION < 3
532 if (m_type == iDVBFrontend::feSatellite)
538 m_secfd = ::open(m_sec_filename, O_RDWR);
541 eWarning("failed! (%s) %m", m_sec_filename);
549 eWarning("sec %d already opened", m_dvbid);
553 setTone(iDVBFrontend::toneOff);
554 setVoltage(iDVBFrontend::voltageOff);
558 m_sn = eSocketNotifier::create(eApp, m_fd, eSocketNotifier::Read, false);
559 CONNECT(m_sn->activated, eDVBFrontend::feEvent);
565 int eDVBFrontend::closeFrontend(bool force)
567 if (!force && m_data[CUR_VOLTAGE] != -1 && m_data[CUR_VOLTAGE] != iDVBFrontend::voltageOff)
569 long tmp = m_data[LINKED_NEXT_PTR];
572 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
573 if (linked_fe->m_inuse)
575 eDebugNoSimulate("dont close frontend %d until the linked frontend %d in slot %d is still in use",
576 m_dvbid, linked_fe->m_frontend->getDVBID(), linked_fe->m_frontend->getSlotID());
579 linked_fe->m_frontend->getData(LINKED_NEXT_PTR, tmp);
585 eDebugNoSimulate("close frontend %d", m_dvbid);
586 setTone(iDVBFrontend::toneOff);
587 setVoltage(iDVBFrontend::voltageOff);
589 if (m_sec && !m_simulate)
590 m_sec->setRotorMoving(false);
594 eWarning("couldnt close frontend %d", m_dvbid);
598 setTone(iDVBFrontend::toneOff);
599 setVoltage(iDVBFrontend::voltageOff);
601 #if HAVE_DVB_API_VERSION < 3
604 if (!::close(m_secfd))
607 eWarning("couldnt close sec %d", m_dvbid);
611 m_state = stateClosed;
616 eDVBFrontend::~eDVBFrontend()
618 m_data[LINKED_PREV_PTR] = m_data[LINKED_NEXT_PTR] = -1;
622 void eDVBFrontend::feEvent(int w)
624 eDVBFrontend *sec_fe = this;
625 long tmp = m_data[LINKED_PREV_PTR];
628 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
629 sec_fe = linked_fe->m_frontend;
630 sec_fe->getData(LINKED_NEXT_PTR, tmp);
634 #if HAVE_DVB_API_VERSION < 3
637 dvb_frontend_event event;
641 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
643 if (res && (errno == EAGAIN))
648 eWarning("FE_GET_EVENT failed! %m");
655 #if HAVE_DVB_API_VERSION < 3
656 if (event.type == FE_COMPLETION_EV)
658 eDebug("(%d)fe event: status %x, inversion %s", m_dvbid, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
659 if (event.status & FE_HAS_LOCK)
669 eDebug("stateLostLock");
670 state = stateLostLock;
671 sec_fe->m_data[CSW] = sec_fe->m_data[UCSW] = sec_fe->m_data[TONEBURST] = -1; // reset diseqc
674 if (m_state != state)
677 m_stateChanged(this);
682 void eDVBFrontend::timeout()
685 if (m_state == stateTuning)
687 m_state = stateFailed;
688 m_stateChanged(this);
692 #define INRANGE(X,Y,Z) (((X<=Y) && (Y<=Z))||((Z<=Y) && (Y<=X)) ? 1 : 0)
694 int eDVBFrontend::readFrontendData(int type)
703 if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
704 eDebug("FE_READ_BER failed (%m)");
713 if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
714 eDebug("FE_READ_SNR failed (%m)");
718 case signalQualitydB: /* this will move into the driver */
723 if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
724 eDebug("FE_READ_SNR failed (%m)");
725 if (!strcmp(m_description, "BCM4501 (internal)"))
727 unsigned int SDS_SNRE = snr << 16;
729 static float SNR_COEFF[6] = {
732 197418.0 / 4194304.0,
733 -2602183.0 / 4194304.0,
734 20377212.0 / 4194304.0,
735 -37791203.0 / 4194304.0,
738 float fval1, fval2, snr_in_db;
740 fval1 = 12.44714 - (2.0 * log10(SDS_SNRE / 256.0));
741 fval2 = pow(10.0, fval1)-1;
742 fval1 = 10.0 * log10(fval2);
746 fval2 = SNR_COEFF[0];
750 fval2 += SNR_COEFF[i];
756 return (int)(snr_in_db * 100.0);
758 else if (strstr(m_description, "Alps BSBE1 C01A") ||
759 !strcmp(m_description, "Alps -S(STV0288)"))
763 else if (snr == 0xFFFF) // i think this should not happen
767 enum { REALVAL, REGVAL };
768 const long CN_lookup[31][2] = {
769 {20,8900}, {25,8680}, {30,8420}, {35,8217}, {40,7897},
770 {50,7333}, {60,6747}, {70,6162}, {80,5580}, {90,5029},
771 {100,4529}, {110,4080}, {120,3685}, {130,3316}, {140,2982},
772 {150,2688}, {160,2418}, {170,2188}, {180,1982}, {190,1802},
773 {200,1663}, {210,1520}, {220,1400}, {230,1295}, {240,1201},
774 {250,1123}, {260,1058}, {270,1004}, {280,957}, {290,920},
777 int add=strchr(m_description, '.') ? 0xA250 : 0xA100;
778 long regval = 0xFFFF - ((snr / 3) + add), // revert some dvb api calulations to get the real register value
782 if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[Imax][REGVAL]))
788 if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[i][REGVAL]))
793 return (((regval - CN_lookup[Imin][REGVAL])
794 * (CN_lookup[Imax][REALVAL] - CN_lookup[Imin][REALVAL])
795 / (CN_lookup[Imax][REGVAL] - CN_lookup[Imin][REGVAL]))
796 + CN_lookup[Imin][REALVAL]) * 10;
802 else if (!strcmp(m_description, "Alps BSBE1 702A") || // some frontends with STV0299
803 !strcmp(m_description, "Alps -S") ||
804 !strcmp(m_description, "Philips -S") ||
805 !strcmp(m_description, "LG -S") )
807 float snr_in_db=(snr-39075)/1764.7;
808 return (int)(snr_in_db * 100.0);
809 } else if (!strcmp(m_description, "Alps BSBE2"))
811 return (int)((snr >> 7) * 10.0);
813 eDebug("no SNR dB calculation for frontendtype %s yet", m_description); */
821 if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
822 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
828 #if HAVE_DVB_API_VERSION < 3
829 FrontendStatus status=0;
835 if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
836 eDebug("FE_READ_STATUS failed (%m)");
837 return !!(status&FE_HAS_LOCK);
843 #if HAVE_DVB_API_VERSION < 3
844 FrontendStatus status=0;
850 if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
851 eDebug("FE_READ_STATUS failed (%m)");
852 return !!(status&FE_HAS_SYNC);
862 void PutToDict(ePyObject &dict, const char*key, long value)
864 ePyObject item = PyInt_FromLong(value);
867 if (PyDict_SetItemString(dict, key, item))
868 eDebug("put %s to dict failed", key);
872 eDebug("could not create PyObject for %s", key);
875 void PutToDict(ePyObject &dict, const char*key, ePyObject item)
879 if (PyDict_SetItemString(dict, key, item))
880 eDebug("put %s to dict failed", key);
884 eDebug("invalid PyObject for %s", key);
887 void PutToDict(ePyObject &dict, const char*key, const char *value)
889 ePyObject item = PyString_FromString(value);
892 if (PyDict_SetItemString(dict, key, item))
893 eDebug("put %s to dict failed", key);
897 eDebug("could not create PyObject for %s", key);
900 void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
904 fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
905 int frequency = parm_frequency + freq_offset;
906 PutToDict(dict, "frequency", frequency);
907 PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
908 switch(parm_u_qpsk_fec_inner)
931 #if HAVE_DVB_API_VERSION >=3
932 case FEC_S2_8PSK_1_2:
933 case FEC_S2_QPSK_1_2:
936 case FEC_S2_8PSK_2_3:
937 case FEC_S2_QPSK_2_3:
940 case FEC_S2_8PSK_3_4:
941 case FEC_S2_QPSK_3_4:
944 case FEC_S2_8PSK_5_6:
945 case FEC_S2_QPSK_5_6:
948 case FEC_S2_8PSK_7_8:
949 case FEC_S2_QPSK_7_8:
952 case FEC_S2_8PSK_8_9:
953 case FEC_S2_QPSK_8_9:
956 case FEC_S2_8PSK_3_5:
957 case FEC_S2_QPSK_3_5:
960 case FEC_S2_8PSK_4_5:
961 case FEC_S2_QPSK_4_5:
964 case FEC_S2_8PSK_9_10:
965 case FEC_S2_QPSK_9_10:
970 PutToDict(dict, "fec_inner", tmp);
971 #if HAVE_DVB_API_VERSION >=3
972 PutToDict(dict, "modulation",
973 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
974 if (parm_u_qpsk_fec_inner > FEC_AUTO)
976 switch(parm_inversion & 0xc)
978 default: // unknown rolloff
980 tmp = "ROLLOFF_0_35";
983 tmp = "ROLLOFF_0_25";
986 tmp = "ROLLOFF_0_20";
989 PutToDict(dict, "rolloff", tmp);
990 if (parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10)
992 switch(parm_inversion & 0x30)
997 case 0x10: // pilot on
1000 case 0x20: // pilot auto
1004 PutToDict(dict, "pilot", tmp);
1011 PutToDict(dict, "modulation", "QPSK" );
1014 PutToDict(dict, "system", tmp);
1017 void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1020 #if HAVE_DVB_API_VERSION < 3
1021 PutToDict(dict, "frequency", parm_frequency);
1023 PutToDict(dict, "frequency", parm_frequency/1000);
1025 PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
1026 switch(parm_u_qam_fec_inner)
1046 #if HAVE_DVB_API_VERSION >= 3
1056 PutToDict(dict, "fec_inner", tmp);
1057 switch(parm_u_qam_modulation)
1079 PutToDict(dict, "modulation", tmp);
1082 void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1085 PutToDict(dict, "frequency", parm_frequency);
1086 switch (parm_u_ofdm_bandwidth)
1088 case BANDWIDTH_8_MHZ:
1089 tmp = "BANDWIDTH_8_MHZ";
1091 case BANDWIDTH_7_MHZ:
1092 tmp = "BANDWIDTH_7_MHZ";
1094 case BANDWIDTH_6_MHZ:
1095 tmp = "BANDWIDTH_6_MHZ";
1098 case BANDWIDTH_AUTO:
1099 tmp = "BANDWIDTH_AUTO";
1102 PutToDict(dict, "bandwidth", tmp);
1103 switch (parm_u_ofdm_code_rate_LP)
1125 PutToDict(dict, "code_rate_lp", tmp);
1126 switch (parm_u_ofdm_code_rate_HP)
1148 PutToDict(dict, "code_rate_hp", tmp);
1149 switch (parm_u_ofdm_constellation)
1165 PutToDict(dict, "constellation", tmp);
1166 switch (parm_u_ofdm_transmission_mode)
1168 case TRANSMISSION_MODE_2K:
1169 tmp = "TRANSMISSION_MODE_2K";
1171 case TRANSMISSION_MODE_8K:
1172 tmp = "TRANSMISSION_MODE_8K";
1175 case TRANSMISSION_MODE_AUTO:
1176 tmp = "TRANSMISSION_MODE_AUTO";
1179 PutToDict(dict, "transmission_mode", tmp);
1180 switch (parm_u_ofdm_guard_interval)
1182 case GUARD_INTERVAL_1_32:
1183 tmp = "GUARD_INTERVAL_1_32";
1185 case GUARD_INTERVAL_1_16:
1186 tmp = "GUARD_INTERVAL_1_16";
1188 case GUARD_INTERVAL_1_8:
1189 tmp = "GUARD_INTERVAL_1_8";
1191 case GUARD_INTERVAL_1_4:
1192 tmp = "GUARD_INTERVAL_1_4";
1195 case GUARD_INTERVAL_AUTO:
1196 tmp = "GUARD_INTERVAL_AUTO";
1199 PutToDict(dict, "guard_interval", tmp);
1200 switch (parm_u_ofdm_hierarchy_information)
1202 case HIERARCHY_NONE:
1203 tmp = "HIERARCHY_NONE";
1206 tmp = "HIERARCHY_1";
1209 tmp = "HIERARCHY_2";
1212 tmp = "HIERARCHY_4";
1215 case HIERARCHY_AUTO:
1216 tmp = "HIERARCHY_AUTO";
1219 PutToDict(dict, "hierarchy_information", tmp);
1222 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1224 if (dest && PyDict_Check(dest))
1226 const char *tmp = "UNKNOWN";
1247 PutToDict(dest, "tuner_state", tmp);
1248 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1249 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1250 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1251 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1252 int sigQualitydB = readFrontendData(signalQualitydB);
1253 if (sigQualitydB == 0x12345678) // not support yet
1255 ePyObject obj=Py_None;
1257 PutToDict(dest, "tuner_signal_quality_db", obj);
1260 PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1261 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1265 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1267 if (dest && PyDict_Check(dest))
1275 FRONTENDPARAMETERS front;
1276 if (m_fd == -1 && !original)
1278 else if (ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1280 eDebug("FE_GET_FRONTEND failed (%m)");
1284 const FRONTENDPARAMETERS &parm = original || m_simulate ? this->parm : front;
1285 const char *tmp = "INVERSION_AUTO";
1286 switch(parm_inversion)
1289 tmp = "INVERSION_ON";
1292 tmp = "INVERSION_OFF";
1298 PutToDict(dest, "inversion", tmp);
1303 fillDictWithSatelliteData(dest, original?parm:front, this);
1306 fillDictWithCableData(dest, original?parm:front);
1309 fillDictWithTerrestrialData(dest, original?parm:front);
1320 void eDVBFrontend::getFrontendData(ePyObject dest)
1322 if (dest && PyDict_Check(dest))
1325 PutToDict(dest, "tuner_number", m_slotid);
1341 PutToDict(dest, "tuner_type", tmp);
1345 #ifndef FP_IOCTL_GET_ID
1346 #define FP_IOCTL_GET_ID 0
1348 int eDVBFrontend::readInputpower()
1352 int power=m_slotid; // this is needed for read inputpower from the correct tuner !
1354 sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1355 FILE *f=fopen(proc_name, "r");
1358 if (fscanf(f, "%d", &power) != 1)
1359 eDebug("read %s failed!! (%m)", proc_name);
1361 eDebug("%s is %d\n", proc_name, power);
1366 // open front prozessor
1367 int fp=::open("/dev/dbox/fp0", O_RDWR);
1370 eDebug("couldn't open fp");
1373 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1374 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1376 eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1385 bool eDVBFrontend::setSecSequencePos(int steps)
1387 eDebugNoSimulate("set sequence pos %d", steps);
1392 if (m_sec_sequence.current() != m_sec_sequence.end())
1393 ++m_sec_sequence.current();
1398 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1399 --m_sec_sequence.current();
1405 void eDVBFrontend::tuneLoop() // called by m_tuneTimer
1408 eDVBFrontend *sec_fe = this;
1409 eDVBRegisteredFrontend *regFE = 0;
1410 long tmp = m_data[LINKED_PREV_PTR];
1413 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1414 sec_fe = prev->m_frontend;
1415 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1416 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1417 int state = sec_fe->m_state;
1418 // workaround to put the kernel frontend thread into idle state!
1419 if (state != eDVBFrontend::stateIdle && state != stateClosed)
1421 sec_fe->closeFrontend(true);
1422 state = sec_fe->m_state;
1424 // sec_fe is closed... we must reopen it here..
1425 if (state == eDVBFrontend::stateClosed)
1433 if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1435 long *sec_fe_data = sec_fe->m_data;
1436 // eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1437 switch (m_sec_sequence.current()->cmd)
1439 case eSecCommand::SLEEP:
1440 delay = m_sec_sequence.current()++->msec;
1441 eDebugNoSimulate("[SEC] sleep %dms", delay);
1443 case eSecCommand::GOTO:
1444 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1445 ++m_sec_sequence.current();
1447 case eSecCommand::SET_VOLTAGE:
1449 int voltage = m_sec_sequence.current()++->voltage;
1450 eDebugNoSimulate("[SEC] setVoltage %d", voltage);
1451 sec_fe->setVoltage(voltage);
1454 case eSecCommand::IF_VOLTAGE_GOTO:
1456 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1457 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1459 ++m_sec_sequence.current();
1462 case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1464 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1465 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1467 ++m_sec_sequence.current();
1470 case eSecCommand::IF_TONE_GOTO:
1472 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1473 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1475 ++m_sec_sequence.current();
1478 case eSecCommand::IF_NOT_TONE_GOTO:
1480 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1481 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1483 ++m_sec_sequence.current();
1486 case eSecCommand::SET_TONE:
1487 eDebugNoSimulate("[SEC] setTone %d", m_sec_sequence.current()->tone);
1488 sec_fe->setTone(m_sec_sequence.current()++->tone);
1490 case eSecCommand::SEND_DISEQC:
1491 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1492 eDebugNoSimulateNoNewLine("[SEC] sendDiseqc: ");
1493 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1494 eDebugNoSimulateNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1495 if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x00", 3))
1496 eDebugNoSimulate("(DiSEqC reset)");
1497 else if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x03", 3))
1498 eDebugNoSimulate("(DiSEqC peripherial power on)");
1500 eDebugNoSimulate("");
1501 ++m_sec_sequence.current();
1503 case eSecCommand::SEND_TONEBURST:
1504 eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1505 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1507 case eSecCommand::SET_FRONTEND:
1508 eDebugNoSimulate("[SEC] setFrontend");
1510 ++m_sec_sequence.current();
1512 case eSecCommand::START_TUNE_TIMEOUT:
1515 m_timeout->start(m_sec_sequence.current()->timeout, 1);
1516 ++m_sec_sequence.current();
1519 case eSecCommand::SET_TIMEOUT:
1520 m_timeoutCount = m_sec_sequence.current()++->val;
1521 eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
1523 case eSecCommand::IF_TIMEOUT_GOTO:
1524 if (!m_timeoutCount)
1526 eDebugNoSimulate("[SEC] rotor timout");
1527 setSecSequencePos(m_sec_sequence.current()->steps);
1530 ++m_sec_sequence.current();
1532 case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1534 int idx = m_sec_sequence.current()++->val;
1535 if ( idx == 0 || idx == 1 )
1537 m_idleInputpower[idx] = sec_fe->readInputpower();
1538 eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1541 eDebugNoSimulate("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1544 case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1546 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1547 int idx = compare.val;
1548 if ( !m_simulate && (idx == 0 || idx == 1) )
1550 int idle = sec_fe->readInputpower();
1551 int diff = abs(idle-m_idleInputpower[idx]);
1554 eDebugNoSimulate("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1555 setSecSequencePos(compare.steps);
1559 ++m_sec_sequence.current();
1562 case eSecCommand::IF_TUNER_LOCKED_GOTO:
1564 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1567 setSecSequencePos(cmd.steps);
1571 int isLocked = readFrontendData(locked);
1572 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1573 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1576 eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1579 eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
1580 cmd.lastSignal = signal;
1583 if (cmd.okcount > 4)
1585 eDebugNoSimulate("ok > 4 .. goto %d\n",cmd.steps);
1586 setSecSequencePos(cmd.steps);
1587 m_state = stateLock;
1588 m_stateChanged(this);
1597 eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1599 eDebugNoSimulate("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1601 if (!m_timeoutCount && m_retryCount > 0)
1606 ++m_sec_sequence.current();
1609 case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1610 m_runningInputpower = sec_fe->readInputpower();
1611 eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
1612 ++m_sec_sequence.current();
1614 case eSecCommand::SET_ROTOR_MOVING:
1616 m_sec->setRotorMoving(true);
1617 ++m_sec_sequence.current();
1619 case eSecCommand::SET_ROTOR_STOPPED:
1621 m_sec->setRotorMoving(false);
1622 ++m_sec_sequence.current();
1624 case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1626 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1629 setSecSequencePos(cmd.steps);
1632 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1633 const char *txt = cmd.direction ? "running" : "stopped";
1634 eDebugNoSimulate("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1636 m_runningInputpower,
1639 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1640 || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1643 eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1644 if ( cmd.okcount > 6 )
1646 eDebugNoSimulate("[SEC] rotor is %s", txt);
1647 if (setSecSequencePos(cmd.steps))
1653 eDebugNoSimulate("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1655 if (!m_timeoutCount && m_retryCount > 0)
1659 ++m_sec_sequence.current();
1662 case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1663 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1664 setSecSequencePos(m_sec_sequence.current()->steps);
1666 ++m_sec_sequence.current();
1668 case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1669 eDebugNoSimulate("[SEC] invalidate current switch params");
1670 sec_fe_data[CSW] = -1;
1671 sec_fe_data[UCSW] = -1;
1672 sec_fe_data[TONEBURST] = -1;
1673 ++m_sec_sequence.current();
1675 case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1676 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1677 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1678 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1679 eDebugNoSimulate("[SEC] update current switch params");
1680 ++m_sec_sequence.current();
1682 case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1683 eDebugNoSimulate("[SEC] invalidate current rotorparams");
1684 sec_fe_data[ROTOR_CMD] = -1;
1685 sec_fe_data[ROTOR_POS] = -1;
1686 ++m_sec_sequence.current();
1688 case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1689 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1690 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1691 eDebugNoSimulate("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1692 ++m_sec_sequence.current();
1694 case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1695 m_retryCount = m_sec_sequence.current()++->val;
1696 eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
1698 case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1701 eDebugNoSimulate("[SEC] no more rotor retrys");
1702 setSecSequencePos(m_sec_sequence.current()->steps);
1705 ++m_sec_sequence.current();
1707 case eSecCommand::SET_POWER_LIMITING_MODE:
1712 sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1713 FILE *f=fopen(proc_name, "w");
1714 if (f) // new interface exist?
1716 bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1717 if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1718 eDebugNoSimulate("write %s failed!! (%m)", proc_name);
1720 eDebugNoSimulate("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1723 else if (sec_fe->m_need_rotor_workaround)
1726 int slotid = sec_fe->m_slotid;
1727 // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1729 sprintf(dev, "/dev/i2c/%d", slotid);
1730 else if (slotid == 2)
1731 sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1732 else if (slotid == 3)
1733 sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1734 int fd = ::open(dev, O_RDWR);
1736 unsigned char data[2];
1737 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1738 if(::read(fd, data, 1) != 1)
1739 eDebugNoSimulate("[SEC] error read lnbp (%m)");
1740 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1742 data[0] |= 0x80; // enable static current limiting
1743 eDebugNoSimulate("[SEC] set static current limiting");
1747 data[0] &= ~0x80; // enable dynamic current limiting
1748 eDebugNoSimulate("[SEC] set dynamic current limiting");
1750 if(::write(fd, data, 1) != 1)
1751 eDebugNoSimulate("[SEC] error write lnbp (%m)");
1755 ++m_sec_sequence.current();
1759 eDebugNoSimulate("[SEC] unhandled sec command %d",
1760 ++m_sec_sequence.current()->cmd);
1761 ++m_sec_sequence.current();
1764 m_tuneTimer->start(delay,true);
1768 if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
1772 void eDVBFrontend::setFrontend()
1776 eDebug("setting frontend %d", m_dvbid);
1779 if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1781 perror("FE_SET_FRONTEND failed");
1787 RESULT eDVBFrontend::getFrontendType(int &t)
1795 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1800 eWarning("no SEC module active!");
1803 res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1806 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1809 feparm.polarisation,
1813 feparm.orbital_position);
1814 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1815 switch (feparm.inversion)
1817 case eDVBFrontendParametersSatellite::Inversion::On:
1818 parm_inversion = INVERSION_ON;
1820 case eDVBFrontendParametersSatellite::Inversion::Off:
1821 parm_inversion = INVERSION_OFF;
1824 case eDVBFrontendParametersSatellite::Inversion::Unknown:
1825 parm_inversion = INVERSION_AUTO;
1828 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1831 case eDVBFrontendParametersSatellite::FEC::fNone:
1832 parm_u_qpsk_fec_inner = FEC_NONE;
1834 case eDVBFrontendParametersSatellite::FEC::f1_2:
1835 parm_u_qpsk_fec_inner = FEC_1_2;
1837 case eDVBFrontendParametersSatellite::FEC::f2_3:
1838 parm_u_qpsk_fec_inner = FEC_2_3;
1840 case eDVBFrontendParametersSatellite::FEC::f3_4:
1841 parm_u_qpsk_fec_inner = FEC_3_4;
1843 case eDVBFrontendParametersSatellite::FEC::f5_6:
1844 parm_u_qpsk_fec_inner = FEC_5_6;
1846 case eDVBFrontendParametersSatellite::FEC::f7_8:
1847 parm_u_qpsk_fec_inner = FEC_7_8;
1850 eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
1851 case eDVBFrontendParametersSatellite::FEC::fAuto:
1852 parm_u_qpsk_fec_inner = FEC_AUTO;
1855 #if HAVE_DVB_API_VERSION >= 3
1860 case eDVBFrontendParametersSatellite::FEC::f1_2:
1861 parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1863 case eDVBFrontendParametersSatellite::FEC::f2_3:
1864 parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1866 case eDVBFrontendParametersSatellite::FEC::f3_4:
1867 parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1869 case eDVBFrontendParametersSatellite::FEC::f3_5:
1870 parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1872 case eDVBFrontendParametersSatellite::FEC::f4_5:
1873 parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1875 case eDVBFrontendParametersSatellite::FEC::f5_6:
1876 parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1878 case eDVBFrontendParametersSatellite::FEC::f7_8:
1879 parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1881 case eDVBFrontendParametersSatellite::FEC::f8_9:
1882 parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1884 case eDVBFrontendParametersSatellite::FEC::f9_10:
1885 parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1888 eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
1891 parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1892 if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1893 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1894 // 8PSK fec driver values are decimal 9 bigger
1895 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1899 // FIXME !!! get frequency range from tuner
1900 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1902 eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1905 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
1910 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1912 #if HAVE_DVB_API_VERSION < 3
1913 parm_frequency = feparm.frequency;
1915 parm_frequency = feparm.frequency * 1000;
1917 parm_u_qam_symbol_rate = feparm.symbol_rate;
1918 switch (feparm.modulation)
1920 case eDVBFrontendParametersCable::Modulation::QAM16:
1921 parm_u_qam_modulation = QAM_16;
1923 case eDVBFrontendParametersCable::Modulation::QAM32:
1924 parm_u_qam_modulation = QAM_32;
1926 case eDVBFrontendParametersCable::Modulation::QAM64:
1927 parm_u_qam_modulation = QAM_64;
1929 case eDVBFrontendParametersCable::Modulation::QAM128:
1930 parm_u_qam_modulation = QAM_128;
1932 case eDVBFrontendParametersCable::Modulation::QAM256:
1933 parm_u_qam_modulation = QAM_256;
1936 case eDVBFrontendParametersCable::Modulation::Auto:
1937 parm_u_qam_modulation = QAM_AUTO;
1940 switch (feparm.inversion)
1942 case eDVBFrontendParametersCable::Inversion::On:
1943 parm_inversion = INVERSION_ON;
1945 case eDVBFrontendParametersCable::Inversion::Off:
1946 parm_inversion = INVERSION_OFF;
1949 case eDVBFrontendParametersCable::Inversion::Unknown:
1950 parm_inversion = INVERSION_AUTO;
1953 switch (feparm.fec_inner)
1955 case eDVBFrontendParametersCable::FEC::fNone:
1956 parm_u_qam_fec_inner = FEC_NONE;
1958 case eDVBFrontendParametersCable::FEC::f1_2:
1959 parm_u_qam_fec_inner = FEC_1_2;
1961 case eDVBFrontendParametersCable::FEC::f2_3:
1962 parm_u_qam_fec_inner = FEC_2_3;
1964 case eDVBFrontendParametersCable::FEC::f3_4:
1965 parm_u_qam_fec_inner = FEC_3_4;
1967 case eDVBFrontendParametersCable::FEC::f5_6:
1968 parm_u_qam_fec_inner = FEC_5_6;
1970 case eDVBFrontendParametersCable::FEC::f7_8:
1971 parm_u_qam_fec_inner = FEC_7_8;
1973 #if HAVE_DVB_API_VERSION >= 3
1974 case eDVBFrontendParametersCable::FEC::f8_9:
1975 parm_u_qam_fec_inner = FEC_8_9;
1979 case eDVBFrontendParametersCable::FEC::fAuto:
1980 parm_u_qam_fec_inner = FEC_AUTO;
1983 eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1984 parm_frequency/1000,
1985 parm_u_qam_symbol_rate,
1986 parm_u_qam_fec_inner,
1987 parm_u_qam_modulation,
1992 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1994 parm_frequency = feparm.frequency;
1996 switch (feparm.bandwidth)
1998 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1999 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
2001 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
2002 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
2004 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
2005 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2008 case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
2009 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2012 switch (feparm.code_rate_LP)
2014 case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2015 parm_u_ofdm_code_rate_LP = FEC_1_2;
2017 case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2018 parm_u_ofdm_code_rate_LP = FEC_2_3;
2020 case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2021 parm_u_ofdm_code_rate_LP = FEC_3_4;
2023 case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2024 parm_u_ofdm_code_rate_LP = FEC_5_6;
2026 case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2027 parm_u_ofdm_code_rate_LP = FEC_7_8;
2030 case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2031 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2034 switch (feparm.code_rate_HP)
2036 case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2037 parm_u_ofdm_code_rate_HP = FEC_1_2;
2039 case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2040 parm_u_ofdm_code_rate_HP = FEC_2_3;
2042 case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2043 parm_u_ofdm_code_rate_HP = FEC_3_4;
2045 case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2046 parm_u_ofdm_code_rate_HP = FEC_5_6;
2048 case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2049 parm_u_ofdm_code_rate_HP = FEC_7_8;
2052 case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2053 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2056 switch (feparm.modulation)
2058 case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
2059 parm_u_ofdm_constellation = QPSK;
2061 case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
2062 parm_u_ofdm_constellation = QAM_16;
2064 case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
2065 parm_u_ofdm_constellation = QAM_64;
2068 case eDVBFrontendParametersTerrestrial::Modulation::Auto:
2069 parm_u_ofdm_constellation = QAM_AUTO;
2072 switch (feparm.transmission_mode)
2074 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
2075 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2077 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
2078 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2081 case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
2082 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2085 switch (feparm.guard_interval)
2087 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
2088 parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2090 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2091 parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2093 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2094 parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2096 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2097 parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2100 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2101 parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2104 switch (feparm.hierarchy)
2106 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2107 parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2109 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2110 parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2112 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2113 parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2115 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2116 parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2119 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2120 parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2123 switch (feparm.inversion)
2125 case eDVBFrontendParametersTerrestrial::Inversion::On:
2126 parm_inversion = INVERSION_ON;
2128 case eDVBFrontendParametersTerrestrial::Inversion::Off:
2129 parm_inversion = INVERSION_OFF;
2132 case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2133 parm_inversion = INVERSION_AUTO;
2139 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2141 unsigned int timeout = 5000;
2142 eDebugNoSimulate("(%d)tune", m_dvbid);
2148 if (!m_sn && !m_simulate)
2150 eDebug("no frontend device opened... do not try to tune !!!");
2164 m_sec_sequence.clear();
2166 where.calcLockTimeout(timeout);
2172 eDVBFrontendParametersSatellite feparm;
2173 if (where.getDVBS(feparm))
2175 eDebug("no dvbs data!");
2180 m_sec->setRotorMoving(false);
2181 res=prepare_sat(feparm, timeout);
2189 eDVBFrontendParametersCable feparm;
2190 if (where.getDVBC(feparm))
2195 res=prepare_cable(feparm);
2199 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2200 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2205 eDVBFrontendParametersTerrestrial feparm;
2206 if (where.getDVBT(feparm))
2208 eDebug("no -T data");
2212 res=prepare_terrestrial(feparm);
2216 std::string enable_5V;
2217 char configStr[255];
2218 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2219 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2220 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2221 if (enable_5V == "True")
2222 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2224 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2225 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2231 m_sec_sequence.current() = m_sec_sequence.begin();
2235 m_tuneTimer->start(0,true);
2236 if (m_state != stateTuning)
2239 m_state = stateTuning;
2240 m_stateChanged(this);
2249 m_tuneTimer->stop();
2253 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2255 connection = new eConnection(this, m_stateChanged.connect(stateChange));
2259 RESULT eDVBFrontend::setVoltage(int voltage)
2261 if (m_type == feCable)
2263 #if HAVE_DVB_API_VERSION < 3
2266 bool increased=false;
2267 fe_sec_voltage_t vlt;
2269 m_data[CUR_VOLTAGE]=voltage;
2273 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2274 vlt = SEC_VOLTAGE_OFF;
2277 #if HAVE_DVB_API_VERSION < 3
2278 vlt = SEC_VOLTAGE_13_5;
2284 vlt = SEC_VOLTAGE_13;
2287 #if HAVE_DVB_API_VERSION < 3
2288 vlt = SEC_VOLTAGE_18_5;
2294 vlt = SEC_VOLTAGE_18;
2301 #if HAVE_DVB_API_VERSION < 3
2302 return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2304 if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2305 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2306 return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2310 RESULT eDVBFrontend::getState(int &state)
2316 RESULT eDVBFrontend::setTone(int t)
2318 if (m_type != feSatellite)
2320 #if HAVE_DVB_API_VERSION < 3
2323 fe_sec_tone_mode_t tone;
2332 tone = SEC_TONE_OFF;
2339 #if HAVE_DVB_API_VERSION < 3
2340 return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2342 return ::ioctl(m_fd, FE_SET_TONE, tone);
2346 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2347 #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2350 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2354 #if HAVE_DVB_API_VERSION < 3
2355 struct secCommand cmd;
2356 cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2357 cmd.u.diseqc.cmdtype = diseqc.data[0];
2358 cmd.u.diseqc.addr = diseqc.data[1];
2359 cmd.u.diseqc.cmd = diseqc.data[2];
2360 cmd.u.diseqc.numParams = diseqc.len-3;
2361 memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2362 if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2364 struct dvb_diseqc_master_cmd cmd;
2365 memcpy(cmd.msg, diseqc.data, diseqc.len);
2366 cmd.msg_len = diseqc.len;
2367 if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2373 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2374 #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2376 RESULT eDVBFrontend::sendToneburst(int burst)
2380 #if HAVE_DVB_API_VERSION < 3
2381 secMiniCmd cmd = SEC_MINI_NONE;
2383 fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2385 if ( burst == eDVBSatelliteDiseqcParameters::A )
2387 else if ( burst == eDVBSatelliteDiseqcParameters::B )
2389 #if HAVE_DVB_API_VERSION < 3
2390 if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2393 if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2399 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2405 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2407 m_sec_sequence = list;
2411 RESULT eDVBFrontend::getData(int num, long &data)
2413 if ( num < NUM_DATA_ENTRIES )
2421 RESULT eDVBFrontend::setData(int num, long val)
2423 if ( num < NUM_DATA_ENTRIES )
2431 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2434 if (feparm->getSystem(type) || type != m_type || !m_enabled)
2436 if (m_type == eDVBFrontend::feSatellite)
2439 eDVBFrontendParametersSatellite sat_parm;
2440 int ret = feparm->getDVBS(sat_parm);
2442 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2444 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2445 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2449 else if (m_type == eDVBFrontend::feCable)
2450 return 2; // more prio for cable frontends
2451 else if (m_type == eDVBFrontend::feTerrestrial)
2456 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2458 ePyObject Id, Descr, Enabled, IsDVBS2;
2459 if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2461 Id = PyTuple_GET_ITEM(obj, 0);
2462 Descr = PyTuple_GET_ITEM(obj, 1);
2463 Enabled = PyTuple_GET_ITEM(obj, 2);
2464 IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2465 if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2467 strcpy(m_description, PyString_AS_STRING(Descr));
2468 m_slotid = PyInt_AsLong(Id);
2469 m_enabled = Enabled == Py_True;
2470 // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2471 m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2472 !!strstr(m_description, "Alps BSBE2") ||
2473 !!strstr(m_description, "Alps -S") ||
2474 !!strstr(m_description, "BCM4501");
2475 m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2476 eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2477 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2480 PyErr_SetString(PyExc_StandardError,
2481 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");