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