0ae2dd35212ba4fa357526efdfd0a4368b09dd9a
[enigma2.git] / lib / dvb / frontend.cpp
1 #include <lib/dvb/dvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/base/nconfig.h> // access to python config
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8
9 #ifndef I2C_SLAVE_FORCE
10 #define I2C_SLAVE_FORCE 0x0706
11 #endif
12
13 #if HAVE_DVB_API_VERSION < 3
14 #include <ost/frontend.h>
15 #include <ost/sec.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
35 #else
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
51 #ifdef FEC_9_10
52         #warning "FEC_9_10 already exist in dvb api ... it seems it is now ready for DVB-S2"
53 #else
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)
72 #endif
73 #endif
74
75 #include <dvbsi++/satellite_delivery_system_descriptor.h>
76 #include <dvbsi++/cable_delivery_system_descriptor.h>
77 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
78
79 void eDVBDiseqcCommand::setCommandString(const char *str)
80 {
81         if (!str)
82                 return;
83         len=0;
84         int slen = strlen(str);
85         if (slen % 2)
86         {
87                 eDebug("invalid diseqc command string length (not 2 byte aligned)");
88                 return;
89         }
90         if (slen > MAX_DISEQC_LENGTH*2)
91         {
92                 eDebug("invalid diseqc command string length (string is to long)");
93                 return;
94         }
95         unsigned char val=0;
96         for (int i=0; i < slen; ++i)
97         {
98                 unsigned char c = str[i];
99                 switch(c)
100                 {
101                         case '0' ... '9': c-=48; break;
102                         case 'a' ... 'f': c-=87; break;
103                         case 'A' ... 'F': c-=55; break;
104                         default:
105                                 eDebug("invalid character in hex string..ignore complete diseqc command !");
106                                 return;
107                 }
108                 if ( i % 2 )
109                 {
110                         val |= c;
111                         data[i/2] = val;
112                 }
113                 else
114                         val = c << 4;
115         }
116         len = slen/2;
117 }
118
119 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
120 {
121         frequency    = descriptor.getFrequency() * 10;
122         symbol_rate  = descriptor.getSymbolRate() * 100;
123         polarisation = descriptor.getPolarization();
124         fec = descriptor.getFecInner();
125         if ( fec != FEC::fNone && fec > FEC::f9_10 )
126                 fec = FEC::fAuto;
127         inversion = Inversion::Unknown;
128         pilot = Pilot::Unknown;
129         orbital_position  = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
130         orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
131         orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
132         orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
133         if (orbital_position && (!descriptor.getWestEastFlag()))
134                 orbital_position = 3600 - orbital_position;
135         system = descriptor.getModulationSystem();
136         modulation = descriptor.getModulation();
137         if (system == System::DVB_S && modulation == Modulation::M8PSK)
138         {
139                 eDebug("satellite_delivery_descriptor non valid modulation type.. force QPSK");
140                 modulation=QPSK;
141         }
142         rolloff = descriptor.getRollOff();
143         if (system == System::DVB_S2)
144         {
145                 eDebug("SAT DVB-S2 freq %d, %s, pos %d, sr %d, fec %d, modulation %d, rolloff %d",
146                         frequency,
147                         polarisation ? "hor" : "vert",
148                         orbital_position,
149                         symbol_rate, fec,
150                         modulation,
151                         rolloff);
152         }
153         else
154         {
155                 eDebug("SAT DVB-S freq %d, %s, pos %d, sr %d, fec %d",
156                         frequency,
157                         polarisation ? "hor" : "vert",
158                         orbital_position,
159                         symbol_rate, fec);
160         }
161 }
162
163 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
164 {
165         frequency = descriptor.getFrequency() / 10;
166         symbol_rate = descriptor.getSymbolRate() * 100;
167         fec_inner = descriptor.getFecInner();
168         if ( fec_inner == 0xF )
169                 fec_inner = FEC::fNone;
170         modulation = descriptor.getModulation();
171         if ( modulation > 0x5 )
172                 modulation = Modulation::Auto;
173         inversion = Inversion::Unknown;
174         eDebug("Cable freq %d, mod %d, sr %d, fec %d",
175                 frequency,
176                 modulation, symbol_rate, fec_inner);
177 }
178
179 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &descriptor)
180 {
181         frequency = descriptor.getCentreFrequency() * 10;
182         bandwidth = descriptor.getBandwidth();
183         if ( bandwidth > 2 ) // 5Mhz forced to auto
184                 bandwidth = Bandwidth::BwAuto;
185         code_rate_HP = descriptor.getCodeRateHpStream();
186         if (code_rate_HP > 4)
187                 code_rate_HP = FEC::fAuto;
188         code_rate_LP = descriptor.getCodeRateLpStream();
189         if (code_rate_LP > 4)
190                 code_rate_LP = FEC::fAuto;
191         transmission_mode = descriptor.getTransmissionMode();
192         if (transmission_mode > 1) // TM4k forced to auto
193                 transmission_mode = TransmissionMode::TMAuto;
194         guard_interval = descriptor.getGuardInterval();
195         if (guard_interval > 3)
196                 guard_interval = GuardInterval::GI_Auto;
197         hierarchy = descriptor.getHierarchyInformation()&3;
198         modulation = descriptor.getConstellation();
199         if (modulation > 2)
200                 modulation = Modulation::Auto;
201         inversion = Inversion::Unknown;
202         eDebug("Terr freq %d, bw %d, cr_hp %d, cr_lp %d, tm_mode %d, guard %d, hierarchy %d, const %d",
203                 frequency, bandwidth, code_rate_HP, code_rate_LP, transmission_mode,
204                 guard_interval, hierarchy, modulation);
205 }
206
207 eDVBFrontendParameters::eDVBFrontendParameters()
208         :m_type(-1), m_flags(0)
209 {
210 }
211
212 DEFINE_REF(eDVBFrontendParameters);
213
214 RESULT eDVBFrontendParameters::getSystem(int &t) const
215 {
216         if (m_type == -1)
217                 return -1;
218         t = m_type;
219         return 0;
220 }
221
222 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
223 {
224         if (m_type != iDVBFrontend::feSatellite)
225                 return -1;
226         p = sat;
227         return 0;
228 }
229
230 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
231 {
232         if (m_type != iDVBFrontend::feCable)
233                 return -1;
234         p = cable;
235         return 0;
236 }
237
238 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
239 {
240         if (m_type != iDVBFrontend::feTerrestrial)
241                 return -1;
242         p = terrestrial;
243         return 0;
244 }
245
246 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p, bool no_rotor_command_on_tune)
247 {
248         sat = p;
249         sat.no_rotor_command_on_tune = no_rotor_command_on_tune;
250         m_type = iDVBFrontend::feSatellite;
251         return 0;
252 }
253
254 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
255 {
256         cable = p;
257         m_type = iDVBFrontend::feCable;
258         return 0;
259 }
260
261 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
262 {
263         terrestrial = p;
264         m_type = iDVBFrontend::feTerrestrial;
265         return 0;
266 }
267
268 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff, bool exact) const
269 {
270         if (!parm)
271                 return -1;
272         int type;
273         if (parm->getSystem(type))
274                 return -1;
275         if (type != m_type)
276         {
277                 diff = 1<<30; // big difference
278                 return 0;
279         }
280
281         switch (type)
282         {
283         case iDVBFrontend::feSatellite:
284         {
285                 eDVBFrontendParametersSatellite osat;
286                 if (parm->getDVBS(osat))
287                         return -2;
288
289                 if (sat.orbital_position != osat.orbital_position)
290                         diff = 1<<29;
291                 else if (sat.polarisation != osat.polarisation)
292                         diff = 1<<28;
293                 else if (exact && sat.fec != osat.fec && sat.fec != eDVBFrontendParametersSatellite::FEC::fAuto && osat.fec != eDVBFrontendParametersSatellite::FEC::fAuto)
294                         diff = 1<<27;
295                 else if (exact && sat.modulation != osat.modulation && sat.modulation != eDVBFrontendParametersSatellite::Modulation::Auto && osat.modulation != eDVBFrontendParametersSatellite::Modulation::Auto)
296                         diff = 1<<27;
297                 else
298                 {
299                         diff = abs(sat.frequency - osat.frequency);
300                         diff += abs(sat.symbol_rate - osat.symbol_rate);
301                 }
302                 return 0;
303         }
304         case iDVBFrontend::feCable:
305                 eDVBFrontendParametersCable ocable;
306                 if (parm->getDVBC(ocable))
307                         return -2;
308
309                 if (exact && cable.modulation != ocable.modulation
310                         && cable.modulation != eDVBFrontendParametersCable::Modulation::Auto
311                         && ocable.modulation != eDVBFrontendParametersCable::Modulation::Auto)
312                         diff = 1 << 29;
313                 else if (exact && cable.fec_inner != ocable.fec_inner && cable.fec_inner != eDVBFrontendParametersCable::FEC::fAuto && ocable.fec_inner != eDVBFrontendParametersCable::FEC::fAuto)
314                         diff = 1 << 27;
315                 else
316                 {
317                         diff = abs(cable.frequency - ocable.frequency);
318                         diff += abs(cable.symbol_rate - ocable.symbol_rate);
319                 }
320                 return 0;
321         case iDVBFrontend::feTerrestrial:
322                 eDVBFrontendParametersTerrestrial oterrestrial;
323                 if (parm->getDVBT(oterrestrial))
324                         return -2;
325
326
327                 if (exact && oterrestrial.bandwidth != terrestrial.bandwidth &&
328                         oterrestrial.bandwidth != eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto &&
329                         terrestrial.bandwidth != eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto)
330                         diff = 1 << 30;
331                 else if (exact && oterrestrial.modulation != terrestrial.modulation &&
332                         oterrestrial.modulation != eDVBFrontendParametersTerrestrial::Modulation::Auto &&
333                         terrestrial.modulation != eDVBFrontendParametersTerrestrial::Modulation::Auto)
334                         diff = 1 << 30;
335                 else if (exact && oterrestrial.transmission_mode != terrestrial.transmission_mode &&
336                         oterrestrial.transmission_mode != eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto &&
337                         terrestrial.transmission_mode != eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto)
338                         diff = 1 << 30;
339                 else if (exact && oterrestrial.guard_interval != terrestrial.guard_interval &&
340                         oterrestrial.guard_interval != eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto &&
341                         terrestrial.guard_interval != eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto)
342                         diff = 1 << 30;
343                 else if (exact && oterrestrial.hierarchy != terrestrial.hierarchy &&
344                         oterrestrial.hierarchy != eDVBFrontendParametersTerrestrial::Hierarchy::HAuto &&
345                         terrestrial.hierarchy != eDVBFrontendParametersTerrestrial::Hierarchy::HAuto)
346                         diff = 1 << 30;
347                 else if (exact && oterrestrial.code_rate_LP != terrestrial.code_rate_LP &&
348                         oterrestrial.code_rate_LP != eDVBFrontendParametersTerrestrial::FEC::fAuto &&
349                         terrestrial.code_rate_LP != eDVBFrontendParametersTerrestrial::FEC::fAuto)
350                         diff = 1 << 30;
351                 else if (exact && oterrestrial.code_rate_HP != terrestrial.code_rate_HP &&
352                         oterrestrial.code_rate_HP != eDVBFrontendParametersTerrestrial::FEC::fAuto &&
353                         terrestrial.code_rate_HP != eDVBFrontendParametersTerrestrial::FEC::fAuto)
354                         diff = 1 << 30;
355                 else
356                         diff = abs(terrestrial.frequency - oterrestrial.frequency);
357                 return 0;
358         default:
359                 return -1;
360         }
361         return 0;
362 }
363
364 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const
365 {
366         switch (m_type)
367         {
368         case iDVBFrontend::feSatellite:
369         {
370                 hash = (sat.orbital_position << 16);
371                 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
372                 return 0;
373         }
374         case iDVBFrontend::feCable:
375                 hash = 0xFFFF0000;
376                 hash |= (cable.frequency/1000)&0xFFFF;
377                 return 0;
378         case iDVBFrontend::feTerrestrial:
379                 hash = 0xEEEE0000;
380                 hash |= (terrestrial.frequency/1000)&0xFFFF;
381                 return 0;
382         default:
383                 return -1;
384         }
385 }
386
387 RESULT eDVBFrontendParameters::calcLockTimeout(unsigned int &timeout) const
388 {
389         switch (m_type)
390         {
391         case iDVBFrontend::feSatellite:
392         {
393                         /* high symbol rate transponders tune faster, due to 
394                                 requiring less zigzag and giving more symbols faster. 
395
396                                 5s are definitely not enough on really low SR when
397                                 zigzag has to find the exact frequency first.
398                         */
399                 if (sat.symbol_rate > 20000000)
400                         timeout = 5000;
401                 else if (sat.symbol_rate > 10000000)
402                         timeout = 10000;
403                 else
404                         timeout = 20000;
405                 return 0;
406         }
407         case iDVBFrontend::feCable:
408                 timeout = 5000;
409                 return 0;
410         case iDVBFrontend::feTerrestrial:
411                 timeout = 5000;
412                 return 0;
413         default:
414                 return -1;
415         }
416 }
417
418 DEFINE_REF(eDVBFrontend);
419
420 int eDVBFrontend::PriorityOrder=0;
421
422 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok)
423         :m_enabled(false), m_type(-1), m_dvbid(fe), m_slotid(fe)
424         ,m_fd(-1), m_need_rotor_workaround(false), m_can_handle_dvbs2(false)
425         ,m_sn(0), m_timeout(0), m_tuneTimer(0)
426 #if HAVE_DVB_API_VERSION < 3
427         ,m_secfd(-1)
428 #endif
429 {
430 #if HAVE_DVB_API_VERSION < 3
431         sprintf(m_filename, "/dev/dvb/card%d/frontend%d", adap, fe);
432         sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
433 #else
434         sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
435 #endif
436         m_timeout = new eTimer(eApp);
437         CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
438
439         m_tuneTimer = new eTimer(eApp);
440         CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
441
442         for (int i=0; i<eDVBFrontend::NUM_DATA_ENTRIES; ++i)
443                 m_data[i] = -1;
444
445         m_idleInputpower[0]=m_idleInputpower[1]=0;
446
447         ok = !openFrontend();
448         closeFrontend();
449 }
450
451 int eDVBFrontend::openFrontend()
452 {
453         if (m_sn)
454                 return -1;  // already opened
455
456         m_state=stateIdle;
457         m_tuning=0;
458
459 #if HAVE_DVB_API_VERSION < 3
460         FrontendInfo fe_info;
461 #else
462         dvb_frontend_info fe_info;
463 #endif
464         eDebug("opening frontend %d", m_dvbid);
465         if (m_fd < 0)
466         {
467                 m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
468                 if (m_fd < 0)
469                 {
470                         eWarning("failed! (%s) %m", m_filename);
471                         return -1;
472                 }
473         }
474         else
475                 eWarning("frontend %d already opened", m_dvbid);
476         if (m_type == -1)
477         {
478                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
479                 {
480                         eWarning("ioctl FE_GET_INFO failed");
481                         ::close(m_fd);
482                         m_fd = -1;
483                         return -1;
484                 }
485
486                 switch (fe_info.type)
487                 {
488                 case FE_QPSK:
489                         m_type = iDVBFrontend::feSatellite;
490                         break;
491                 case FE_QAM:
492                         m_type = iDVBFrontend::feCable;
493                         break;
494                 case FE_OFDM:
495                         m_type = iDVBFrontend::feTerrestrial;
496                         break;
497                 default:
498                         eWarning("unknown frontend type.");
499                         ::close(m_fd);
500                         m_fd = -1;
501                         return -1;
502                 }
503                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
504         }
505
506 #if HAVE_DVB_API_VERSION < 3
507         if (m_type == iDVBFrontend::feSatellite)
508         {
509                         if (m_secfd < 0)
510                         {
511                                 m_secfd = ::open(m_sec_filename, O_RDWR);
512                                 if (m_secfd < 0)
513                                 {
514                                         eWarning("failed! (%s) %m", m_sec_filename);
515                                         ::close(m_fd);
516                                         m_fd=-1;
517                                         return -1;
518                                 }
519                         }
520                         else
521                                 eWarning("sec %d already opened", m_dvbid);
522         }
523 #endif
524
525         setTone(iDVBFrontend::toneOff);
526         setVoltage(iDVBFrontend::voltageOff);
527
528         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read, false);
529         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
530
531         return 0;
532 }
533
534 int eDVBFrontend::closeFrontend(bool force)
535 {
536         if (!force && m_data[CUR_VOLTAGE] != -1 && m_data[CUR_VOLTAGE] != iDVBFrontend::voltageOff)
537         {
538                 long tmp = m_data[LINKED_NEXT_PTR];
539                 while (tmp != -1)
540                 {
541                         eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
542                         if (linked_fe->m_inuse)
543                         {
544                                 eDebug("dont close frontend %d until the linked frontend %d in slot %d is still in use",
545                                         m_dvbid, linked_fe->m_frontend->getDVBID(), linked_fe->m_frontend->getSlotID());
546                                 return -1;
547                         }
548                         linked_fe->m_frontend->getData(LINKED_NEXT_PTR, tmp);
549                 }
550         }
551         if (m_fd >= 0)
552         {
553                 eDebug("close frontend %d", m_dvbid);
554                 m_tuneTimer->stop();
555                 setTone(iDVBFrontend::toneOff);
556                 setVoltage(iDVBFrontend::voltageOff);
557                 if (m_sec)
558                         m_sec->setRotorMoving(false);
559                 if (!::close(m_fd))
560                         m_fd=-1;
561                 else
562                         eWarning("couldnt close frontend %d", m_dvbid);
563         }
564 #if HAVE_DVB_API_VERSION < 3
565         if (m_secfd >= 0)
566         {
567                 if (!::close(m_secfd))
568                         m_secfd=-1;
569                 else
570                         eWarning("couldnt close sec %d", m_dvbid);
571         }
572 #endif
573         delete m_sn;
574         m_sn=0;
575         m_state = stateClosed;
576
577         return 0;
578 }
579
580 eDVBFrontend::~eDVBFrontend()
581 {
582         m_data[LINKED_PREV_PTR] = m_data[LINKED_NEXT_PTR] = -1;
583         closeFrontend();
584         delete m_timeout;
585         delete m_tuneTimer;
586 }
587
588 void eDVBFrontend::feEvent(int w)
589 {
590         eDVBFrontend *sec_fe = this;
591         long tmp = m_data[LINKED_PREV_PTR];
592         while (tmp != -1)
593         {
594                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
595                 sec_fe = linked_fe->m_frontend;
596                 sec_fe->getData(LINKED_NEXT_PTR, tmp);
597         }
598         while (1)
599         {
600 #if HAVE_DVB_API_VERSION < 3
601                 FrontendEvent event;
602 #else
603                 dvb_frontend_event event;
604 #endif
605                 int res;
606                 int state;
607                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
608
609                 if (res && (errno == EAGAIN))
610                         break;
611
612                 if (res)
613                 {
614                         eWarning("FE_GET_EVENT failed! %m");
615                         return;
616                 }
617
618                 if (w < 0)
619                         continue;
620
621 #if HAVE_DVB_API_VERSION < 3
622                 if (event.type == FE_COMPLETION_EV)
623 #else
624                 eDebug("(%d)fe event: status %x, inversion %s", m_dvbid, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
625                 if (event.status & FE_HAS_LOCK)
626 #endif
627                 {
628                         state = stateLock;
629                 } else
630                 {
631                         if (m_tuning)
632                                 state = stateTuning;
633                         else
634                         {
635                                 eDebug("stateLostLock");
636                                 state = stateLostLock;
637                                 sec_fe->m_data[CSW] = sec_fe->m_data[UCSW] = sec_fe->m_data[TONEBURST] = -1; // reset diseqc
638                         }
639                 }
640                 if (m_state != state)
641                 {
642                         m_state = state;
643                         m_stateChanged(this);
644                 }
645         }
646 }
647
648 void eDVBFrontend::timeout()
649 {
650         m_tuning = 0;
651         if (m_state == stateTuning)
652         {
653                 m_state = stateFailed;
654                 m_stateChanged(this);
655         }
656 }
657
658 #define INRANGE(X,Y,Z) (((X<=Y) && (Y<=Z))||((Z<=Y) && (Y<=X)) ? 1 : 0)
659
660 int eDVBFrontend::readFrontendData(int type)
661 {
662         switch(type)
663         {
664                 case bitErrorRate:
665                 {
666                         uint32_t ber=0;
667                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
668                                 eDebug("FE_READ_BER failed (%m)");
669                         return ber;
670                 }
671                 case signalQuality:
672                 {
673                         uint16_t snr=0;
674                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
675                                 eDebug("FE_READ_SNR failed (%m)");
676                         return snr;
677                 }
678                 case signalQualitydB: /* this will move into the driver */
679                 {
680                         uint16_t snr=0;
681                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
682                                 eDebug("FE_READ_SNR failed (%m)");
683                         if (!strcmp(m_description, "BCM4501 (internal)"))
684                         {
685                                 unsigned int SDS_SNRE = snr << 16;
686
687                                 static float SNR_COEFF[6] = {
688                                         100.0 / 4194304.0,
689                                         -7136.0 / 4194304.0,
690                                         197418.0 / 4194304.0,
691                                         -2602183.0 / 4194304.0,
692                                         20377212.0 / 4194304.0,
693                                         -37791203.0 / 4194304.0,
694                                 };
695                         
696                                 float fval1, fval2, snr_in_db;
697                                 int i;
698                                 fval1 = 12.44714 - (2.0 * log10(SDS_SNRE / 256.0));
699                                 fval2 = pow(10.0, fval1)-1;
700                                 fval1 = 10.0 * log10(fval2);
701                         
702                                 if (fval1 < 10.0)
703                                 {
704                                         fval2 = SNR_COEFF[0];
705                                         for (i=0; i<6; ++i)
706                                         {
707                                                 fval2 *= fval1;
708                                                 fval2 += SNR_COEFF[i];
709                                         }
710                                         fval1 = fval2;
711                                 }
712                                 snr_in_db = fval1;
713                         
714                                 return (int)(snr_in_db * 100.0);
715                         }
716                         else if (strstr(m_description, "Alps BSBE1 C01A") ||
717                                 !strcmp(m_description, "Alps -S(STV0288)"))
718                         {
719                                 if (snr == 0)
720                                         return 0;
721                                 else if (snr == 0xFFFF) // i think this should not happen
722                                         return 100*100;
723                                 else
724                                 {
725                                         enum { REALVAL, REGVAL };
726                                         const long CN_lookup[31][2] = {
727                                                 {20,8900}, {25,8680}, {30,8420}, {35,8217}, {40,7897},
728                                                 {50,7333}, {60,6747}, {70,6162}, {80,5580}, {90,5029},
729                                                 {100,4529}, {110,4080}, {120,3685}, {130,3316}, {140,2982},
730                                                 {150,2688}, {160,2418}, {170,2188}, {180,1982}, {190,1802},
731                                                 {200,1663}, {210,1520}, {220,1400}, {230,1295}, {240,1201},
732                                                 {250,1123}, {260,1058}, {270,1004}, {280,957}, {290,920},
733                                                 {300,890}
734                                         };
735                                         long regval = 0xFFFF - ((snr / 3) + 0xA100), // revert some dvb api calulations to get the real register value
736                                                 Imin=0,
737                                                 Imax=30,
738                                                 i;
739                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[Imax][REGVAL]))
740                                         {
741                                                 long val;
742                                                 while((Imax-Imin)>1)
743                                                 {
744                                                         i=(Imax+Imin)/2;
745                                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[i][REGVAL]))
746                                                                 Imax = i;
747                                                         else
748                                                                 Imin = i;
749                                                 }
750                                                 return (((regval - CN_lookup[Imin][REGVAL])
751                                                                 * (CN_lookup[Imax][REALVAL] - CN_lookup[Imin][REALVAL])
752                                                                 / (CN_lookup[Imax][REGVAL] - CN_lookup[Imin][REGVAL]))
753                                                                 + CN_lookup[Imin][REALVAL]) * 10;
754                                         }
755                                         return 100;
756                                 }
757                                 return 0;
758                         }
759                         else if (!strcmp(m_description, "Alps BSBE1 702A") ||  // some frontends with STV0299
760                                 !strcmp(m_description, "Alps -S") ||
761                                 !strcmp(m_description, "Philips -S") ||
762                                 !strcmp(m_description, "LG -S") )
763                         {
764                                 float snr_in_db=(snr-39075)/1764.7;
765                                 return (int)(snr_in_db * 100.0);
766                         } else if (!strcmp(m_description, "Alps BSBE2"))
767                         {
768                                 return (int)((snr >> 7) * 10.0);
769                         } /* else
770                                 eDebug("no SNR dB calculation for frontendtype %s yet", m_description); */
771                         return 0x12345678;
772                 }
773                 case signalPower:
774                 {
775                         uint16_t strength=0;
776                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
777                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
778                         return strength;
779                 }
780                 case locked:
781                 {
782 #if HAVE_DVB_API_VERSION < 3
783                         FrontendStatus status=0;
784 #else
785                         fe_status_t status;
786 #endif
787                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
788                                 eDebug("FE_READ_STATUS failed (%m)");
789                         return !!(status&FE_HAS_LOCK);
790                 }
791                 case synced:
792                 {
793 #if HAVE_DVB_API_VERSION < 3
794                         FrontendStatus status=0;
795 #else
796                         fe_status_t status;
797 #endif
798                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
799                                 eDebug("FE_READ_STATUS failed (%m)");
800                         return !!(status&FE_HAS_SYNC);
801                 }
802                 case frontendNumber:
803                         return m_slotid;
804         }
805         return 0;
806 }
807
808 void PutToDict(ePyObject &dict, const char*key, long value)
809 {
810         ePyObject item = PyInt_FromLong(value);
811         if (item)
812         {
813                 if (PyDict_SetItemString(dict, key, item))
814                         eDebug("put %s to dict failed", key);
815                 Py_DECREF(item);
816         }
817         else
818                 eDebug("could not create PyObject for %s", key);
819 }
820
821 void PutToDict(ePyObject &dict, const char*key, ePyObject item)
822 {
823         if (item)
824         {
825                 if (PyDict_SetItemString(dict, key, item))
826                         eDebug("put %s to dict failed", key);
827                 Py_DECREF(item);
828         }
829         else
830                 eDebug("invalid PyObject for %s", key);
831 }
832
833 void PutToDict(ePyObject &dict, const char*key, const char *value)
834 {
835         ePyObject item = PyString_FromString(value);
836         if (item)
837         {
838                 if (PyDict_SetItemString(dict, key, item))
839                         eDebug("put %s to dict failed", key);
840                 Py_DECREF(item);
841         }
842         else
843                 eDebug("could not create PyObject for %s", key);
844 }
845
846 void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
847 {
848         long freq_offset=0;
849         const char *tmp=0;
850         fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
851         int frequency = parm_frequency + freq_offset;
852         PutToDict(dict, "frequency", frequency);
853         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
854         switch(parm_u_qpsk_fec_inner)
855         {
856         case FEC_1_2:
857                 tmp = "FEC_1_2";
858                 break;
859         case FEC_2_3:
860                 tmp = "FEC_2_3";
861                 break;
862         case FEC_3_4:
863                 tmp = "FEC_3_4";
864                 break;
865         case FEC_5_6:
866                 tmp = "FEC_5_6";
867                 break;
868         case FEC_7_8:
869                 tmp = "FEC_7_8";
870                 break;
871         case FEC_NONE:
872                 tmp = "FEC_NONE";
873         default:
874         case FEC_AUTO:
875                 tmp = "FEC_AUTO";
876                 break;
877 #if HAVE_DVB_API_VERSION >=3
878         case FEC_S2_8PSK_1_2:
879         case FEC_S2_QPSK_1_2:
880                 tmp = "FEC_1_2";
881                 break;
882         case FEC_S2_8PSK_2_3:
883         case FEC_S2_QPSK_2_3:
884                 tmp = "FEC_2_3";
885                 break;
886         case FEC_S2_8PSK_3_4:
887         case FEC_S2_QPSK_3_4:
888                 tmp = "FEC_3_4";
889                 break;
890         case FEC_S2_8PSK_5_6:
891         case FEC_S2_QPSK_5_6:
892                 tmp = "FEC_5_6";
893                 break;
894         case FEC_S2_8PSK_7_8:
895         case FEC_S2_QPSK_7_8:
896                 tmp = "FEC_7_8";
897                 break;
898         case FEC_S2_8PSK_8_9:
899         case FEC_S2_QPSK_8_9:
900                 tmp = "FEC_8_9";
901                 break;
902         case FEC_S2_8PSK_3_5:
903         case FEC_S2_QPSK_3_5:
904                 tmp = "FEC_3_5";
905                 break;
906         case FEC_S2_8PSK_4_5:
907         case FEC_S2_QPSK_4_5:
908                 tmp = "FEC_4_5";
909                 break;
910         case FEC_S2_8PSK_9_10:
911         case FEC_S2_QPSK_9_10:
912                 tmp = "FEC_9_10";
913                 break;
914 #endif
915         }
916         PutToDict(dict, "fec_inner", tmp);
917 #if HAVE_DVB_API_VERSION >=3
918         PutToDict(dict, "modulation",
919                 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
920         if (parm_u_qpsk_fec_inner > FEC_AUTO)
921         {
922                 switch(parm_inversion & 0xc)
923                 {
924                 default: // unknown rolloff
925                 case 0: // 0.35
926                         tmp = "ROLLOFF_0_35";
927                         break;
928                 case 4: // 0.25
929                         tmp = "ROLLOFF_0_25";
930                         break;
931                 case 8: // 0.20
932                         tmp = "ROLLOFF_0_20";
933                         break;
934                 }
935                 PutToDict(dict, "rolloff", tmp);
936                 if (parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10)
937                 {
938                         switch(parm_inversion & 0x30)
939                         {
940                         case 0: // pilot off
941                                 tmp = "PILOT_OFF";
942                                 break;
943                         case 0x10: // pilot on
944                                 tmp = "PILOT_ON";
945                                 break;
946                         case 0x20: // pilot auto
947                                 tmp = "PILOT_AUTO";
948                                 break;
949                         }
950                         PutToDict(dict, "pilot", tmp);
951                 }
952                 tmp = "DVB-S2";
953         }
954         else
955                 tmp = "DVB-S";
956 #else
957         PutToDict(dict, "modulation", "QPSK" );
958         tmp = "DVB-S";
959 #endif
960         PutToDict(dict, "system", tmp);
961 }
962
963 void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
964 {
965         const char *tmp=0;
966 #if HAVE_DVB_API_VERSION < 3
967         PutToDict(dict, "frequency", parm_frequency);
968 #else
969         PutToDict(dict, "frequency", parm_frequency/1000);
970 #endif
971         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
972         switch(parm_u_qam_fec_inner)
973         {
974         case FEC_NONE:
975                 tmp = "FEC_NONE";
976                 break;
977         case FEC_1_2:
978                 tmp = "FEC_1_2";
979                 break;
980         case FEC_2_3:
981                 tmp = "FEC_2_3";
982                 break;
983         case FEC_3_4:
984                 tmp = "FEC_3_4";
985                 break;
986         case FEC_5_6:
987                 tmp = "FEC_5_6";
988                 break;
989         case FEC_7_8:
990                 tmp = "FEC_7_8";
991                 break;
992 #if HAVE_DVB_API_VERSION >= 3
993         case FEC_8_9:
994                 tmp = "FEC_8_9";
995                 break;
996 #endif
997         default:
998         case FEC_AUTO:
999                 tmp = "FEC_AUTO";
1000                 break;
1001         }
1002         PutToDict(dict, "fec_inner", tmp);
1003         switch(parm_u_qam_modulation)
1004         {
1005         case QAM_16:
1006                 tmp = "QAM_16";
1007                 break;
1008         case QAM_32:
1009                 tmp = "QAM_32";
1010                 break;
1011         case QAM_64:
1012                 tmp = "QAM_64";
1013                 break;
1014         case QAM_128:
1015                 tmp = "QAM_128";
1016                 break;
1017         case QAM_256:
1018                 tmp = "QAM_256";
1019                 break;
1020         default:
1021         case QAM_AUTO:
1022                 tmp = "QAM_AUTO";
1023                 break;
1024         }
1025         PutToDict(dict, "modulation", tmp);
1026 }
1027
1028 void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1029 {
1030         const char *tmp=0;
1031         PutToDict(dict, "frequency", parm_frequency);
1032         switch (parm_u_ofdm_bandwidth)
1033         {
1034         case BANDWIDTH_8_MHZ:
1035                 tmp = "BANDWIDTH_8_MHZ";
1036                 break;
1037         case BANDWIDTH_7_MHZ:
1038                 tmp = "BANDWIDTH_7_MHZ";
1039                 break;
1040         case BANDWIDTH_6_MHZ:
1041                 tmp = "BANDWIDTH_6_MHZ";
1042                 break;
1043         default:
1044         case BANDWIDTH_AUTO:
1045                 tmp = "BANDWIDTH_AUTO";
1046                 break;
1047         }
1048         PutToDict(dict, "bandwidth", tmp);
1049         switch (parm_u_ofdm_code_rate_LP)
1050         {
1051         case FEC_1_2:
1052                 tmp = "FEC_1_2";
1053                 break;
1054         case FEC_2_3:
1055                 tmp = "FEC_2_3";
1056                 break;
1057         case FEC_3_4:
1058                 tmp = "FEC_3_4";
1059                 break;
1060         case FEC_5_6:
1061                 tmp = "FEC_5_6";
1062                 break;
1063         case FEC_7_8:
1064                 tmp = "FEC_7_8";
1065                 break;
1066         default:
1067         case FEC_AUTO:
1068                 tmp = "FEC_AUTO";
1069                 break;
1070         }
1071         PutToDict(dict, "code_rate_lp", tmp);
1072         switch (parm_u_ofdm_code_rate_HP)
1073         {
1074         case FEC_1_2:
1075                 tmp = "FEC_1_2";
1076                 break;
1077         case FEC_2_3:
1078                 tmp = "FEC_2_3";
1079                 break;
1080         case FEC_3_4:
1081                 tmp = "FEC_3_4";
1082                 break;
1083         case FEC_5_6:
1084                 tmp = "FEC_5_6";
1085                 break;
1086         case FEC_7_8:
1087                 tmp = "FEC_7_8";
1088                 break;
1089         default:
1090         case FEC_AUTO:
1091                 tmp = "FEC_AUTO";
1092                 break;
1093         }
1094         PutToDict(dict, "code_rate_hp", tmp);
1095         switch (parm_u_ofdm_constellation)
1096         {
1097         case QPSK:
1098                 tmp = "QPSK";
1099                 break;
1100         case QAM_16:
1101                 tmp = "QAM_16";
1102                 break;
1103         case QAM_64:
1104                 tmp = "QAM_64";
1105                 break;
1106         default:
1107         case QAM_AUTO:
1108                 tmp = "QAM_AUTO";
1109                 break;
1110         }
1111         PutToDict(dict, "constellation", tmp);
1112         switch (parm_u_ofdm_transmission_mode)
1113         {
1114         case TRANSMISSION_MODE_2K:
1115                 tmp = "TRANSMISSION_MODE_2K";
1116                 break;
1117         case TRANSMISSION_MODE_8K:
1118                 tmp = "TRANSMISSION_MODE_8K";
1119                 break;
1120         default:
1121         case TRANSMISSION_MODE_AUTO:
1122                 tmp = "TRANSMISSION_MODE_AUTO";
1123                 break;
1124         }
1125         PutToDict(dict, "transmission_mode", tmp);
1126         switch (parm_u_ofdm_guard_interval)
1127         {
1128                 case GUARD_INTERVAL_1_32:
1129                         tmp = "GUARD_INTERVAL_1_32";
1130                         break;
1131                 case GUARD_INTERVAL_1_16:
1132                         tmp = "GUARD_INTERVAL_1_16";
1133                         break;
1134                 case GUARD_INTERVAL_1_8:
1135                         tmp = "GUARD_INTERVAL_1_8";
1136                         break;
1137                 case GUARD_INTERVAL_1_4:
1138                         tmp = "GUARD_INTERVAL_1_4";
1139                         break;
1140                 default:
1141                 case GUARD_INTERVAL_AUTO:
1142                         tmp = "GUARD_INTERVAL_AUTO";
1143                         break;
1144         }
1145         PutToDict(dict, "guard_interval", tmp);
1146         switch (parm_u_ofdm_hierarchy_information)
1147         {
1148                 case HIERARCHY_NONE:
1149                         tmp = "HIERARCHY_NONE";
1150                         break;
1151                 case HIERARCHY_1:
1152                         tmp = "HIERARCHY_1";
1153                         break;
1154                 case HIERARCHY_2:
1155                         tmp = "HIERARCHY_2";
1156                         break;
1157                 case HIERARCHY_4:
1158                         tmp = "HIERARCHY_4";
1159                         break;
1160                 default:
1161                 case HIERARCHY_AUTO:
1162                         tmp = "HIERARCHY_AUTO";
1163                         break;
1164         }
1165         PutToDict(dict, "hierarchy_information", tmp);
1166 }
1167
1168 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1169 {
1170         if (dest && PyDict_Check(dest))
1171         {
1172                 const char *tmp = "UNKNOWN";
1173                 switch(m_state)
1174                 {
1175                         case stateIdle:
1176                                 tmp="IDLE";
1177                                 break;
1178                         case stateTuning:
1179                                 tmp="TUNING";
1180                                 break;
1181                         case stateFailed:
1182                                 tmp="FAILED";
1183                                 break;
1184                         case stateLock:
1185                                 tmp="LOCKED";
1186                                 break;
1187                         case stateLostLock:
1188                                 tmp="LOSTLOCK";
1189                                 break;
1190                         default:
1191                                 break;
1192                 }
1193                 PutToDict(dest, "tuner_state", tmp);
1194                 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1195                 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1196                 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1197                 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1198                 int sigQualitydB = readFrontendData(signalQualitydB);
1199                 if (sigQualitydB == 0x12345678) // not support yet
1200                 {
1201                         ePyObject obj=Py_None;
1202                         Py_INCREF(obj);
1203                         PutToDict(dest, "tuner_signal_quality_db", obj);
1204                 }
1205                 else
1206                         PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1207                 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1208         }
1209 }
1210
1211 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1212 {
1213         if (m_fd != -1 && dest && PyDict_Check(dest))
1214         {
1215                 switch(m_type)
1216                 {
1217                         case feSatellite:
1218                         case feCable:
1219                         case feTerrestrial:
1220                         {
1221                                 FRONTENDPARAMETERS front;
1222                                 if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1223                                         eDebug("FE_GET_FRONTEND (%m)");
1224                                 else
1225                                 {
1226                                         const FRONTENDPARAMETERS &parm = original ? this->parm : front;
1227                                         const char *tmp = "INVERSION_AUTO";
1228                                         switch(parm_inversion)
1229                                         {
1230                                                 case INVERSION_ON:
1231                                                         tmp = "INVERSION_ON";
1232                                                         break;
1233                                                 case INVERSION_OFF:
1234                                                         tmp = "INVERSION_OFF";
1235                                                         break;
1236                                                 default:
1237                                                         break;
1238                                         }
1239                                         if (tmp)
1240                                                 PutToDict(dest, "inversion", tmp);
1241
1242                                         switch(m_type)
1243                                         {
1244                                                 case feSatellite:
1245                                                         fillDictWithSatelliteData(dest, original?parm:front, this);
1246                                                         break;
1247                                                 case feCable:
1248                                                         fillDictWithCableData(dest, original?parm:front);
1249                                                         break;
1250                                                 case feTerrestrial:
1251                                                         fillDictWithTerrestrialData(dest, original?parm:front);
1252                                                         break;
1253                                         }
1254                                 }
1255                         }
1256                         default:
1257                                 break;
1258                 }
1259         }
1260 }
1261
1262 void eDVBFrontend::getFrontendData(ePyObject dest)
1263 {
1264         if (dest && PyDict_Check(dest))
1265         {
1266                 const char *tmp=0;
1267                 PutToDict(dest, "tuner_number", m_slotid);
1268                 switch(m_type)
1269                 {
1270                         case feSatellite:
1271                                 tmp = "DVB-S";
1272                                 break;
1273                         case feCable:
1274                                 tmp = "DVB-C";
1275                                 break;
1276                         case feTerrestrial:
1277                                 tmp = "DVB-T";
1278                                 break;
1279                         default:
1280                                 tmp = "UNKNOWN";
1281                                 break;
1282                 }
1283                 PutToDict(dest, "tuner_type", tmp);
1284         }
1285 }
1286
1287 #ifndef FP_IOCTL_GET_ID
1288 #define FP_IOCTL_GET_ID 0
1289 #endif
1290 int eDVBFrontend::readInputpower()
1291 {
1292         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1293         char proc_name[64];
1294         sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1295         FILE *f=fopen(proc_name, "r");
1296         if (f)
1297         {
1298                 if (fscanf(f, "%d", &power) != 1)
1299                         eDebug("read %s failed!! (%m)", proc_name);
1300                 else
1301                         eDebug("%s is %d\n", proc_name, power);
1302                 fclose(f);
1303         }
1304         else
1305         {
1306                 // open front prozessor
1307                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1308                 if (fp < 0)
1309                 {
1310                         eDebug("couldn't open fp");
1311                         return -1;
1312                 }
1313                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1314                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1315                 {
1316                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1317                         return -1;
1318                 }
1319                 ::close(fp);
1320         }
1321
1322         return power;
1323 }
1324
1325 bool eDVBFrontend::setSecSequencePos(int steps)
1326 {
1327         eDebug("set sequence pos %d", steps);
1328         if (!steps)
1329                 return false;
1330         while( steps > 0 )
1331         {
1332                 if (m_sec_sequence.current() != m_sec_sequence.end())
1333                         ++m_sec_sequence.current();
1334                 --steps;
1335         }
1336         while( steps < 0 )
1337         {
1338                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1339                         --m_sec_sequence.current();
1340                 ++steps;
1341         }
1342         return true;
1343 }
1344
1345 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1346 {
1347         int delay=0;
1348         eDVBFrontend *sec_fe = this;
1349         eDVBRegisteredFrontend *regFE = 0;
1350         long tmp = m_data[LINKED_PREV_PTR];
1351         while ( tmp != -1 )
1352         {
1353                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1354                 sec_fe = prev->m_frontend;
1355                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1356                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1357                         int state = sec_fe->m_state;
1358                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1359                         {
1360                                 sec_fe->closeFrontend(true);
1361                                 state = sec_fe->m_state;
1362                         }
1363                         if (state == eDVBFrontend::stateClosed)
1364                         {
1365                                 regFE = prev;
1366                                 prev->inc_use();
1367                         }
1368                 }
1369         }
1370
1371         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1372         {
1373                 long *sec_fe_data = sec_fe->m_data;
1374 //              eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1375                 switch (m_sec_sequence.current()->cmd)
1376                 {
1377                         case eSecCommand::SLEEP:
1378                                 delay = m_sec_sequence.current()++->msec;
1379                                 eDebug("[SEC] sleep %dms", delay);
1380                                 break;
1381                         case eSecCommand::GOTO:
1382                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1383                                         ++m_sec_sequence.current();
1384                                 break;
1385                         case eSecCommand::SET_VOLTAGE:
1386                         {
1387                                 int voltage = m_sec_sequence.current()++->voltage;
1388                                 eDebug("[SEC] setVoltage %d", voltage);
1389                                 sec_fe->setVoltage(voltage);
1390                                 break;
1391                         }
1392                         case eSecCommand::IF_VOLTAGE_GOTO:
1393                         {
1394                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1395                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1396                                         break;
1397                                 ++m_sec_sequence.current();
1398                                 break;
1399                         }
1400                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1401                         {
1402                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1403                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1404                                         break;
1405                                 ++m_sec_sequence.current();
1406                                 break;
1407                         }
1408                         case eSecCommand::IF_TONE_GOTO:
1409                         {
1410                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1411                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1412                                         break;
1413                                 ++m_sec_sequence.current();
1414                                 break;
1415                         }
1416                         case eSecCommand::IF_NOT_TONE_GOTO:
1417                         {
1418                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1419                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1420                                         break;
1421                                 ++m_sec_sequence.current();
1422                                 break;
1423                         }
1424                         case eSecCommand::SET_TONE:
1425                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
1426                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1427                                 break;
1428                         case eSecCommand::SEND_DISEQC:
1429                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1430                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
1431                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1432                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1433                                 eDebug("");
1434                                 ++m_sec_sequence.current();
1435                                 break;
1436                         case eSecCommand::SEND_TONEBURST:
1437                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1438                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1439                                 break;
1440                         case eSecCommand::SET_FRONTEND:
1441                                 eDebug("[SEC] setFrontend");
1442                                 setFrontend();
1443                                 ++m_sec_sequence.current();
1444                                 break;
1445                         case eSecCommand::START_TUNE_TIMEOUT:
1446                         {
1447                                 m_timeout->start(m_sec_sequence.current()->timeout, 1);
1448                                 ++m_sec_sequence.current();
1449                                 break;
1450                         }
1451                         case eSecCommand::SET_TIMEOUT:
1452                                 m_timeoutCount = m_sec_sequence.current()++->val;
1453                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
1454                                 break;
1455                         case eSecCommand::IF_TIMEOUT_GOTO:
1456                                 if (!m_timeoutCount)
1457                                 {
1458                                         eDebug("[SEC] rotor timout");
1459                                         setSecSequencePos(m_sec_sequence.current()->steps);
1460                                 }
1461                                 else
1462                                         ++m_sec_sequence.current();
1463                                 break;
1464                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1465                         {
1466                                 int idx = m_sec_sequence.current()++->val;
1467                                 if ( idx == 0 || idx == 1 )
1468                                 {
1469                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1470                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1471                                 }
1472                                 else
1473                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1474                                 break;
1475                         }
1476                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1477                         {
1478                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1479                                 int idx = compare.val;
1480                                 if ( idx == 0 || idx == 1 )
1481                                 {
1482                                         int idle = sec_fe->readInputpower();
1483                                         int diff = abs(idle-m_idleInputpower[idx]);
1484                                         if ( diff > 0)
1485                                         {
1486                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1487                                                 setSecSequencePos(compare.steps);
1488                                                 break;
1489                                         }
1490                                 }
1491                                 ++m_sec_sequence.current();
1492                                 break;
1493                         }
1494                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1495                         {
1496                                 int signal = 0;
1497                                 int isLocked = readFrontendData(locked);
1498                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1499                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1500                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1501                                 {
1502                                         if (cmd.lastSignal)
1503                                                 eDebug("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1504                                         else
1505                                         {
1506                                                 eDebug("[SEC] locked step %d ok", cmd.okcount);
1507                                                 cmd.lastSignal = signal;
1508                                         }
1509                                         ++cmd.okcount;
1510                                         if (cmd.okcount > 4)
1511                                         {
1512                                                 eDebug("ok > 4 .. goto %d\n",cmd.steps);
1513                                                 setSecSequencePos(cmd.steps);
1514                                                 m_state = stateLock;
1515                                                 m_stateChanged(this);
1516                                                 feEvent(-1);
1517                                                 m_sn->start();
1518                                                 break;
1519                                         }
1520                                 }
1521                                 else
1522                                 {
1523                                         if (isLocked)
1524                                                 eDebug("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1525                                         else
1526                                                 eDebug("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1527                                         --m_timeoutCount;
1528                                         if (!m_timeoutCount && m_retryCount > 0)
1529                                                 --m_retryCount;
1530                                         cmd.okcount=0;
1531                                         cmd.lastSignal=0;
1532                                 }
1533                                 ++m_sec_sequence.current();
1534                                 break;
1535                         }
1536                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1537                                 m_runningInputpower = sec_fe->readInputpower();
1538                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
1539                                 ++m_sec_sequence.current();
1540                                 break;
1541                         case eSecCommand::SET_ROTOR_MOVING:
1542                                 m_sec->setRotorMoving(true);
1543                                 ++m_sec_sequence.current();
1544                                 break;
1545                         case eSecCommand::SET_ROTOR_STOPPED:
1546                                 m_sec->setRotorMoving(false);
1547                                 ++m_sec_sequence.current();
1548                                 break;
1549                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1550                         {
1551                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1552                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1553                                 const char *txt = cmd.direction ? "running" : "stopped";
1554                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1555                                         txt,
1556                                         m_runningInputpower,
1557                                         idleInputpower,
1558                                         cmd.deltaA);
1559                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1560                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1561                                 {
1562                                         ++cmd.okcount;
1563                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1564                                         if ( cmd.okcount > 6 )
1565                                         {
1566                                                 eDebug("[SEC] rotor is %s", txt);
1567                                                 if (setSecSequencePos(cmd.steps))
1568                                                         break;
1569                                         }
1570                                 }
1571                                 else
1572                                 {
1573                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1574                                         --m_timeoutCount;
1575                                         if (!m_timeoutCount && m_retryCount > 0)
1576                                                 --m_retryCount;
1577                                         cmd.okcount=0;
1578                                 }
1579                                 ++m_sec_sequence.current();
1580                                 break;
1581                         }
1582                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1583                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1584                                         setSecSequencePos(m_sec_sequence.current()->steps);
1585                                 else
1586                                         ++m_sec_sequence.current();
1587                                 break;
1588                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1589                                 eDebug("[SEC] invalidate current switch params");
1590                                 sec_fe_data[CSW] = -1;
1591                                 sec_fe_data[UCSW] = -1;
1592                                 sec_fe_data[TONEBURST] = -1;
1593                                 ++m_sec_sequence.current();
1594                                 break;
1595                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1596                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1597                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1598                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1599                                 eDebug("[SEC] update current switch params");
1600                                 ++m_sec_sequence.current();
1601                                 break;
1602                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1603                                 eDebug("[SEC] invalidate current rotorparams");
1604                                 sec_fe_data[ROTOR_CMD] = -1;
1605                                 sec_fe_data[ROTOR_POS] = -1;
1606                                 ++m_sec_sequence.current();
1607                                 break;
1608                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1609                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1610                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1611                                 eDebug("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1612                                 ++m_sec_sequence.current();
1613                                 break;
1614                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1615                                 m_retryCount = m_sec_sequence.current()++->val;
1616                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
1617                                 break;
1618                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1619                                 if (!m_retryCount)
1620                                 {
1621                                         eDebug("[SEC] no more rotor retrys");
1622                                         setSecSequencePos(m_sec_sequence.current()->steps);
1623                                 }
1624                                 else
1625                                         ++m_sec_sequence.current();
1626                                 break;
1627                         case eSecCommand::SET_POWER_LIMITING_MODE:
1628                         {
1629                                 char proc_name[64];
1630                                 sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1631                                 FILE *f=fopen(proc_name, "w");
1632                                 if (f) // new interface exist?
1633                                 {
1634                                         bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1635                                         if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1636                                                 eDebug("write %s failed!! (%m)", proc_name);
1637                                         else
1638                                                 eDebug("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1639                                         fclose(f);
1640                                 }
1641                                 else if (sec_fe->m_need_rotor_workaround)
1642                                 {
1643                                         char dev[16];
1644                                         int slotid = sec_fe->m_slotid;
1645                                         // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1646                                         if (slotid < 2)
1647                                                 sprintf(dev, "/dev/i2c/%d", slotid);
1648                                         else if (slotid == 2)
1649                                                 sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1650                                         else if (slotid == 3)
1651                                                 sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1652                                         int fd = ::open(dev, O_RDWR);
1653
1654                                         unsigned char data[2];
1655                                         ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1656                                         if(::read(fd, data, 1) != 1)
1657                                                 eDebug("[SEC] error read lnbp (%m)");
1658                                         if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1659                                         {
1660                                                 data[0] |= 0x80;  // enable static current limiting
1661                                                 eDebug("[SEC] set static current limiting");
1662                                         }
1663                                         else
1664                                         {
1665                                                 data[0] &= ~0x80;  // enable dynamic current limiting
1666                                                 eDebug("[SEC] set dynamic current limiting");
1667                                         }
1668                                         if(::write(fd, data, 1) != 1)
1669                                                 eDebug("[SEC] error write lnbp (%m)");
1670                                         ::close(fd);
1671                                 }
1672                                 ++m_sec_sequence.current();
1673                                 break;
1674                         }
1675                         default:
1676                                 eDebug("[SEC] unhandled sec command %d",
1677                                         ++m_sec_sequence.current()->cmd);
1678                                 ++m_sec_sequence.current();
1679                 }
1680                 m_tuneTimer->start(delay,true);
1681         }
1682         if (regFE)
1683                 regFE->dec_use();
1684 }
1685
1686 void eDVBFrontend::setFrontend()
1687 {
1688         eDebug("setting frontend %d", m_dvbid);
1689         m_sn->start();
1690         feEvent(-1);
1691         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1692         {
1693                 perror("FE_SET_FRONTEND failed");
1694                 return;
1695         }
1696 }
1697
1698 RESULT eDVBFrontend::getFrontendType(int &t)
1699 {
1700         if (m_type == -1)
1701                 return -ENODEV;
1702         t = m_type;
1703         return 0;
1704 }
1705
1706 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1707 {
1708         int res;
1709         if (!m_sec)
1710         {
1711                 eWarning("no SEC module active!");
1712                 return -ENOENT;
1713         }
1714         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1715         if (!res)
1716         {
1717                 eDebug("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1718                         feparm.system,
1719                         feparm.frequency,
1720                         feparm.polarisation,
1721                         feparm.symbol_rate,
1722                         feparm.inversion,
1723                         feparm.fec,
1724                         feparm.orbital_position);
1725                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1726                 switch (feparm.inversion)
1727                 {
1728                         case eDVBFrontendParametersSatellite::Inversion::On:
1729                                 parm_inversion = INVERSION_ON;
1730                                 break;
1731                         case eDVBFrontendParametersSatellite::Inversion::Off:
1732                                 parm_inversion = INVERSION_OFF;
1733                                 break;
1734                         default:
1735                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1736                                 parm_inversion = INVERSION_AUTO;
1737                                 break;
1738                 }
1739                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1740                         switch (feparm.fec)
1741                         {
1742                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1743                                         parm_u_qpsk_fec_inner = FEC_NONE;
1744                                         break;
1745                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1746                                         parm_u_qpsk_fec_inner = FEC_1_2;
1747                                         break;
1748                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1749                                         parm_u_qpsk_fec_inner = FEC_2_3;
1750                                         break;
1751                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1752                                         parm_u_qpsk_fec_inner = FEC_3_4;
1753                                         break;
1754                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1755                                         parm_u_qpsk_fec_inner = FEC_5_6;
1756                                         break;
1757                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1758                                         parm_u_qpsk_fec_inner = FEC_7_8;
1759                                         break;
1760                                 default:
1761                                         eDebug("no valid fec for DVB-S set.. assume auto");
1762                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1763                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1764                                         break;
1765                         }
1766 #if HAVE_DVB_API_VERSION >= 3
1767                 else // DVB_S2
1768                 {
1769                         switch (feparm.fec)
1770                         {
1771                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1772                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1773                                         break;
1774                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1775                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1776                                         break;
1777                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1778                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1779                                         break;
1780                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1781                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1782                                         break;
1783                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1784                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1785                                         break;
1786                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1787                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1788                                         break;
1789                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1790                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1791                                         break;
1792                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1793                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1794                                         break;
1795                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1796                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1797                                         break;
1798                                 default:
1799                                         eDebug("no valid fec for DVB-S2 set.. abort !!");
1800                                         return -EINVAL;
1801                         }
1802                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1803                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1804                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1805                                 // 8PSK fec driver values are decimal 9 bigger
1806                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1807                         }
1808                 }
1809 #endif
1810                 // FIXME !!! get frequency range from tuner
1811                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1812                 {
1813                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1814                         return -EINVAL;
1815                 }
1816                 eDebug("tuning to %d mhz", parm_frequency/1000);
1817         }
1818         return res;
1819 }
1820
1821 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1822 {
1823 #if HAVE_DVB_API_VERSION < 3
1824         parm_frequency = feparm.frequency;
1825 #else
1826         parm_frequency = feparm.frequency * 1000;
1827 #endif
1828         parm_u_qam_symbol_rate = feparm.symbol_rate;
1829         switch (feparm.modulation)
1830         {
1831         case eDVBFrontendParametersCable::Modulation::QAM16:
1832                 parm_u_qam_modulation = QAM_16;
1833                 break;
1834         case eDVBFrontendParametersCable::Modulation::QAM32:
1835                 parm_u_qam_modulation = QAM_32;
1836                 break;
1837         case eDVBFrontendParametersCable::Modulation::QAM64:
1838                 parm_u_qam_modulation = QAM_64;
1839                 break;
1840         case eDVBFrontendParametersCable::Modulation::QAM128:
1841                 parm_u_qam_modulation = QAM_128;
1842                 break;
1843         case eDVBFrontendParametersCable::Modulation::QAM256:
1844                 parm_u_qam_modulation = QAM_256;
1845                 break;
1846         default:
1847         case eDVBFrontendParametersCable::Modulation::Auto:
1848                 parm_u_qam_modulation = QAM_AUTO;
1849                 break;
1850         }
1851         switch (feparm.inversion)
1852         {
1853         case eDVBFrontendParametersCable::Inversion::On:
1854                 parm_inversion = INVERSION_ON;
1855                 break;
1856         case eDVBFrontendParametersCable::Inversion::Off:
1857                 parm_inversion = INVERSION_OFF;
1858                 break;
1859         default:
1860         case eDVBFrontendParametersCable::Inversion::Unknown:
1861                 parm_inversion = INVERSION_AUTO;
1862                 break;
1863         }
1864         switch (feparm.fec_inner)
1865         {
1866         case eDVBFrontendParametersCable::FEC::fNone:
1867                 parm_u_qam_fec_inner = FEC_NONE;
1868                 break;
1869         case eDVBFrontendParametersCable::FEC::f1_2:
1870                 parm_u_qam_fec_inner = FEC_1_2;
1871                 break;
1872         case eDVBFrontendParametersCable::FEC::f2_3:
1873                 parm_u_qam_fec_inner = FEC_2_3;
1874                 break;
1875         case eDVBFrontendParametersCable::FEC::f3_4:
1876                 parm_u_qam_fec_inner = FEC_3_4;
1877                 break;
1878         case eDVBFrontendParametersCable::FEC::f5_6:
1879                 parm_u_qam_fec_inner = FEC_5_6;
1880                 break;
1881         case eDVBFrontendParametersCable::FEC::f7_8:
1882                 parm_u_qam_fec_inner = FEC_7_8;
1883                 break;
1884 #if HAVE_DVB_API_VERSION >= 3
1885         case eDVBFrontendParametersCable::FEC::f8_9:
1886                 parm_u_qam_fec_inner = FEC_8_9;
1887                 break;
1888 #endif
1889         default:
1890         case eDVBFrontendParametersCable::FEC::fAuto:
1891                 parm_u_qam_fec_inner = FEC_AUTO;
1892                 break;
1893         }
1894         eDebug("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1895                 parm_frequency/1000,
1896                 parm_u_qam_symbol_rate,
1897                 parm_u_qam_fec_inner,
1898                 parm_u_qam_modulation,
1899                 parm_inversion);
1900         return 0;
1901 }
1902
1903 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1904 {
1905         parm_frequency = feparm.frequency;
1906
1907         switch (feparm.bandwidth)
1908         {
1909         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1910                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1911                 break;
1912         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1913                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1914                 break;
1915         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1916                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1917                 break;
1918         default:
1919         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1920                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1921                 break;
1922         }
1923         switch (feparm.code_rate_LP)
1924         {
1925         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1926                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1927                 break;
1928         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1929                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1930                 break;
1931         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1932                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1933                 break;
1934         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1935                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1936                 break;
1937         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1938                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1939                 break;
1940         default:
1941         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1942                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1943                 break;
1944         }
1945         switch (feparm.code_rate_HP)
1946         {
1947         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1948                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1949                 break;
1950         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1951                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1952                 break;
1953         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1954                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1955                 break;
1956         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1957                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1958                 break;
1959         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1960                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1961                 break;
1962         default:
1963         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1964                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1965                 break;
1966         }
1967         switch (feparm.modulation)
1968         {
1969         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1970                 parm_u_ofdm_constellation = QPSK;
1971                 break;
1972         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1973                 parm_u_ofdm_constellation = QAM_16;
1974                 break;
1975         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
1976                 parm_u_ofdm_constellation = QAM_64;
1977                 break;
1978         default:
1979         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1980                 parm_u_ofdm_constellation = QAM_AUTO;
1981                 break;
1982         }
1983         switch (feparm.transmission_mode)
1984         {
1985         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1986                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1987                 break;
1988         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1989                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1990                 break;
1991         default:
1992         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1993                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1994                 break;
1995         }
1996         switch (feparm.guard_interval)
1997         {
1998                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
1999                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2000                         break;
2001                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2002                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2003                         break;
2004                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2005                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2006                         break;
2007                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2008                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2009                         break;
2010                 default:
2011                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2012                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2013                         break;
2014         }
2015         switch (feparm.hierarchy)
2016         {
2017                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2018                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2019                         break;
2020                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2021                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2022                         break;
2023                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2024                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2025                         break;
2026                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2027                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2028                         break;
2029                 default:
2030                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2031                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2032                         break;
2033         }
2034         switch (feparm.inversion)
2035         {
2036         case eDVBFrontendParametersTerrestrial::Inversion::On:
2037                 parm_inversion = INVERSION_ON;
2038                 break;
2039         case eDVBFrontendParametersTerrestrial::Inversion::Off:
2040                 parm_inversion = INVERSION_OFF;
2041                 break;
2042         default:
2043         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2044                 parm_inversion = INVERSION_AUTO;
2045                 break;
2046         }
2047         return 0;
2048 }
2049
2050 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2051 {
2052         unsigned int timeout = 5000;
2053         eDebug("(%d)tune", m_dvbid);
2054
2055         m_timeout->stop();
2056
2057         int res=0;
2058
2059         if (!m_sn)
2060         {
2061                 eDebug("no frontend device opened... do not try to tune !!!");
2062                 res = -ENODEV;
2063                 goto tune_error;
2064         }
2065
2066         if (m_type == -1)
2067         {
2068                 res = -ENODEV;
2069                 goto tune_error;
2070         }
2071
2072         m_sn->stop();
2073         m_sec_sequence.clear();
2074
2075         where.calcLockTimeout(timeout);
2076
2077         switch (m_type)
2078         {
2079         case feSatellite:
2080         {
2081                 eDVBFrontendParametersSatellite feparm;
2082                 if (where.getDVBS(feparm))
2083                 {
2084                         eDebug("no dvbs data!");
2085                         res = -EINVAL;
2086                         goto tune_error;
2087                 }
2088                 m_sec->setRotorMoving(false);
2089                 res=prepare_sat(feparm, timeout);
2090                 if (res)
2091                         goto tune_error;
2092
2093                 break;
2094         }
2095         case feCable:
2096         {
2097                 eDVBFrontendParametersCable feparm;
2098                 if (where.getDVBC(feparm))
2099                 {
2100                         res = -EINVAL;
2101                         goto tune_error;
2102                 }
2103                 res=prepare_cable(feparm);
2104                 if (res)
2105                         goto tune_error;
2106
2107                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2108                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2109                 break;
2110         }
2111         case feTerrestrial:
2112         {
2113                 eDVBFrontendParametersTerrestrial feparm;
2114                 if (where.getDVBT(feparm))
2115                 {
2116                         eDebug("no -T data");
2117                         res = -EINVAL;
2118                         goto tune_error;
2119                 }
2120                 res=prepare_terrestrial(feparm);
2121                 if (res)
2122                         goto tune_error;
2123
2124                 std::string enable_5V;
2125                 char configStr[255];
2126                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2127                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2128                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2129                 if (enable_5V == "True")
2130                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2131                 else
2132                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2133                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2134
2135                 break;
2136         }
2137         }
2138
2139         m_tuneTimer->start(0,true);
2140         m_sec_sequence.current() = m_sec_sequence.begin();
2141
2142         if (m_state != stateTuning)
2143         {
2144                 m_tuning = 1;
2145                 m_state = stateTuning;
2146                 m_stateChanged(this);
2147         }
2148
2149         return res;
2150
2151 tune_error:
2152         m_tuneTimer->stop();
2153         return res;
2154 }
2155
2156 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2157 {
2158         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2159         return 0;
2160 }
2161
2162 RESULT eDVBFrontend::setVoltage(int voltage)
2163 {
2164         if (m_type == feCable)
2165                 return -1;
2166 #if HAVE_DVB_API_VERSION < 3
2167         secVoltage vlt;
2168 #else
2169         bool increased=false;
2170         fe_sec_voltage_t vlt;
2171 #endif
2172         m_data[CUR_VOLTAGE]=voltage;
2173         switch (voltage)
2174         {
2175         case voltageOff:
2176                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2177                 vlt = SEC_VOLTAGE_OFF;
2178                 break;
2179         case voltage13_5:
2180 #if HAVE_DVB_API_VERSION < 3
2181                 vlt = SEC_VOLTAGE_13_5;
2182                 break;
2183 #else
2184                 increased = true;
2185 #endif
2186         case voltage13:
2187                 vlt = SEC_VOLTAGE_13;
2188                 break;
2189         case voltage18_5:
2190 #if HAVE_DVB_API_VERSION < 3
2191                 vlt = SEC_VOLTAGE_18_5;
2192                 break;
2193 #else
2194                 increased = true;
2195 #endif
2196         case voltage18:
2197                 vlt = SEC_VOLTAGE_18;
2198                 break;
2199         default:
2200                 return -ENODEV;
2201         }
2202 #if HAVE_DVB_API_VERSION < 3
2203         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2204 #else
2205         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2206                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2207         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2208 #endif
2209 }
2210
2211 RESULT eDVBFrontend::getState(int &state)
2212 {
2213         state = m_state;
2214         return 0;
2215 }
2216
2217 RESULT eDVBFrontend::setTone(int t)
2218 {
2219         if (m_type != feSatellite)
2220                 return -1;
2221 #if HAVE_DVB_API_VERSION < 3
2222         secToneMode_t tone;
2223 #else
2224         fe_sec_tone_mode_t tone;
2225 #endif
2226         m_data[CUR_TONE]=t;
2227         switch (t)
2228         {
2229         case toneOn:
2230                 tone = SEC_TONE_ON;
2231                 break;
2232         case toneOff:
2233                 tone = SEC_TONE_OFF;
2234                 break;
2235         default:
2236                 return -ENODEV;
2237         }
2238 #if HAVE_DVB_API_VERSION < 3    
2239         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2240 #else   
2241         return ::ioctl(m_fd, FE_SET_TONE, tone);
2242 #endif
2243 }
2244
2245 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2246         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2247 #endif
2248
2249 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2250 {
2251 #if HAVE_DVB_API_VERSION < 3
2252         struct secCommand cmd;
2253         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2254         cmd.u.diseqc.cmdtype = diseqc.data[0];
2255         cmd.u.diseqc.addr = diseqc.data[1];
2256         cmd.u.diseqc.cmd = diseqc.data[2];
2257         cmd.u.diseqc.numParams = diseqc.len-3;
2258         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2259         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2260 #else
2261         struct dvb_diseqc_master_cmd cmd;
2262         memcpy(cmd.msg, diseqc.data, diseqc.len);
2263         cmd.msg_len = diseqc.len;
2264         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2265 #endif
2266                 return -EINVAL;
2267         return 0;
2268 }
2269
2270 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2271         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2272 #endif
2273 RESULT eDVBFrontend::sendToneburst(int burst)
2274 {
2275 #if HAVE_DVB_API_VERSION < 3
2276         secMiniCmd cmd = SEC_MINI_NONE;
2277 #else
2278         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2279 #endif
2280         if ( burst == eDVBSatelliteDiseqcParameters::A )
2281                 cmd = SEC_MINI_A;
2282         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2283                 cmd = SEC_MINI_B;
2284 #if HAVE_DVB_API_VERSION < 3
2285         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2286                 return -EINVAL;
2287 #else
2288         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2289                 return -EINVAL;
2290 #endif
2291         return 0;
2292 }
2293
2294 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2295 {
2296         m_sec = sec;
2297         return 0;
2298 }
2299
2300 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2301 {
2302         m_sec_sequence = list;
2303         return 0;
2304 }
2305
2306 RESULT eDVBFrontend::getData(int num, long &data)
2307 {
2308         if ( num < NUM_DATA_ENTRIES )
2309         {
2310                 data = m_data[num];
2311                 return 0;
2312         }
2313         return -EINVAL;
2314 }
2315
2316 RESULT eDVBFrontend::setData(int num, long val)
2317 {
2318         if ( num < NUM_DATA_ENTRIES )
2319         {
2320                 m_data[num] = val;
2321                 return 0;
2322         }
2323         return -EINVAL;
2324 }
2325
2326 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2327 {
2328         int type;
2329         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2330                 return 0;
2331         if (m_type == eDVBFrontend::feSatellite)
2332         {
2333                 ASSERT(m_sec);
2334                 eDVBFrontendParametersSatellite sat_parm;
2335                 int ret = feparm->getDVBS(sat_parm);
2336                 ASSERT(!ret);
2337                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2338                         return 0;
2339                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2340                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2341                         ret -= 1;
2342                 return ret;
2343         }
2344         else if (m_type == eDVBFrontend::feCable)
2345                 return 2;  // more prio for cable frontends
2346         else if (m_type == eDVBFrontend::feTerrestrial)
2347                 return 1;
2348         return 0;
2349 }
2350
2351 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2352 {
2353         ePyObject Id, Descr, Enabled;
2354         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 3)
2355                 goto arg_error;
2356         Id = PyTuple_GET_ITEM(obj, 0);
2357         Descr = PyTuple_GET_ITEM(obj, 1);
2358         Enabled = PyTuple_GET_ITEM(obj, 2);
2359         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled))
2360                 goto arg_error;
2361         strcpy(m_description, PyString_AS_STRING(Descr));
2362         m_slotid = PyInt_AsLong(Id);
2363         m_enabled = Enabled == Py_True;
2364         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2365         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2366                 !!strstr(m_description, "Alps BSBE2") ||
2367                 !!strstr(m_description, "Alps -S") ||
2368                 !!strstr(m_description, "BCM4501");
2369         m_can_handle_dvbs2 = !!strstr(m_description, "Alps BSBE2") || !!strstr(m_description, "BCM4501");
2370         eDebug("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2371                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2372         return true;
2373 arg_error:
2374         PyErr_SetString(PyExc_StandardError,
2375                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2376         return false;
2377 }