use frontend type infomation in /proc/nim_sockets to detect if a frontend
[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)
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                                         int add=strchr(m_description, '.') ? 0xA250 : 0xA100;
736                                         long regval = 0xFFFF - ((snr / 3) + add), // revert some dvb api calulations to get the real register value
737                                                 Imin=0,
738                                                 Imax=30,
739                                                 i;
740                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[Imax][REGVAL]))
741                                         {
742                                                 long val;
743                                                 while((Imax-Imin)>1)
744                                                 {
745                                                         i=(Imax+Imin)/2;
746                                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[i][REGVAL]))
747                                                                 Imax = i;
748                                                         else
749                                                                 Imin = i;
750                                                 }
751                                                 return (((regval - CN_lookup[Imin][REGVAL])
752                                                                 * (CN_lookup[Imax][REALVAL] - CN_lookup[Imin][REALVAL])
753                                                                 / (CN_lookup[Imax][REGVAL] - CN_lookup[Imin][REGVAL]))
754                                                                 + CN_lookup[Imin][REALVAL]) * 10;
755                                         }
756                                         return 100;
757                                 }
758                                 return 0;
759                         }
760                         else if (!strcmp(m_description, "Alps BSBE1 702A") ||  // some frontends with STV0299
761                                 !strcmp(m_description, "Alps -S") ||
762                                 !strcmp(m_description, "Philips -S") ||
763                                 !strcmp(m_description, "LG -S") )
764                         {
765                                 float snr_in_db=(snr-39075)/1764.7;
766                                 return (int)(snr_in_db * 100.0);
767                         } else if (!strcmp(m_description, "Alps BSBE2"))
768                         {
769                                 return (int)((snr >> 7) * 10.0);
770                         } /* else
771                                 eDebug("no SNR dB calculation for frontendtype %s yet", m_description); */
772                         return 0x12345678;
773                 }
774                 case signalPower:
775                 {
776                         uint16_t strength=0;
777                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
778                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
779                         return strength;
780                 }
781                 case locked:
782                 {
783 #if HAVE_DVB_API_VERSION < 3
784                         FrontendStatus status=0;
785 #else
786                         fe_status_t status;
787 #endif
788                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
789                                 eDebug("FE_READ_STATUS failed (%m)");
790                         return !!(status&FE_HAS_LOCK);
791                 }
792                 case synced:
793                 {
794 #if HAVE_DVB_API_VERSION < 3
795                         FrontendStatus status=0;
796 #else
797                         fe_status_t status;
798 #endif
799                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
800                                 eDebug("FE_READ_STATUS failed (%m)");
801                         return !!(status&FE_HAS_SYNC);
802                 }
803                 case frontendNumber:
804                         return m_slotid;
805         }
806         return 0;
807 }
808
809 void PutToDict(ePyObject &dict, const char*key, long value)
810 {
811         ePyObject item = PyInt_FromLong(value);
812         if (item)
813         {
814                 if (PyDict_SetItemString(dict, key, item))
815                         eDebug("put %s to dict failed", key);
816                 Py_DECREF(item);
817         }
818         else
819                 eDebug("could not create PyObject for %s", key);
820 }
821
822 void PutToDict(ePyObject &dict, const char*key, ePyObject item)
823 {
824         if (item)
825         {
826                 if (PyDict_SetItemString(dict, key, item))
827                         eDebug("put %s to dict failed", key);
828                 Py_DECREF(item);
829         }
830         else
831                 eDebug("invalid PyObject for %s", key);
832 }
833
834 void PutToDict(ePyObject &dict, const char*key, const char *value)
835 {
836         ePyObject item = PyString_FromString(value);
837         if (item)
838         {
839                 if (PyDict_SetItemString(dict, key, item))
840                         eDebug("put %s to dict failed", key);
841                 Py_DECREF(item);
842         }
843         else
844                 eDebug("could not create PyObject for %s", key);
845 }
846
847 void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
848 {
849         long freq_offset=0;
850         const char *tmp=0;
851         fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
852         int frequency = parm_frequency + freq_offset;
853         PutToDict(dict, "frequency", frequency);
854         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
855         switch(parm_u_qpsk_fec_inner)
856         {
857         case FEC_1_2:
858                 tmp = "FEC_1_2";
859                 break;
860         case FEC_2_3:
861                 tmp = "FEC_2_3";
862                 break;
863         case FEC_3_4:
864                 tmp = "FEC_3_4";
865                 break;
866         case FEC_5_6:
867                 tmp = "FEC_5_6";
868                 break;
869         case FEC_7_8:
870                 tmp = "FEC_7_8";
871                 break;
872         case FEC_NONE:
873                 tmp = "FEC_NONE";
874         default:
875         case FEC_AUTO:
876                 tmp = "FEC_AUTO";
877                 break;
878 #if HAVE_DVB_API_VERSION >=3
879         case FEC_S2_8PSK_1_2:
880         case FEC_S2_QPSK_1_2:
881                 tmp = "FEC_1_2";
882                 break;
883         case FEC_S2_8PSK_2_3:
884         case FEC_S2_QPSK_2_3:
885                 tmp = "FEC_2_3";
886                 break;
887         case FEC_S2_8PSK_3_4:
888         case FEC_S2_QPSK_3_4:
889                 tmp = "FEC_3_4";
890                 break;
891         case FEC_S2_8PSK_5_6:
892         case FEC_S2_QPSK_5_6:
893                 tmp = "FEC_5_6";
894                 break;
895         case FEC_S2_8PSK_7_8:
896         case FEC_S2_QPSK_7_8:
897                 tmp = "FEC_7_8";
898                 break;
899         case FEC_S2_8PSK_8_9:
900         case FEC_S2_QPSK_8_9:
901                 tmp = "FEC_8_9";
902                 break;
903         case FEC_S2_8PSK_3_5:
904         case FEC_S2_QPSK_3_5:
905                 tmp = "FEC_3_5";
906                 break;
907         case FEC_S2_8PSK_4_5:
908         case FEC_S2_QPSK_4_5:
909                 tmp = "FEC_4_5";
910                 break;
911         case FEC_S2_8PSK_9_10:
912         case FEC_S2_QPSK_9_10:
913                 tmp = "FEC_9_10";
914                 break;
915 #endif
916         }
917         PutToDict(dict, "fec_inner", tmp);
918 #if HAVE_DVB_API_VERSION >=3
919         PutToDict(dict, "modulation",
920                 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
921         if (parm_u_qpsk_fec_inner > FEC_AUTO)
922         {
923                 switch(parm_inversion & 0xc)
924                 {
925                 default: // unknown rolloff
926                 case 0: // 0.35
927                         tmp = "ROLLOFF_0_35";
928                         break;
929                 case 4: // 0.25
930                         tmp = "ROLLOFF_0_25";
931                         break;
932                 case 8: // 0.20
933                         tmp = "ROLLOFF_0_20";
934                         break;
935                 }
936                 PutToDict(dict, "rolloff", tmp);
937                 if (parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10)
938                 {
939                         switch(parm_inversion & 0x30)
940                         {
941                         case 0: // pilot off
942                                 tmp = "PILOT_OFF";
943                                 break;
944                         case 0x10: // pilot on
945                                 tmp = "PILOT_ON";
946                                 break;
947                         case 0x20: // pilot auto
948                                 tmp = "PILOT_AUTO";
949                                 break;
950                         }
951                         PutToDict(dict, "pilot", tmp);
952                 }
953                 tmp = "DVB-S2";
954         }
955         else
956                 tmp = "DVB-S";
957 #else
958         PutToDict(dict, "modulation", "QPSK" );
959         tmp = "DVB-S";
960 #endif
961         PutToDict(dict, "system", tmp);
962 }
963
964 void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
965 {
966         const char *tmp=0;
967 #if HAVE_DVB_API_VERSION < 3
968         PutToDict(dict, "frequency", parm_frequency);
969 #else
970         PutToDict(dict, "frequency", parm_frequency/1000);
971 #endif
972         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
973         switch(parm_u_qam_fec_inner)
974         {
975         case FEC_NONE:
976                 tmp = "FEC_NONE";
977                 break;
978         case FEC_1_2:
979                 tmp = "FEC_1_2";
980                 break;
981         case FEC_2_3:
982                 tmp = "FEC_2_3";
983                 break;
984         case FEC_3_4:
985                 tmp = "FEC_3_4";
986                 break;
987         case FEC_5_6:
988                 tmp = "FEC_5_6";
989                 break;
990         case FEC_7_8:
991                 tmp = "FEC_7_8";
992                 break;
993 #if HAVE_DVB_API_VERSION >= 3
994         case FEC_8_9:
995                 tmp = "FEC_8_9";
996                 break;
997 #endif
998         default:
999         case FEC_AUTO:
1000                 tmp = "FEC_AUTO";
1001                 break;
1002         }
1003         PutToDict(dict, "fec_inner", tmp);
1004         switch(parm_u_qam_modulation)
1005         {
1006         case QAM_16:
1007                 tmp = "QAM_16";
1008                 break;
1009         case QAM_32:
1010                 tmp = "QAM_32";
1011                 break;
1012         case QAM_64:
1013                 tmp = "QAM_64";
1014                 break;
1015         case QAM_128:
1016                 tmp = "QAM_128";
1017                 break;
1018         case QAM_256:
1019                 tmp = "QAM_256";
1020                 break;
1021         default:
1022         case QAM_AUTO:
1023                 tmp = "QAM_AUTO";
1024                 break;
1025         }
1026         PutToDict(dict, "modulation", tmp);
1027 }
1028
1029 void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1030 {
1031         const char *tmp=0;
1032         PutToDict(dict, "frequency", parm_frequency);
1033         switch (parm_u_ofdm_bandwidth)
1034         {
1035         case BANDWIDTH_8_MHZ:
1036                 tmp = "BANDWIDTH_8_MHZ";
1037                 break;
1038         case BANDWIDTH_7_MHZ:
1039                 tmp = "BANDWIDTH_7_MHZ";
1040                 break;
1041         case BANDWIDTH_6_MHZ:
1042                 tmp = "BANDWIDTH_6_MHZ";
1043                 break;
1044         default:
1045         case BANDWIDTH_AUTO:
1046                 tmp = "BANDWIDTH_AUTO";
1047                 break;
1048         }
1049         PutToDict(dict, "bandwidth", tmp);
1050         switch (parm_u_ofdm_code_rate_LP)
1051         {
1052         case FEC_1_2:
1053                 tmp = "FEC_1_2";
1054                 break;
1055         case FEC_2_3:
1056                 tmp = "FEC_2_3";
1057                 break;
1058         case FEC_3_4:
1059                 tmp = "FEC_3_4";
1060                 break;
1061         case FEC_5_6:
1062                 tmp = "FEC_5_6";
1063                 break;
1064         case FEC_7_8:
1065                 tmp = "FEC_7_8";
1066                 break;
1067         default:
1068         case FEC_AUTO:
1069                 tmp = "FEC_AUTO";
1070                 break;
1071         }
1072         PutToDict(dict, "code_rate_lp", tmp);
1073         switch (parm_u_ofdm_code_rate_HP)
1074         {
1075         case FEC_1_2:
1076                 tmp = "FEC_1_2";
1077                 break;
1078         case FEC_2_3:
1079                 tmp = "FEC_2_3";
1080                 break;
1081         case FEC_3_4:
1082                 tmp = "FEC_3_4";
1083                 break;
1084         case FEC_5_6:
1085                 tmp = "FEC_5_6";
1086                 break;
1087         case FEC_7_8:
1088                 tmp = "FEC_7_8";
1089                 break;
1090         default:
1091         case FEC_AUTO:
1092                 tmp = "FEC_AUTO";
1093                 break;
1094         }
1095         PutToDict(dict, "code_rate_hp", tmp);
1096         switch (parm_u_ofdm_constellation)
1097         {
1098         case QPSK:
1099                 tmp = "QPSK";
1100                 break;
1101         case QAM_16:
1102                 tmp = "QAM_16";
1103                 break;
1104         case QAM_64:
1105                 tmp = "QAM_64";
1106                 break;
1107         default:
1108         case QAM_AUTO:
1109                 tmp = "QAM_AUTO";
1110                 break;
1111         }
1112         PutToDict(dict, "constellation", tmp);
1113         switch (parm_u_ofdm_transmission_mode)
1114         {
1115         case TRANSMISSION_MODE_2K:
1116                 tmp = "TRANSMISSION_MODE_2K";
1117                 break;
1118         case TRANSMISSION_MODE_8K:
1119                 tmp = "TRANSMISSION_MODE_8K";
1120                 break;
1121         default:
1122         case TRANSMISSION_MODE_AUTO:
1123                 tmp = "TRANSMISSION_MODE_AUTO";
1124                 break;
1125         }
1126         PutToDict(dict, "transmission_mode", tmp);
1127         switch (parm_u_ofdm_guard_interval)
1128         {
1129                 case GUARD_INTERVAL_1_32:
1130                         tmp = "GUARD_INTERVAL_1_32";
1131                         break;
1132                 case GUARD_INTERVAL_1_16:
1133                         tmp = "GUARD_INTERVAL_1_16";
1134                         break;
1135                 case GUARD_INTERVAL_1_8:
1136                         tmp = "GUARD_INTERVAL_1_8";
1137                         break;
1138                 case GUARD_INTERVAL_1_4:
1139                         tmp = "GUARD_INTERVAL_1_4";
1140                         break;
1141                 default:
1142                 case GUARD_INTERVAL_AUTO:
1143                         tmp = "GUARD_INTERVAL_AUTO";
1144                         break;
1145         }
1146         PutToDict(dict, "guard_interval", tmp);
1147         switch (parm_u_ofdm_hierarchy_information)
1148         {
1149                 case HIERARCHY_NONE:
1150                         tmp = "HIERARCHY_NONE";
1151                         break;
1152                 case HIERARCHY_1:
1153                         tmp = "HIERARCHY_1";
1154                         break;
1155                 case HIERARCHY_2:
1156                         tmp = "HIERARCHY_2";
1157                         break;
1158                 case HIERARCHY_4:
1159                         tmp = "HIERARCHY_4";
1160                         break;
1161                 default:
1162                 case HIERARCHY_AUTO:
1163                         tmp = "HIERARCHY_AUTO";
1164                         break;
1165         }
1166         PutToDict(dict, "hierarchy_information", tmp);
1167 }
1168
1169 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1170 {
1171         if (dest && PyDict_Check(dest))
1172         {
1173                 const char *tmp = "UNKNOWN";
1174                 switch(m_state)
1175                 {
1176                         case stateIdle:
1177                                 tmp="IDLE";
1178                                 break;
1179                         case stateTuning:
1180                                 tmp="TUNING";
1181                                 break;
1182                         case stateFailed:
1183                                 tmp="FAILED";
1184                                 break;
1185                         case stateLock:
1186                                 tmp="LOCKED";
1187                                 break;
1188                         case stateLostLock:
1189                                 tmp="LOSTLOCK";
1190                                 break;
1191                         default:
1192                                 break;
1193                 }
1194                 PutToDict(dest, "tuner_state", tmp);
1195                 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1196                 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1197                 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1198                 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1199                 int sigQualitydB = readFrontendData(signalQualitydB);
1200                 if (sigQualitydB == 0x12345678) // not support yet
1201                 {
1202                         ePyObject obj=Py_None;
1203                         Py_INCREF(obj);
1204                         PutToDict(dest, "tuner_signal_quality_db", obj);
1205                 }
1206                 else
1207                         PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1208                 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1209         }
1210 }
1211
1212 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1213 {
1214         if (m_fd != -1 && dest && PyDict_Check(dest))
1215         {
1216                 switch(m_type)
1217                 {
1218                         case feSatellite:
1219                         case feCable:
1220                         case feTerrestrial:
1221                         {
1222                                 FRONTENDPARAMETERS front;
1223                                 if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1224                                         eDebug("FE_GET_FRONTEND (%m)");
1225                                 else
1226                                 {
1227                                         const FRONTENDPARAMETERS &parm = original ? this->parm : front;
1228                                         const char *tmp = "INVERSION_AUTO";
1229                                         switch(parm_inversion)
1230                                         {
1231                                                 case INVERSION_ON:
1232                                                         tmp = "INVERSION_ON";
1233                                                         break;
1234                                                 case INVERSION_OFF:
1235                                                         tmp = "INVERSION_OFF";
1236                                                         break;
1237                                                 default:
1238                                                         break;
1239                                         }
1240                                         if (tmp)
1241                                                 PutToDict(dest, "inversion", tmp);
1242
1243                                         switch(m_type)
1244                                         {
1245                                                 case feSatellite:
1246                                                         fillDictWithSatelliteData(dest, original?parm:front, this);
1247                                                         break;
1248                                                 case feCable:
1249                                                         fillDictWithCableData(dest, original?parm:front);
1250                                                         break;
1251                                                 case feTerrestrial:
1252                                                         fillDictWithTerrestrialData(dest, original?parm:front);
1253                                                         break;
1254                                         }
1255                                 }
1256                         }
1257                         default:
1258                                 break;
1259                 }
1260         }
1261 }
1262
1263 void eDVBFrontend::getFrontendData(ePyObject dest)
1264 {
1265         if (dest && PyDict_Check(dest))
1266         {
1267                 const char *tmp=0;
1268                 PutToDict(dest, "tuner_number", m_slotid);
1269                 switch(m_type)
1270                 {
1271                         case feSatellite:
1272                                 tmp = "DVB-S";
1273                                 break;
1274                         case feCable:
1275                                 tmp = "DVB-C";
1276                                 break;
1277                         case feTerrestrial:
1278                                 tmp = "DVB-T";
1279                                 break;
1280                         default:
1281                                 tmp = "UNKNOWN";
1282                                 break;
1283                 }
1284                 PutToDict(dest, "tuner_type", tmp);
1285         }
1286 }
1287
1288 #ifndef FP_IOCTL_GET_ID
1289 #define FP_IOCTL_GET_ID 0
1290 #endif
1291 int eDVBFrontend::readInputpower()
1292 {
1293         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1294         char proc_name[64];
1295         sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1296         FILE *f=fopen(proc_name, "r");
1297         if (f)
1298         {
1299                 if (fscanf(f, "%d", &power) != 1)
1300                         eDebug("read %s failed!! (%m)", proc_name);
1301                 else
1302                         eDebug("%s is %d\n", proc_name, power);
1303                 fclose(f);
1304         }
1305         else
1306         {
1307                 // open front prozessor
1308                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1309                 if (fp < 0)
1310                 {
1311                         eDebug("couldn't open fp");
1312                         return -1;
1313                 }
1314                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1315                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1316                 {
1317                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1318                         return -1;
1319                 }
1320                 ::close(fp);
1321         }
1322
1323         return power;
1324 }
1325
1326 bool eDVBFrontend::setSecSequencePos(int steps)
1327 {
1328         eDebug("set sequence pos %d", steps);
1329         if (!steps)
1330                 return false;
1331         while( steps > 0 )
1332         {
1333                 if (m_sec_sequence.current() != m_sec_sequence.end())
1334                         ++m_sec_sequence.current();
1335                 --steps;
1336         }
1337         while( steps < 0 )
1338         {
1339                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1340                         --m_sec_sequence.current();
1341                 ++steps;
1342         }
1343         return true;
1344 }
1345
1346 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1347 {
1348         int delay=0;
1349         eDVBFrontend *sec_fe = this;
1350         eDVBRegisteredFrontend *regFE = 0;
1351         long tmp = m_data[LINKED_PREV_PTR];
1352         while ( tmp != -1 )
1353         {
1354                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1355                 sec_fe = prev->m_frontend;
1356                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1357                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1358                         int state = sec_fe->m_state;
1359                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1360                         {
1361                                 sec_fe->closeFrontend(true);
1362                                 state = sec_fe->m_state;
1363                         }
1364                         if (state == eDVBFrontend::stateClosed)
1365                         {
1366                                 regFE = prev;
1367                                 prev->inc_use();
1368                         }
1369                 }
1370         }
1371
1372         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1373         {
1374                 long *sec_fe_data = sec_fe->m_data;
1375 //              eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1376                 switch (m_sec_sequence.current()->cmd)
1377                 {
1378                         case eSecCommand::SLEEP:
1379                                 delay = m_sec_sequence.current()++->msec;
1380                                 eDebug("[SEC] sleep %dms", delay);
1381                                 break;
1382                         case eSecCommand::GOTO:
1383                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1384                                         ++m_sec_sequence.current();
1385                                 break;
1386                         case eSecCommand::SET_VOLTAGE:
1387                         {
1388                                 int voltage = m_sec_sequence.current()++->voltage;
1389                                 eDebug("[SEC] setVoltage %d", voltage);
1390                                 sec_fe->setVoltage(voltage);
1391                                 break;
1392                         }
1393                         case eSecCommand::IF_VOLTAGE_GOTO:
1394                         {
1395                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1396                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1397                                         break;
1398                                 ++m_sec_sequence.current();
1399                                 break;
1400                         }
1401                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1402                         {
1403                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1404                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1405                                         break;
1406                                 ++m_sec_sequence.current();
1407                                 break;
1408                         }
1409                         case eSecCommand::IF_TONE_GOTO:
1410                         {
1411                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1412                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1413                                         break;
1414                                 ++m_sec_sequence.current();
1415                                 break;
1416                         }
1417                         case eSecCommand::IF_NOT_TONE_GOTO:
1418                         {
1419                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1420                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1421                                         break;
1422                                 ++m_sec_sequence.current();
1423                                 break;
1424                         }
1425                         case eSecCommand::SET_TONE:
1426                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
1427                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1428                                 break;
1429                         case eSecCommand::SEND_DISEQC:
1430                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1431                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
1432                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1433                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1434                                 eDebug("");
1435                                 ++m_sec_sequence.current();
1436                                 break;
1437                         case eSecCommand::SEND_TONEBURST:
1438                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1439                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1440                                 break;
1441                         case eSecCommand::SET_FRONTEND:
1442                                 eDebug("[SEC] setFrontend");
1443                                 setFrontend();
1444                                 ++m_sec_sequence.current();
1445                                 break;
1446                         case eSecCommand::START_TUNE_TIMEOUT:
1447                         {
1448                                 m_timeout->start(m_sec_sequence.current()->timeout, 1);
1449                                 ++m_sec_sequence.current();
1450                                 break;
1451                         }
1452                         case eSecCommand::SET_TIMEOUT:
1453                                 m_timeoutCount = m_sec_sequence.current()++->val;
1454                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
1455                                 break;
1456                         case eSecCommand::IF_TIMEOUT_GOTO:
1457                                 if (!m_timeoutCount)
1458                                 {
1459                                         eDebug("[SEC] rotor timout");
1460                                         setSecSequencePos(m_sec_sequence.current()->steps);
1461                                 }
1462                                 else
1463                                         ++m_sec_sequence.current();
1464                                 break;
1465                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1466                         {
1467                                 int idx = m_sec_sequence.current()++->val;
1468                                 if ( idx == 0 || idx == 1 )
1469                                 {
1470                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1471                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1472                                 }
1473                                 else
1474                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1475                                 break;
1476                         }
1477                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1478                         {
1479                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1480                                 int idx = compare.val;
1481                                 if ( idx == 0 || idx == 1 )
1482                                 {
1483                                         int idle = sec_fe->readInputpower();
1484                                         int diff = abs(idle-m_idleInputpower[idx]);
1485                                         if ( diff > 0)
1486                                         {
1487                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1488                                                 setSecSequencePos(compare.steps);
1489                                                 break;
1490                                         }
1491                                 }
1492                                 ++m_sec_sequence.current();
1493                                 break;
1494                         }
1495                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1496                         {
1497                                 int signal = 0;
1498                                 int isLocked = readFrontendData(locked);
1499                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1500                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1501                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1502                                 {
1503                                         if (cmd.lastSignal)
1504                                                 eDebug("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1505                                         else
1506                                         {
1507                                                 eDebug("[SEC] locked step %d ok", cmd.okcount);
1508                                                 cmd.lastSignal = signal;
1509                                         }
1510                                         ++cmd.okcount;
1511                                         if (cmd.okcount > 4)
1512                                         {
1513                                                 eDebug("ok > 4 .. goto %d\n",cmd.steps);
1514                                                 setSecSequencePos(cmd.steps);
1515                                                 m_state = stateLock;
1516                                                 m_stateChanged(this);
1517                                                 feEvent(-1);
1518                                                 m_sn->start();
1519                                                 break;
1520                                         }
1521                                 }
1522                                 else
1523                                 {
1524                                         if (isLocked)
1525                                                 eDebug("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1526                                         else
1527                                                 eDebug("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1528                                         --m_timeoutCount;
1529                                         if (!m_timeoutCount && m_retryCount > 0)
1530                                                 --m_retryCount;
1531                                         cmd.okcount=0;
1532                                         cmd.lastSignal=0;
1533                                 }
1534                                 ++m_sec_sequence.current();
1535                                 break;
1536                         }
1537                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1538                                 m_runningInputpower = sec_fe->readInputpower();
1539                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
1540                                 ++m_sec_sequence.current();
1541                                 break;
1542                         case eSecCommand::SET_ROTOR_MOVING:
1543                                 m_sec->setRotorMoving(true);
1544                                 ++m_sec_sequence.current();
1545                                 break;
1546                         case eSecCommand::SET_ROTOR_STOPPED:
1547                                 m_sec->setRotorMoving(false);
1548                                 ++m_sec_sequence.current();
1549                                 break;
1550                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1551                         {
1552                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1553                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1554                                 const char *txt = cmd.direction ? "running" : "stopped";
1555                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1556                                         txt,
1557                                         m_runningInputpower,
1558                                         idleInputpower,
1559                                         cmd.deltaA);
1560                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1561                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1562                                 {
1563                                         ++cmd.okcount;
1564                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1565                                         if ( cmd.okcount > 6 )
1566                                         {
1567                                                 eDebug("[SEC] rotor is %s", txt);
1568                                                 if (setSecSequencePos(cmd.steps))
1569                                                         break;
1570                                         }
1571                                 }
1572                                 else
1573                                 {
1574                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1575                                         --m_timeoutCount;
1576                                         if (!m_timeoutCount && m_retryCount > 0)
1577                                                 --m_retryCount;
1578                                         cmd.okcount=0;
1579                                 }
1580                                 ++m_sec_sequence.current();
1581                                 break;
1582                         }
1583                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1584                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1585                                         setSecSequencePos(m_sec_sequence.current()->steps);
1586                                 else
1587                                         ++m_sec_sequence.current();
1588                                 break;
1589                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1590                                 eDebug("[SEC] invalidate current switch params");
1591                                 sec_fe_data[CSW] = -1;
1592                                 sec_fe_data[UCSW] = -1;
1593                                 sec_fe_data[TONEBURST] = -1;
1594                                 ++m_sec_sequence.current();
1595                                 break;
1596                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1597                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1598                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1599                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1600                                 eDebug("[SEC] update current switch params");
1601                                 ++m_sec_sequence.current();
1602                                 break;
1603                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1604                                 eDebug("[SEC] invalidate current rotorparams");
1605                                 sec_fe_data[ROTOR_CMD] = -1;
1606                                 sec_fe_data[ROTOR_POS] = -1;
1607                                 ++m_sec_sequence.current();
1608                                 break;
1609                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1610                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1611                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1612                                 eDebug("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1613                                 ++m_sec_sequence.current();
1614                                 break;
1615                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1616                                 m_retryCount = m_sec_sequence.current()++->val;
1617                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
1618                                 break;
1619                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1620                                 if (!m_retryCount)
1621                                 {
1622                                         eDebug("[SEC] no more rotor retrys");
1623                                         setSecSequencePos(m_sec_sequence.current()->steps);
1624                                 }
1625                                 else
1626                                         ++m_sec_sequence.current();
1627                                 break;
1628                         case eSecCommand::SET_POWER_LIMITING_MODE:
1629                         {
1630                                 char proc_name[64];
1631                                 sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1632                                 FILE *f=fopen(proc_name, "w");
1633                                 if (f) // new interface exist?
1634                                 {
1635                                         bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1636                                         if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1637                                                 eDebug("write %s failed!! (%m)", proc_name);
1638                                         else
1639                                                 eDebug("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1640                                         fclose(f);
1641                                 }
1642                                 else if (sec_fe->m_need_rotor_workaround)
1643                                 {
1644                                         char dev[16];
1645                                         int slotid = sec_fe->m_slotid;
1646                                         // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1647                                         if (slotid < 2)
1648                                                 sprintf(dev, "/dev/i2c/%d", slotid);
1649                                         else if (slotid == 2)
1650                                                 sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1651                                         else if (slotid == 3)
1652                                                 sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1653                                         int fd = ::open(dev, O_RDWR);
1654
1655                                         unsigned char data[2];
1656                                         ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1657                                         if(::read(fd, data, 1) != 1)
1658                                                 eDebug("[SEC] error read lnbp (%m)");
1659                                         if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1660                                         {
1661                                                 data[0] |= 0x80;  // enable static current limiting
1662                                                 eDebug("[SEC] set static current limiting");
1663                                         }
1664                                         else
1665                                         {
1666                                                 data[0] &= ~0x80;  // enable dynamic current limiting
1667                                                 eDebug("[SEC] set dynamic current limiting");
1668                                         }
1669                                         if(::write(fd, data, 1) != 1)
1670                                                 eDebug("[SEC] error write lnbp (%m)");
1671                                         ::close(fd);
1672                                 }
1673                                 ++m_sec_sequence.current();
1674                                 break;
1675                         }
1676                         default:
1677                                 eDebug("[SEC] unhandled sec command %d",
1678                                         ++m_sec_sequence.current()->cmd);
1679                                 ++m_sec_sequence.current();
1680                 }
1681                 m_tuneTimer->start(delay,true);
1682         }
1683         if (regFE)
1684                 regFE->dec_use();
1685 }
1686
1687 void eDVBFrontend::setFrontend()
1688 {
1689         eDebug("setting frontend %d", m_dvbid);
1690         m_sn->start();
1691         feEvent(-1);
1692         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1693         {
1694                 perror("FE_SET_FRONTEND failed");
1695                 return;
1696         }
1697 }
1698
1699 RESULT eDVBFrontend::getFrontendType(int &t)
1700 {
1701         if (m_type == -1)
1702                 return -ENODEV;
1703         t = m_type;
1704         return 0;
1705 }
1706
1707 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1708 {
1709         int res;
1710         if (!m_sec)
1711         {
1712                 eWarning("no SEC module active!");
1713                 return -ENOENT;
1714         }
1715         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1716         if (!res)
1717         {
1718                 eDebug("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1719                         feparm.system,
1720                         feparm.frequency,
1721                         feparm.polarisation,
1722                         feparm.symbol_rate,
1723                         feparm.inversion,
1724                         feparm.fec,
1725                         feparm.orbital_position);
1726                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1727                 switch (feparm.inversion)
1728                 {
1729                         case eDVBFrontendParametersSatellite::Inversion::On:
1730                                 parm_inversion = INVERSION_ON;
1731                                 break;
1732                         case eDVBFrontendParametersSatellite::Inversion::Off:
1733                                 parm_inversion = INVERSION_OFF;
1734                                 break;
1735                         default:
1736                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1737                                 parm_inversion = INVERSION_AUTO;
1738                                 break;
1739                 }
1740                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1741                         switch (feparm.fec)
1742                         {
1743                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1744                                         parm_u_qpsk_fec_inner = FEC_NONE;
1745                                         break;
1746                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1747                                         parm_u_qpsk_fec_inner = FEC_1_2;
1748                                         break;
1749                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1750                                         parm_u_qpsk_fec_inner = FEC_2_3;
1751                                         break;
1752                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1753                                         parm_u_qpsk_fec_inner = FEC_3_4;
1754                                         break;
1755                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1756                                         parm_u_qpsk_fec_inner = FEC_5_6;
1757                                         break;
1758                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1759                                         parm_u_qpsk_fec_inner = FEC_7_8;
1760                                         break;
1761                                 default:
1762                                         eDebug("no valid fec for DVB-S set.. assume auto");
1763                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1764                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1765                                         break;
1766                         }
1767 #if HAVE_DVB_API_VERSION >= 3
1768                 else // DVB_S2
1769                 {
1770                         switch (feparm.fec)
1771                         {
1772                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1773                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1774                                         break;
1775                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1776                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1777                                         break;
1778                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1779                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1780                                         break;
1781                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1782                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1783                                         break;
1784                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1785                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1786                                         break;
1787                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1788                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1789                                         break;
1790                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1791                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1792                                         break;
1793                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1794                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1795                                         break;
1796                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1797                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1798                                         break;
1799                                 default:
1800                                         eDebug("no valid fec for DVB-S2 set.. abort !!");
1801                                         return -EINVAL;
1802                         }
1803                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1804                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1805                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1806                                 // 8PSK fec driver values are decimal 9 bigger
1807                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1808                         }
1809                 }
1810 #endif
1811                 // FIXME !!! get frequency range from tuner
1812                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1813                 {
1814                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1815                         return -EINVAL;
1816                 }
1817                 eDebug("tuning to %d mhz", parm_frequency/1000);
1818         }
1819         return res;
1820 }
1821
1822 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1823 {
1824 #if HAVE_DVB_API_VERSION < 3
1825         parm_frequency = feparm.frequency;
1826 #else
1827         parm_frequency = feparm.frequency * 1000;
1828 #endif
1829         parm_u_qam_symbol_rate = feparm.symbol_rate;
1830         switch (feparm.modulation)
1831         {
1832         case eDVBFrontendParametersCable::Modulation::QAM16:
1833                 parm_u_qam_modulation = QAM_16;
1834                 break;
1835         case eDVBFrontendParametersCable::Modulation::QAM32:
1836                 parm_u_qam_modulation = QAM_32;
1837                 break;
1838         case eDVBFrontendParametersCable::Modulation::QAM64:
1839                 parm_u_qam_modulation = QAM_64;
1840                 break;
1841         case eDVBFrontendParametersCable::Modulation::QAM128:
1842                 parm_u_qam_modulation = QAM_128;
1843                 break;
1844         case eDVBFrontendParametersCable::Modulation::QAM256:
1845                 parm_u_qam_modulation = QAM_256;
1846                 break;
1847         default:
1848         case eDVBFrontendParametersCable::Modulation::Auto:
1849                 parm_u_qam_modulation = QAM_AUTO;
1850                 break;
1851         }
1852         switch (feparm.inversion)
1853         {
1854         case eDVBFrontendParametersCable::Inversion::On:
1855                 parm_inversion = INVERSION_ON;
1856                 break;
1857         case eDVBFrontendParametersCable::Inversion::Off:
1858                 parm_inversion = INVERSION_OFF;
1859                 break;
1860         default:
1861         case eDVBFrontendParametersCable::Inversion::Unknown:
1862                 parm_inversion = INVERSION_AUTO;
1863                 break;
1864         }
1865         switch (feparm.fec_inner)
1866         {
1867         case eDVBFrontendParametersCable::FEC::fNone:
1868                 parm_u_qam_fec_inner = FEC_NONE;
1869                 break;
1870         case eDVBFrontendParametersCable::FEC::f1_2:
1871                 parm_u_qam_fec_inner = FEC_1_2;
1872                 break;
1873         case eDVBFrontendParametersCable::FEC::f2_3:
1874                 parm_u_qam_fec_inner = FEC_2_3;
1875                 break;
1876         case eDVBFrontendParametersCable::FEC::f3_4:
1877                 parm_u_qam_fec_inner = FEC_3_4;
1878                 break;
1879         case eDVBFrontendParametersCable::FEC::f5_6:
1880                 parm_u_qam_fec_inner = FEC_5_6;
1881                 break;
1882         case eDVBFrontendParametersCable::FEC::f7_8:
1883                 parm_u_qam_fec_inner = FEC_7_8;
1884                 break;
1885 #if HAVE_DVB_API_VERSION >= 3
1886         case eDVBFrontendParametersCable::FEC::f8_9:
1887                 parm_u_qam_fec_inner = FEC_8_9;
1888                 break;
1889 #endif
1890         default:
1891         case eDVBFrontendParametersCable::FEC::fAuto:
1892                 parm_u_qam_fec_inner = FEC_AUTO;
1893                 break;
1894         }
1895         eDebug("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1896                 parm_frequency/1000,
1897                 parm_u_qam_symbol_rate,
1898                 parm_u_qam_fec_inner,
1899                 parm_u_qam_modulation,
1900                 parm_inversion);
1901         return 0;
1902 }
1903
1904 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1905 {
1906         parm_frequency = feparm.frequency;
1907
1908         switch (feparm.bandwidth)
1909         {
1910         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1911                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1912                 break;
1913         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1914                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1915                 break;
1916         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1917                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1918                 break;
1919         default:
1920         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1921                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1922                 break;
1923         }
1924         switch (feparm.code_rate_LP)
1925         {
1926         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1927                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1928                 break;
1929         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1930                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1931                 break;
1932         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1933                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1934                 break;
1935         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1936                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1937                 break;
1938         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1939                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1940                 break;
1941         default:
1942         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1943                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1944                 break;
1945         }
1946         switch (feparm.code_rate_HP)
1947         {
1948         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1949                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1950                 break;
1951         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1952                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1953                 break;
1954         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1955                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1956                 break;
1957         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1958                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1959                 break;
1960         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1961                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1962                 break;
1963         default:
1964         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1965                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1966                 break;
1967         }
1968         switch (feparm.modulation)
1969         {
1970         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1971                 parm_u_ofdm_constellation = QPSK;
1972                 break;
1973         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1974                 parm_u_ofdm_constellation = QAM_16;
1975                 break;
1976         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
1977                 parm_u_ofdm_constellation = QAM_64;
1978                 break;
1979         default:
1980         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1981                 parm_u_ofdm_constellation = QAM_AUTO;
1982                 break;
1983         }
1984         switch (feparm.transmission_mode)
1985         {
1986         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1987                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1988                 break;
1989         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1990                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1991                 break;
1992         default:
1993         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1994                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1995                 break;
1996         }
1997         switch (feparm.guard_interval)
1998         {
1999                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
2000                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2001                         break;
2002                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2003                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2004                         break;
2005                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2006                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2007                         break;
2008                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2009                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2010                         break;
2011                 default:
2012                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2013                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2014                         break;
2015         }
2016         switch (feparm.hierarchy)
2017         {
2018                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2019                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2020                         break;
2021                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2022                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2023                         break;
2024                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2025                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2026                         break;
2027                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2028                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2029                         break;
2030                 default:
2031                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2032                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2033                         break;
2034         }
2035         switch (feparm.inversion)
2036         {
2037         case eDVBFrontendParametersTerrestrial::Inversion::On:
2038                 parm_inversion = INVERSION_ON;
2039                 break;
2040         case eDVBFrontendParametersTerrestrial::Inversion::Off:
2041                 parm_inversion = INVERSION_OFF;
2042                 break;
2043         default:
2044         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2045                 parm_inversion = INVERSION_AUTO;
2046                 break;
2047         }
2048         return 0;
2049 }
2050
2051 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2052 {
2053         unsigned int timeout = 5000;
2054         eDebug("(%d)tune", m_dvbid);
2055
2056         m_timeout->stop();
2057
2058         int res=0;
2059
2060         if (!m_sn)
2061         {
2062                 eDebug("no frontend device opened... do not try to tune !!!");
2063                 res = -ENODEV;
2064                 goto tune_error;
2065         }
2066
2067         if (m_type == -1)
2068         {
2069                 res = -ENODEV;
2070                 goto tune_error;
2071         }
2072
2073         m_sn->stop();
2074         m_sec_sequence.clear();
2075
2076         where.calcLockTimeout(timeout);
2077
2078         switch (m_type)
2079         {
2080         case feSatellite:
2081         {
2082                 eDVBFrontendParametersSatellite feparm;
2083                 if (where.getDVBS(feparm))
2084                 {
2085                         eDebug("no dvbs data!");
2086                         res = -EINVAL;
2087                         goto tune_error;
2088                 }
2089                 m_sec->setRotorMoving(false);
2090                 res=prepare_sat(feparm, timeout);
2091                 if (res)
2092                         goto tune_error;
2093
2094                 break;
2095         }
2096         case feCable:
2097         {
2098                 eDVBFrontendParametersCable feparm;
2099                 if (where.getDVBC(feparm))
2100                 {
2101                         res = -EINVAL;
2102                         goto tune_error;
2103                 }
2104                 res=prepare_cable(feparm);
2105                 if (res)
2106                         goto tune_error;
2107
2108                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2109                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2110                 break;
2111         }
2112         case feTerrestrial:
2113         {
2114                 eDVBFrontendParametersTerrestrial feparm;
2115                 if (where.getDVBT(feparm))
2116                 {
2117                         eDebug("no -T data");
2118                         res = -EINVAL;
2119                         goto tune_error;
2120                 }
2121                 res=prepare_terrestrial(feparm);
2122                 if (res)
2123                         goto tune_error;
2124
2125                 std::string enable_5V;
2126                 char configStr[255];
2127                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2128                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2129                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2130                 if (enable_5V == "True")
2131                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2132                 else
2133                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2134                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2135
2136                 break;
2137         }
2138         }
2139
2140         m_tuneTimer->start(0,true);
2141         m_sec_sequence.current() = m_sec_sequence.begin();
2142
2143         if (m_state != stateTuning)
2144         {
2145                 m_tuning = 1;
2146                 m_state = stateTuning;
2147                 m_stateChanged(this);
2148         }
2149
2150         return res;
2151
2152 tune_error:
2153         m_tuneTimer->stop();
2154         return res;
2155 }
2156
2157 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2158 {
2159         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2160         return 0;
2161 }
2162
2163 RESULT eDVBFrontend::setVoltage(int voltage)
2164 {
2165         if (m_type == feCable)
2166                 return -1;
2167 #if HAVE_DVB_API_VERSION < 3
2168         secVoltage vlt;
2169 #else
2170         bool increased=false;
2171         fe_sec_voltage_t vlt;
2172 #endif
2173         m_data[CUR_VOLTAGE]=voltage;
2174         switch (voltage)
2175         {
2176         case voltageOff:
2177                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2178                 vlt = SEC_VOLTAGE_OFF;
2179                 break;
2180         case voltage13_5:
2181 #if HAVE_DVB_API_VERSION < 3
2182                 vlt = SEC_VOLTAGE_13_5;
2183                 break;
2184 #else
2185                 increased = true;
2186 #endif
2187         case voltage13:
2188                 vlt = SEC_VOLTAGE_13;
2189                 break;
2190         case voltage18_5:
2191 #if HAVE_DVB_API_VERSION < 3
2192                 vlt = SEC_VOLTAGE_18_5;
2193                 break;
2194 #else
2195                 increased = true;
2196 #endif
2197         case voltage18:
2198                 vlt = SEC_VOLTAGE_18;
2199                 break;
2200         default:
2201                 return -ENODEV;
2202         }
2203 #if HAVE_DVB_API_VERSION < 3
2204         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2205 #else
2206         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2207                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2208         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2209 #endif
2210 }
2211
2212 RESULT eDVBFrontend::getState(int &state)
2213 {
2214         state = m_state;
2215         return 0;
2216 }
2217
2218 RESULT eDVBFrontend::setTone(int t)
2219 {
2220         if (m_type != feSatellite)
2221                 return -1;
2222 #if HAVE_DVB_API_VERSION < 3
2223         secToneMode_t tone;
2224 #else
2225         fe_sec_tone_mode_t tone;
2226 #endif
2227         m_data[CUR_TONE]=t;
2228         switch (t)
2229         {
2230         case toneOn:
2231                 tone = SEC_TONE_ON;
2232                 break;
2233         case toneOff:
2234                 tone = SEC_TONE_OFF;
2235                 break;
2236         default:
2237                 return -ENODEV;
2238         }
2239 #if HAVE_DVB_API_VERSION < 3    
2240         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2241 #else   
2242         return ::ioctl(m_fd, FE_SET_TONE, tone);
2243 #endif
2244 }
2245
2246 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2247         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2248 #endif
2249
2250 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2251 {
2252 #if HAVE_DVB_API_VERSION < 3
2253         struct secCommand cmd;
2254         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2255         cmd.u.diseqc.cmdtype = diseqc.data[0];
2256         cmd.u.diseqc.addr = diseqc.data[1];
2257         cmd.u.diseqc.cmd = diseqc.data[2];
2258         cmd.u.diseqc.numParams = diseqc.len-3;
2259         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2260         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2261 #else
2262         struct dvb_diseqc_master_cmd cmd;
2263         memcpy(cmd.msg, diseqc.data, diseqc.len);
2264         cmd.msg_len = diseqc.len;
2265         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2266 #endif
2267                 return -EINVAL;
2268         return 0;
2269 }
2270
2271 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2272         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2273 #endif
2274 RESULT eDVBFrontend::sendToneburst(int burst)
2275 {
2276 #if HAVE_DVB_API_VERSION < 3
2277         secMiniCmd cmd = SEC_MINI_NONE;
2278 #else
2279         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2280 #endif
2281         if ( burst == eDVBSatelliteDiseqcParameters::A )
2282                 cmd = SEC_MINI_A;
2283         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2284                 cmd = SEC_MINI_B;
2285 #if HAVE_DVB_API_VERSION < 3
2286         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2287                 return -EINVAL;
2288 #else
2289         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2290                 return -EINVAL;
2291 #endif
2292         return 0;
2293 }
2294
2295 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2296 {
2297         m_sec = sec;
2298         return 0;
2299 }
2300
2301 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2302 {
2303         m_sec_sequence = list;
2304         return 0;
2305 }
2306
2307 RESULT eDVBFrontend::getData(int num, long &data)
2308 {
2309         if ( num < NUM_DATA_ENTRIES )
2310         {
2311                 data = m_data[num];
2312                 return 0;
2313         }
2314         return -EINVAL;
2315 }
2316
2317 RESULT eDVBFrontend::setData(int num, long val)
2318 {
2319         if ( num < NUM_DATA_ENTRIES )
2320         {
2321                 m_data[num] = val;
2322                 return 0;
2323         }
2324         return -EINVAL;
2325 }
2326
2327 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2328 {
2329         int type;
2330         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2331                 return 0;
2332         if (m_type == eDVBFrontend::feSatellite)
2333         {
2334                 ASSERT(m_sec);
2335                 eDVBFrontendParametersSatellite sat_parm;
2336                 int ret = feparm->getDVBS(sat_parm);
2337                 ASSERT(!ret);
2338                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2339                         return 0;
2340                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2341                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2342                         ret -= 1;
2343                 return ret;
2344         }
2345         else if (m_type == eDVBFrontend::feCable)
2346                 return 2;  // more prio for cable frontends
2347         else if (m_type == eDVBFrontend::feTerrestrial)
2348                 return 1;
2349         return 0;
2350 }
2351
2352 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2353 {
2354         ePyObject Id, Descr, Enabled, IsDVBS2;
2355         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2356                 goto arg_error;
2357         Id = PyTuple_GET_ITEM(obj, 0);
2358         Descr = PyTuple_GET_ITEM(obj, 1);
2359         Enabled = PyTuple_GET_ITEM(obj, 2);
2360         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2361         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2362                 goto arg_error;
2363         strcpy(m_description, PyString_AS_STRING(Descr));
2364         m_slotid = PyInt_AsLong(Id);
2365         m_enabled = Enabled == Py_True;
2366         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2367         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2368                 !!strstr(m_description, "Alps BSBE2") ||
2369                 !!strstr(m_description, "Alps -S") ||
2370                 !!strstr(m_description, "BCM4501");
2371         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2372         eDebug("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2373                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2374         return true;
2375 arg_error:
2376         PyErr_SetString(PyExc_StandardError,
2377                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2378         return false;
2379 }