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