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