Merge remote branch 'origin/bug_347_adenin_unicable_xml'
[vuplus_dvbapp] / 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         PutToDict(dict, "fec_inner", tmp);
1080
1081         switch (p[0].u.data)
1082         {
1083         default: eDebug("got unsupported system from frontend! report as DVBS!");
1084         case SYS_DVBS: tmp = eDVBFrontendParametersSatellite::System_DVB_S; break;
1085         case SYS_DVBS2:
1086         {
1087                 switch (p[2].u.data)
1088                 {
1089                 default: eDebug("got unsupported rolloff from frontend! report as 0_20!");
1090                 case ROLLOFF_20: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_20; break;
1091                 case ROLLOFF_25: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_25; break;
1092                 case ROLLOFF_35: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_35; break;
1093                 }
1094                 PutToDict(dict, "rolloff", tmp);
1095
1096                 switch (p[3].u.data)
1097                 {
1098                 case PILOT_OFF: tmp = eDVBFrontendParametersSatellite::Pilot_Off; break;
1099                 case PILOT_ON: tmp = eDVBFrontendParametersSatellite::Pilot_On; break;
1100                 case PILOT_AUTO: tmp = eDVBFrontendParametersSatellite::Pilot_Unknown; break;
1101                 }
1102                 PutToDict(dict, "pilot", tmp);
1103
1104                 tmp = eDVBFrontendParametersSatellite::System_DVB_S2; break;
1105         }
1106         }
1107         PutToDict(dict, "system", tmp);
1108
1109         switch (p[1].u.data)
1110         {
1111         default: eDebug("got unsupported modulation from frontend! report as QPSK!");
1112         case QPSK: tmp = eDVBFrontendParametersSatellite::Modulation_QPSK; break;
1113         case PSK_8: tmp = eDVBFrontendParametersSatellite::Modulation_8PSK; break;
1114         }
1115         PutToDict(dict, "modulation", tmp);
1116 }
1117
1118 #else
1119 static void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, long freq_offset, int orb_pos, int polarization)
1120 {
1121         long tmp=0;
1122         int frequency = parm_frequency + freq_offset;
1123         PutToDict(dict, "frequency", frequency);
1124         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
1125         PutToDict(dict, "orbital_position", orb_pos);
1126         PutToDict(dict, "polarization", polarization);
1127
1128         switch((int)parm_u_qpsk_fec_inner)
1129         {
1130         case FEC_1_2: tmp = eDVBFrontendParametersSatellite::FEC_1_2; break;
1131         case FEC_2_3: tmp = eDVBFrontendParametersSatellite::FEC_2_3; break;
1132         case FEC_3_4: tmp = eDVBFrontendParametersSatellite::FEC_3_4; break;
1133         case FEC_5_6: tmp = eDVBFrontendParametersSatellite::FEC_5_6; break;
1134         case FEC_7_8: tmp = eDVBFrontendParametersSatellite::FEC_7_8; break;
1135         case FEC_NONE: tmp = eDVBFrontendParametersSatellite::FEC_None; break;
1136         default:
1137         case FEC_AUTO: tmp = eDVBFrontendParametersSatellite::FEC_Auto; break;
1138 #if HAVE_DVB_API_VERSION >=3
1139         case FEC_S2_8PSK_1_2:
1140         case FEC_S2_QPSK_1_2: tmp = eDVBFrontendParametersSatellite::FEC_1_2; break;
1141         case FEC_S2_8PSK_2_3:
1142         case FEC_S2_QPSK_2_3: tmp = eDVBFrontendParametersSatellite::FEC_2_3; break;
1143         case FEC_S2_8PSK_3_4:
1144         case FEC_S2_QPSK_3_4: tmp = eDVBFrontendParametersSatellite::FEC_3_4; break;
1145         case FEC_S2_8PSK_5_6:
1146         case FEC_S2_QPSK_5_6: tmp = eDVBFrontendParametersSatellite::FEC_5_6; break;
1147         case FEC_S2_8PSK_7_8:
1148         case FEC_S2_QPSK_7_8: tmp = eDVBFrontendParametersSatellite::FEC_7_8; break;
1149         case FEC_S2_8PSK_8_9:
1150         case FEC_S2_QPSK_8_9: tmp = eDVBFrontendParametersSatellite::FEC_8_9; break;
1151         case FEC_S2_8PSK_3_5:
1152         case FEC_S2_QPSK_3_5: tmp = eDVBFrontendParametersSatellite::FEC_3_5; break;
1153         case FEC_S2_8PSK_4_5:
1154         case FEC_S2_QPSK_4_5: tmp = eDVBFrontendParametersSatellite::FEC_4_5; break;
1155         case FEC_S2_8PSK_9_10:
1156         case FEC_S2_QPSK_9_10: tmp = eDVBFrontendParametersSatellite::FEC_9_10; break;
1157 #endif
1158         }
1159         PutToDict(dict, "fec_inner", tmp);
1160 #if HAVE_DVB_API_VERSION >=3
1161         PutToDict(dict, "modulation",
1162                 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ?
1163                         eDVBFrontendParametersSatellite::Modulation_8PSK :
1164                         eDVBFrontendParametersSatellite::Modulation_QPSK );
1165         if (parm_u_qpsk_fec_inner > FEC_AUTO)
1166         {
1167                 switch(parm_inversion & 0xc)
1168                 {
1169                 default: // unknown rolloff
1170                 case 0: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_35; break;
1171                 case 4: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_25; break;
1172                 case 8: tmp = eDVBFrontendParametersSatellite::RollOff_alpha_0_20; break;
1173                 }
1174                 PutToDict(dict, "rolloff", tmp);
1175                 switch(parm_inversion & 0x30)
1176                 {
1177                 case 0: tmp = eDVBFrontendParametersSatellite::Pilot_Off; break;
1178                 case 0x10: tmp = eDVBFrontendParametersSatellite::Pilot_On; break;
1179                 case 0x20: tmp = eDVBFrontendParametersSatellite::Pilot_Unknown; break;
1180                 }
1181                 PutToDict(dict, "pilot", tmp);
1182                 tmp = eDVBFrontendParametersSatellite::System_DVB_S2;
1183         }
1184         else
1185                 tmp = eDVBFrontendParametersSatellite::System_DVB_S;
1186 #else
1187         PutToDict(dict, "modulation", eDVBFrontendParametersSatellite::Modulation_QPSK );
1188         tmp = eDVBFrontendParametersSatellite::System_DVB_S;
1189 #endif
1190         PutToDict(dict, "system", tmp);
1191 }
1192 #endif
1193
1194 static void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1195 {
1196         long tmp=0;
1197 #if HAVE_DVB_API_VERSION < 3
1198         PutToDict(dict, "frequency", parm_frequency);
1199 #else
1200         PutToDict(dict, "frequency", parm_frequency/1000);
1201 #endif
1202         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
1203         switch(parm_u_qam_fec_inner)
1204         {
1205         case FEC_NONE: tmp = eDVBFrontendParametersCable::FEC_None; break;
1206         case FEC_1_2: tmp = eDVBFrontendParametersCable::FEC_1_2; break;
1207         case FEC_2_3: tmp = eDVBFrontendParametersCable::FEC_2_3; break;
1208         case FEC_3_4: tmp = eDVBFrontendParametersCable::FEC_3_4; break;
1209         case FEC_5_6: tmp = eDVBFrontendParametersCable::FEC_5_6; break;
1210         case FEC_7_8: tmp = eDVBFrontendParametersCable::FEC_7_8; break;
1211 #if HAVE_DVB_API_VERSION >= 3
1212         case FEC_8_9: tmp = eDVBFrontendParametersCable::FEC_7_8; break;
1213 #endif
1214         default:
1215         case FEC_AUTO: tmp = eDVBFrontendParametersCable::FEC_Auto; break;
1216         }
1217         PutToDict(dict, "fec_inner", tmp);
1218         switch(parm_u_qam_modulation)
1219         {
1220         case QAM_16: tmp = eDVBFrontendParametersCable::Modulation_QAM16; break;
1221         case QAM_32: tmp = eDVBFrontendParametersCable::Modulation_QAM32; break;
1222         case QAM_64: tmp = eDVBFrontendParametersCable::Modulation_QAM64; break;
1223         case QAM_128: tmp = eDVBFrontendParametersCable::Modulation_QAM128; break;
1224         case QAM_256: tmp = eDVBFrontendParametersCable::Modulation_QAM256; break;
1225         default:
1226         case QAM_AUTO:   tmp = eDVBFrontendParametersCable::Modulation_Auto; break;
1227         }
1228         PutToDict(dict, "modulation", tmp);
1229 }
1230
1231 static void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1232 {
1233         long tmp=0;
1234         PutToDict(dict, "frequency", parm_frequency);
1235         switch (parm_u_ofdm_bandwidth)
1236         {
1237         case BANDWIDTH_8_MHZ: tmp = eDVBFrontendParametersTerrestrial::Bandwidth_8MHz; break;
1238         case BANDWIDTH_7_MHZ: tmp = eDVBFrontendParametersTerrestrial::Bandwidth_7MHz; break;
1239         case BANDWIDTH_6_MHZ: tmp = eDVBFrontendParametersTerrestrial::Bandwidth_6MHz; break;
1240         default:
1241         case BANDWIDTH_AUTO: tmp = eDVBFrontendParametersTerrestrial::Bandwidth_Auto; break;
1242         }
1243         PutToDict(dict, "bandwidth", tmp);
1244         switch (parm_u_ofdm_code_rate_LP)
1245         {
1246         case FEC_1_2: tmp = eDVBFrontendParametersTerrestrial::FEC_1_2; break;
1247         case FEC_2_3: tmp = eDVBFrontendParametersTerrestrial::FEC_2_3; break;
1248         case FEC_3_4: tmp = eDVBFrontendParametersTerrestrial::FEC_3_4; break;
1249         case FEC_5_6: tmp = eDVBFrontendParametersTerrestrial::FEC_5_6; break;
1250         case FEC_7_8: tmp = eDVBFrontendParametersTerrestrial::FEC_7_8; break;
1251         default:
1252         case FEC_AUTO: tmp = eDVBFrontendParametersTerrestrial::FEC_Auto; break;
1253         }
1254         PutToDict(dict, "code_rate_lp", tmp);
1255         switch (parm_u_ofdm_code_rate_HP)
1256         {
1257         case FEC_1_2: tmp = eDVBFrontendParametersTerrestrial::FEC_1_2; break;
1258         case FEC_2_3: tmp = eDVBFrontendParametersTerrestrial::FEC_2_3; break;
1259         case FEC_3_4: tmp = eDVBFrontendParametersTerrestrial::FEC_3_4; break;
1260         case FEC_5_6: tmp = eDVBFrontendParametersTerrestrial::FEC_5_6; break;
1261         case FEC_7_8: tmp = eDVBFrontendParametersTerrestrial::FEC_7_8; break;
1262         default:
1263         case FEC_AUTO: tmp = eDVBFrontendParametersTerrestrial::FEC_Auto; break;
1264         }
1265         PutToDict(dict, "code_rate_hp", tmp);
1266         switch (parm_u_ofdm_constellation)
1267         {
1268         case QPSK: tmp = eDVBFrontendParametersTerrestrial::Modulation_QPSK; break;
1269         case QAM_16: tmp = eDVBFrontendParametersTerrestrial::Modulation_QAM16; break;
1270         case QAM_64: tmp = eDVBFrontendParametersTerrestrial::Modulation_QAM64; break;
1271         default:
1272         case QAM_AUTO: tmp = eDVBFrontendParametersTerrestrial::Modulation_Auto; break;
1273         }
1274         PutToDict(dict, "constellation", tmp);
1275         switch (parm_u_ofdm_transmission_mode)
1276         {
1277         case TRANSMISSION_MODE_2K: tmp = eDVBFrontendParametersTerrestrial::TransmissionMode_2k; break;
1278         case TRANSMISSION_MODE_8K: tmp = eDVBFrontendParametersTerrestrial::TransmissionMode_8k; break;
1279         default:
1280         case TRANSMISSION_MODE_AUTO: tmp = eDVBFrontendParametersTerrestrial::TransmissionMode_Auto; break;
1281         }
1282         PutToDict(dict, "transmission_mode", tmp);
1283         switch (parm_u_ofdm_guard_interval)
1284         {
1285                 case GUARD_INTERVAL_1_32: tmp = eDVBFrontendParametersTerrestrial::GuardInterval_1_32; break;
1286                 case GUARD_INTERVAL_1_16: tmp = eDVBFrontendParametersTerrestrial::GuardInterval_1_16; break;
1287                 case GUARD_INTERVAL_1_8: tmp = eDVBFrontendParametersTerrestrial::GuardInterval_1_8; break;
1288                 case GUARD_INTERVAL_1_4: tmp = eDVBFrontendParametersTerrestrial::GuardInterval_1_4; break;
1289                 default:
1290                 case GUARD_INTERVAL_AUTO: tmp = eDVBFrontendParametersTerrestrial::GuardInterval_Auto; break;
1291         }
1292         PutToDict(dict, "guard_interval", tmp);
1293         switch (parm_u_ofdm_hierarchy_information)
1294         {
1295                 case HIERARCHY_NONE: tmp = eDVBFrontendParametersTerrestrial::Hierarchy_None; break;
1296                 case HIERARCHY_1: tmp = eDVBFrontendParametersTerrestrial::Hierarchy_1; break;
1297                 case HIERARCHY_2: tmp = eDVBFrontendParametersTerrestrial::Hierarchy_2; break;
1298                 case HIERARCHY_4: tmp = eDVBFrontendParametersTerrestrial::Hierarchy_4; break;
1299                 default:
1300                 case HIERARCHY_AUTO: tmp = eDVBFrontendParametersTerrestrial::Hierarchy_Auto; break;
1301         }
1302         PutToDict(dict, "hierarchy_information", tmp);
1303 }
1304
1305 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1306 {
1307         if (dest && PyDict_Check(dest))
1308         {
1309                 const char *tmp = "UNKNOWN";
1310                 switch(m_state)
1311                 {
1312                         case stateIdle:
1313                                 tmp="IDLE";
1314                                 break;
1315                         case stateTuning:
1316                                 tmp="TUNING";
1317                                 break;
1318                         case stateFailed:
1319                                 tmp="FAILED";
1320                                 break;
1321                         case stateLock:
1322                                 tmp="LOCKED";
1323                                 break;
1324                         case stateLostLock:
1325                                 tmp="LOSTLOCK";
1326                                 break;
1327                         default:
1328                                 break;
1329                 }
1330                 PutToDict(dest, "tuner_state", tmp);
1331                 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1332                 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1333                 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1334                 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1335                 int sigQualitydB = readFrontendData(signalQualitydB);
1336                 if (sigQualitydB == 0x12345678) // not support yet
1337                 {
1338                         ePyObject obj=Py_None;
1339                         Py_INCREF(obj);
1340                         PutToDict(dest, "tuner_signal_quality_db", obj);
1341                 }
1342                 else
1343                         PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1344                 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1345         }
1346 }
1347
1348 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1349 {
1350         if (dest && PyDict_Check(dest))
1351         {
1352                 FRONTENDPARAMETERS front;
1353 #if HAVE_DVB_API_VERSION >= 5
1354                 struct dtv_property p[4];
1355                 struct dtv_properties cmdseq;
1356                 cmdseq.props = p;
1357                 cmdseq.num = 4;
1358                 p[0].cmd = DTV_DELIVERY_SYSTEM;
1359                 p[1].cmd = DTV_MODULATION;
1360                 p[2].cmd = DTV_ROLLOFF;
1361                 p[3].cmd = DTV_PILOT;
1362 #endif
1363                 if (m_simulate || m_fd == -1 || original)
1364                         original = true;
1365 #if HAVE_DVB_API_VERSION >= 5
1366                 else if (m_type == feSatellite && // yet just use new api for DVB-S(2) only
1367                         ioctl(m_fd, FE_GET_PROPERTY, &cmdseq)<0)
1368                 {
1369                         eDebug("FE_GET_PROPERTY failed (%m)");
1370                         original = true;
1371                 }
1372 #endif
1373                 else if (ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1374                 {
1375                         eDebug("FE_GET_FRONTEND failed (%m)");
1376                         original = true;
1377                 }
1378                 if (original)
1379                 {
1380                         switch(m_type)
1381                         {
1382                                 case feSatellite:
1383                                         PutSatelliteDataToDict(dest, oparm.sat);
1384                                         break;
1385                                 case feCable:
1386                                         PutCableDataToDict(dest, oparm.cab);
1387                                         break;
1388                                 case feTerrestrial:
1389                                         PutTerrestrialDataToDict(dest, oparm.ter);
1390                                         break;
1391                         }
1392                 }
1393                 else
1394                 {
1395                         FRONTENDPARAMETERS &parm = front;
1396                         long tmp = eDVBFrontendParametersSatellite::Inversion_Unknown;
1397                         switch(parm_inversion & 3)
1398                         {
1399                                 case INVERSION_ON:
1400                                         tmp = eDVBFrontendParametersSatellite::Inversion_On;
1401                                         break;
1402                                 case INVERSION_OFF:
1403                                         tmp = eDVBFrontendParametersSatellite::Inversion_Off;
1404                                 default:
1405                                         break;
1406                         }
1407                         PutToDict(dest, "inversion", tmp);
1408                         switch(m_type)
1409                         {
1410                                 case feSatellite:
1411 #if HAVE_DVB_API_VERSION >= 5
1412                                         fillDictWithSatelliteData(dest, parm, p, m_data[FREQ_OFFSET], oparm.sat.orbital_position, oparm.sat.polarisation);
1413 #else
1414                                         fillDictWithSatelliteData(dest, parm, m_data[FREQ_OFFSET], oparm.sat.orbital_position, oparm.sat.polarisation);
1415 #endif
1416                                         break;
1417                                 case feCable:
1418                                         fillDictWithCableData(dest, parm);
1419                                         break;
1420                                 case feTerrestrial:
1421                                         fillDictWithTerrestrialData(dest, parm);
1422                                         break;
1423                         }
1424                 }
1425         }
1426 }
1427
1428 void eDVBFrontend::getFrontendData(ePyObject dest)
1429 {
1430         if (dest && PyDict_Check(dest))
1431         {
1432                 const char *tmp=0;
1433                 PutToDict(dest, "tuner_number", m_slotid);
1434                 switch(m_type)
1435                 {
1436                         case feSatellite:
1437                                 tmp = "DVB-S";
1438                                 break;
1439                         case feCable:
1440                                 tmp = "DVB-C";
1441                                 break;
1442                         case feTerrestrial:
1443                                 tmp = "DVB-T";
1444                                 break;
1445                         default:
1446                                 tmp = "UNKNOWN";
1447                                 break;
1448                 }
1449                 PutToDict(dest, "tuner_type", tmp);
1450         }
1451 }
1452
1453 #ifndef FP_IOCTL_GET_ID
1454 #define FP_IOCTL_GET_ID 0
1455 #endif
1456 int eDVBFrontend::readInputpower()
1457 {
1458         if (m_simulate)
1459                 return 0;
1460         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1461         char proc_name[64];
1462         char proc_name2[64];
1463         sprintf(proc_name, "/proc/stb/frontend/%d/lnb_sense", m_slotid);
1464         sprintf(proc_name2, "/proc/stb/fp/lnb_sense%d", m_slotid);
1465         FILE *f;
1466         if ((f=fopen(proc_name, "r")) || (f=fopen(proc_name2, "r")))
1467         {
1468                 if (fscanf(f, "%d", &power) != 1)
1469                         eDebug("read %s failed!! (%m)", proc_name);
1470                 else
1471                         eDebug("%s is %d\n", proc_name, power);
1472                 fclose(f);
1473         }
1474         else
1475         {
1476                 // open front prozessor
1477                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1478                 if (fp < 0)
1479                 {
1480                         eDebug("couldn't open fp");
1481                         return -1;
1482                 }
1483                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1484                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1485                 {
1486                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1487                         return -1;
1488                 }
1489                 ::close(fp);
1490         }
1491
1492         return power;
1493 }
1494
1495 bool eDVBFrontend::setSecSequencePos(int steps)
1496 {
1497         eDebugNoSimulate("set sequence pos %d", steps);
1498         if (!steps)
1499                 return false;
1500         while( steps > 0 )
1501         {
1502                 if (m_sec_sequence.current() != m_sec_sequence.end())
1503                         ++m_sec_sequence.current();
1504                 --steps;
1505         }
1506         while( steps < 0 )
1507         {
1508                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1509                         --m_sec_sequence.current();
1510                 ++steps;
1511         }
1512         return true;
1513 }
1514
1515 void eDVBFrontend::tuneLoop()
1516 {
1517         tuneLoopInt();
1518 }
1519
1520 int eDVBFrontend::tuneLoopInt()  // called by m_tuneTimer
1521 {
1522         int delay=-1;
1523         eDVBFrontend *sec_fe = this;
1524         eDVBRegisteredFrontend *regFE = 0;
1525         long tmp = m_data[LINKED_PREV_PTR];
1526         while ( tmp != -1 )
1527         {
1528                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1529                 sec_fe = prev->m_frontend;
1530                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1531                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1532                         int state = sec_fe->m_state;
1533                         // workaround to put the kernel frontend thread into idle state!
1534                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1535                         {
1536                                 sec_fe->closeFrontend(true);
1537                                 state = sec_fe->m_state;
1538                         }
1539                         // sec_fe is closed... we must reopen it here..
1540                         if (state == stateClosed)
1541                         {
1542                                 regFE = prev;
1543                                 prev->inc_use();
1544                         }
1545                 }
1546         }
1547
1548         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1549         {
1550                 long *sec_fe_data = sec_fe->m_data;
1551 //              eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1552                 delay = 0;
1553                 switch (m_sec_sequence.current()->cmd)
1554                 {
1555                         case eSecCommand::SLEEP:
1556                                 delay = m_sec_sequence.current()++->msec;
1557                                 eDebugNoSimulate("[SEC] sleep %dms", delay);
1558                                 break;
1559                         case eSecCommand::GOTO:
1560                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1561                                         ++m_sec_sequence.current();
1562                                 break;
1563                         case eSecCommand::SET_VOLTAGE:
1564                         {
1565                                 int voltage = m_sec_sequence.current()++->voltage;
1566                                 eDebugNoSimulate("[SEC] setVoltage %d", voltage);
1567                                 sec_fe->setVoltage(voltage);
1568                                 break;
1569                         }
1570                         case eSecCommand::IF_VOLTAGE_GOTO:
1571                         {
1572                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1573                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1574                                         break;
1575                                 ++m_sec_sequence.current();
1576                                 break;
1577                         }
1578                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1579                         {
1580                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1581                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1582                                         break;
1583                                 ++m_sec_sequence.current();
1584                                 break;
1585                         }
1586                         case eSecCommand::IF_TONE_GOTO:
1587                         {
1588                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1589                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1590                                         break;
1591                                 ++m_sec_sequence.current();
1592                                 break;
1593                         }
1594                         case eSecCommand::IF_NOT_TONE_GOTO:
1595                         {
1596                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1597                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1598                                         break;
1599                                 ++m_sec_sequence.current();
1600                                 break;
1601                         }
1602                         case eSecCommand::SET_TONE:
1603                                 eDebugNoSimulate("[SEC] setTone %d", m_sec_sequence.current()->tone);
1604                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1605                                 break;
1606                         case eSecCommand::SEND_DISEQC:
1607                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1608                                 eDebugNoSimulateNoNewLine("[SEC] sendDiseqc: ");
1609                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1610                                     eDebugNoSimulateNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1611                                 if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x00", 3))
1612                                         eDebugNoSimulate("(DiSEqC reset)");
1613                                 else if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x03", 3))
1614                                         eDebugNoSimulate("(DiSEqC peripherial power on)");
1615                                 else
1616                                         eDebugNoSimulate("");
1617                                 ++m_sec_sequence.current();
1618                                 break;
1619                         case eSecCommand::SEND_TONEBURST:
1620                                 eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1621                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1622                                 break;
1623                         case eSecCommand::SET_FRONTEND:
1624                         {
1625                                 int enableEvents = (m_sec_sequence.current()++)->val;
1626                                 eDebugNoSimulate("[SEC] setFrontend %d", enableEvents);
1627                                 setFrontend(enableEvents);
1628                                 break;
1629                         }
1630                         case eSecCommand::START_TUNE_TIMEOUT:
1631                         {
1632                                 int tuneTimeout = m_sec_sequence.current()->timeout;
1633                                 eDebugNoSimulate("[SEC] startTuneTimeout %d", tuneTimeout);
1634                                 if (!m_simulate)
1635                                         m_timeout->start(tuneTimeout, 1);
1636                                 ++m_sec_sequence.current();
1637                                 break;
1638                         }
1639                         case eSecCommand::SET_TIMEOUT:
1640                                 m_timeoutCount = m_sec_sequence.current()++->val;
1641                                 eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
1642                                 break;
1643                         case eSecCommand::IF_TIMEOUT_GOTO:
1644                                 if (!m_timeoutCount)
1645                                 {
1646                                         eDebugNoSimulate("[SEC] rotor timout");
1647                                         setSecSequencePos(m_sec_sequence.current()->steps);
1648                                 }
1649                                 else
1650                                         ++m_sec_sequence.current();
1651                                 break;
1652                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1653                         {
1654                                 int idx = m_sec_sequence.current()++->val;
1655                                 if ( idx == 0 || idx == 1 )
1656                                 {
1657                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1658                                         eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1659                                 }
1660                                 else
1661                                         eDebugNoSimulate("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1662                                 break;
1663                         }
1664                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1665                         {
1666                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1667                                 int idx = compare.val;
1668                                 if ( !m_simulate && (idx == 0 || idx == 1) )
1669                                 {
1670                                         int idle = sec_fe->readInputpower();
1671                                         int diff = abs(idle-m_idleInputpower[idx]);
1672                                         if ( diff > 0)
1673                                         {
1674                                                 eDebugNoSimulate("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1675                                                 setSecSequencePos(compare.steps);
1676                                                 break;
1677                                         }
1678                                 }
1679                                 ++m_sec_sequence.current();
1680                                 break;
1681                         }
1682                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1683                         {
1684                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1685                                 if (m_simulate)
1686                                 {
1687                                         setSecSequencePos(cmd.steps);
1688                                         break;
1689                                 }
1690                                 int signal = 0;
1691                                 int isLocked = readFrontendData(locked);
1692                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1693                                 --m_timeoutCount;
1694                                 if (!m_timeoutCount && m_retryCount > 0)
1695                                         --m_retryCount;
1696                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 40) || !cmd.lastSignal))
1697                                 {
1698                                         if (cmd.lastSignal)
1699                                                 eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1700                                         else
1701                                         {
1702                                                 eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
1703                                                 if (!cmd.okcount)
1704                                                         cmd.lastSignal = signal;
1705                                         }
1706                                         ++cmd.okcount;
1707                                         if (cmd.okcount > 4)
1708                                         {
1709                                                 eDebugNoSimulate("ok > 4 .. goto %d\n", cmd.steps);
1710                                                 setSecSequencePos(cmd.steps);
1711                                                 m_state = stateLock;
1712                                                 m_stateChanged(this);
1713                                                 feEvent(-1); // flush events
1714                                                 m_sn->start();
1715                                                 break;
1716                                         }
1717                                 }
1718                                 else
1719                                 {
1720                                         if (isLocked)
1721                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1722                                         else
1723                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1724                                         cmd.okcount=0;
1725                                         cmd.lastSignal=0;
1726                                 }
1727                                 ++m_sec_sequence.current();
1728                                 break;
1729                         }
1730                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1731                                 m_runningInputpower = sec_fe->readInputpower();
1732                                 eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
1733                                 ++m_sec_sequence.current();
1734                                 break;
1735                         case eSecCommand::SET_ROTOR_MOVING:
1736                                 if (!m_simulate)
1737                                         m_sec->setRotorMoving(m_slotid, true);
1738                                 ++m_sec_sequence.current();
1739                                 break;
1740                         case eSecCommand::SET_ROTOR_STOPPED:
1741                                 if (!m_simulate)
1742                                         m_sec->setRotorMoving(m_slotid, false);
1743                                 ++m_sec_sequence.current();
1744                                 break;
1745                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1746                         {
1747                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1748                                 if (m_simulate)
1749                                 {
1750                                         setSecSequencePos(cmd.steps);
1751                                         break;
1752                                 }
1753                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1754                                 const char *txt = cmd.direction ? "running" : "stopped";
1755                                 --m_timeoutCount;
1756                                 if (!m_timeoutCount && m_retryCount > 0)
1757                                         --m_retryCount;
1758                                 eDebugNoSimulate("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1759                                         txt,
1760                                         m_runningInputpower,
1761                                         idleInputpower,
1762                                         cmd.deltaA);
1763                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1764                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1765                                 {
1766                                         ++cmd.okcount;
1767                                         eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1768                                         if ( cmd.okcount > 6 )
1769                                         {
1770                                                 eDebugNoSimulate("[SEC] rotor is %s", txt);
1771                                                 if (setSecSequencePos(cmd.steps))
1772                                                         break;
1773                                         }
1774                                 }
1775                                 else
1776                                 {
1777                                         eDebugNoSimulate("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1778                                         cmd.okcount=0;
1779                                 }
1780                                 ++m_sec_sequence.current();
1781                                 break;
1782                         }
1783                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1784                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1785                                         setSecSequencePos(m_sec_sequence.current()->steps);
1786                                 else
1787                                         ++m_sec_sequence.current();
1788                                 break;
1789                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1790                                 eDebugNoSimulate("[SEC] invalidate current switch params");
1791                                 sec_fe_data[CSW] = -1;
1792                                 sec_fe_data[UCSW] = -1;
1793                                 sec_fe_data[TONEBURST] = -1;
1794                                 ++m_sec_sequence.current();
1795                                 break;
1796                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1797                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1798                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1799                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1800                                 eDebugNoSimulate("[SEC] update current switch params");
1801                                 ++m_sec_sequence.current();
1802                                 break;
1803                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1804                                 eDebugNoSimulate("[SEC] invalidate current rotorparams");
1805                                 sec_fe_data[ROTOR_CMD] = -1;
1806                                 sec_fe_data[ROTOR_POS] = -1;
1807                                 ++m_sec_sequence.current();
1808                                 break;
1809                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1810                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1811                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1812                                 eDebugNoSimulate("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1813                                 ++m_sec_sequence.current();
1814                                 break;
1815                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1816                                 m_retryCount = m_sec_sequence.current()++->val;
1817                                 eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
1818                                 break;
1819                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1820                                 if (!m_retryCount)
1821                                 {
1822                                         eDebugNoSimulate("[SEC] no more rotor retrys");
1823                                         setSecSequencePos(m_sec_sequence.current()->steps);
1824                                 }
1825                                 else
1826                                         ++m_sec_sequence.current();
1827                                 break;
1828                         case eSecCommand::SET_POWER_LIMITING_MODE:
1829                         {
1830                                 if (!m_simulate)
1831                                 {
1832                                         char proc_name[64];
1833                                         sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1834                                         FILE *f=fopen(proc_name, "w");
1835                                         if (f) // new interface exist?
1836                                         {
1837                                                 bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1838                                                 if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1839                                                         eDebugNoSimulate("write %s failed!! (%m)", proc_name);
1840                                                 else
1841                                                         eDebugNoSimulate("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1842                                                 fclose(f);
1843                                         }
1844                                         else if (sec_fe->m_need_rotor_workaround)
1845                                         {
1846                                                 char dev[16];
1847                                                 int slotid = sec_fe->m_slotid;
1848                                                 // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1849                                                 if (slotid < 2)
1850                                                         sprintf(dev, "/dev/i2c/%d", slotid);
1851                                                 else if (slotid == 2)
1852                                                         sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1853                                                 else if (slotid == 3)
1854                                                         sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1855                                                 int fd = ::open(dev, O_RDWR);
1856
1857                                                 unsigned char data[2];
1858                                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1859                                                 if(::read(fd, data, 1) != 1)
1860                                                         eDebugNoSimulate("[SEC] error read lnbp (%m)");
1861                                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1862                                                 {
1863                                                         data[0] |= 0x80;  // enable static current limiting
1864                                                         eDebugNoSimulate("[SEC] set static current limiting");
1865                                                 }
1866                                                 else
1867                                                 {
1868                                                         data[0] &= ~0x80;  // enable dynamic current limiting
1869                                                         eDebugNoSimulate("[SEC] set dynamic current limiting");
1870                                                 }
1871                                                 if(::write(fd, data, 1) != 1)
1872                                                         eDebugNoSimulate("[SEC] error write lnbp (%m)");
1873                                                 ::close(fd);
1874                                         }
1875                                 }
1876                                 ++m_sec_sequence.current();
1877                                 break;
1878                         }
1879                         case eSecCommand::DELAYED_CLOSE_FRONTEND:
1880                         {
1881                                 eDebugNoSimulate("[SEC] delayed close frontend");
1882                                 closeFrontend(false, true);
1883                                 ++m_sec_sequence.current();
1884                                 break;
1885                         }
1886                         default:
1887                                 eDebugNoSimulate("[SEC] unhandled sec command %d",
1888                                         ++m_sec_sequence.current()->cmd);
1889                                 ++m_sec_sequence.current();
1890                 }
1891                 if (!m_simulate)
1892                         m_tuneTimer->start(delay,true);
1893         }
1894         if (regFE)
1895                 regFE->dec_use();
1896         if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
1897                 tuneLoop();
1898         return delay;
1899 }
1900
1901 void eDVBFrontend::setFrontend(bool recvEvents)
1902 {
1903         if (!m_simulate)
1904         {
1905                 eDebug("setting frontend %d", m_dvbid);
1906                 if (recvEvents)
1907                         m_sn->start();
1908                 feEvent(-1); // flush events
1909 #if HAVE_DVB_API_VERSION >= 5
1910                 if (m_type == iDVBFrontend::feSatellite)
1911                 {
1912                         fe_rolloff_t rolloff = ROLLOFF_35;
1913                         fe_pilot_t pilot = PILOT_OFF;
1914                         fe_modulation_t modulation = QPSK;
1915                         fe_delivery_system_t system = SYS_DVBS;
1916                         switch(oparm.sat.system)
1917                         {
1918                         case eDVBFrontendParametersSatellite::System_DVB_S: system = SYS_DVBS; break;
1919                         case eDVBFrontendParametersSatellite::System_DVB_S2: system = SYS_DVBS2; break;
1920                         };
1921                         switch(oparm.sat.modulation)
1922                         {
1923                         case eDVBFrontendParametersSatellite::Modulation_QPSK: modulation = QPSK; break;
1924                         case eDVBFrontendParametersSatellite::Modulation_8PSK: modulation = PSK_8; break;
1925                         case eDVBFrontendParametersSatellite::Modulation_QAM16: modulation = QAM_16; break;
1926                         };
1927                         switch(oparm.sat.pilot)
1928                         {
1929                         case eDVBFrontendParametersSatellite::Pilot_Off: pilot = PILOT_OFF; break;
1930                         case eDVBFrontendParametersSatellite::Pilot_On: pilot = PILOT_ON; break;
1931                         case eDVBFrontendParametersSatellite::Pilot_Unknown: pilot = PILOT_AUTO; break;
1932                         };
1933                         switch(oparm.sat.rolloff)
1934                         {
1935                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_20: rolloff = ROLLOFF_20; break;
1936                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_25: rolloff = ROLLOFF_25; break;
1937                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_35: rolloff = ROLLOFF_35; break;
1938                         };
1939                         struct dtv_property p[10];
1940                         struct dtv_properties cmdseq;
1941                         cmdseq.props = p;
1942                         p[0].cmd = DTV_CLEAR;
1943                         p[1].cmd = DTV_DELIVERY_SYSTEM, p[1].u.data = system;
1944                         p[2].cmd = DTV_FREQUENCY,       p[2].u.data = parm_frequency;
1945                         p[3].cmd = DTV_MODULATION,      p[3].u.data = modulation;
1946                         p[4].cmd = DTV_SYMBOL_RATE,     p[4].u.data = parm_u_qpsk_symbol_rate;
1947                         p[5].cmd = DTV_INNER_FEC,       p[5].u.data = parm_u_qpsk_fec_inner;
1948                         p[6].cmd = DTV_INVERSION,       p[6].u.data = parm_inversion;
1949                         if (system == SYS_DVBS2)
1950                         {
1951                                 p[7].cmd = DTV_ROLLOFF,         p[7].u.data = rolloff;
1952                                 p[8].cmd = DTV_PILOT,           p[8].u.data = pilot;
1953                                 p[9].cmd = DTV_TUNE;
1954                                 cmdseq.num = 10;
1955                         }
1956                         else
1957                         {
1958                                 p[7].cmd = DTV_TUNE;
1959                                 cmdseq.num = 8;
1960                         }
1961                         if (ioctl(m_fd, FE_SET_PROPERTY, &cmdseq) == -1)
1962                         {
1963                                 perror("FE_SET_PROPERTY failed");
1964                                 return;
1965                         }
1966                 }
1967                 else
1968 #endif
1969                 {
1970                         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1971                         {
1972                                 perror("FE_SET_FRONTEND failed");
1973                                 return;
1974                         }
1975                 }
1976         }
1977 }
1978
1979 RESULT eDVBFrontend::getFrontendType(int &t)
1980 {
1981         if (m_type == -1)
1982                 return -ENODEV;
1983         t = m_type;
1984         return 0;
1985 }
1986
1987 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1988 {
1989         int res;
1990         if (!m_sec)
1991         {
1992                 eWarning("no SEC module active!");
1993                 return -ENOENT;
1994         }
1995         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1996         if (!res)
1997         {
1998 #if HAVE_DVB_API_VERSION >= 3
1999                 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",
2000                         feparm.system,
2001                         feparm.frequency,
2002                         feparm.polarisation,
2003                         feparm.symbol_rate,
2004                         feparm.inversion,
2005                         feparm.fec,
2006                         feparm.orbital_position,
2007                         feparm.system,
2008                         feparm.modulation,
2009                         feparm.pilot,
2010                         feparm.rolloff);
2011 #else
2012                 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
2013                         feparm.system,
2014                         feparm.frequency,
2015                         feparm.polarisation,
2016                         feparm.symbol_rate,
2017                         feparm.inversion,
2018                         feparm.fec,
2019                         feparm.orbital_position);
2020 #endif
2021                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
2022                 switch (feparm.inversion)
2023                 {
2024                         case eDVBFrontendParametersSatellite::Inversion_On:
2025                                 parm_inversion = INVERSION_ON;
2026                                 break;
2027                         case eDVBFrontendParametersSatellite::Inversion_Off:
2028                                 parm_inversion = INVERSION_OFF;
2029                                 break;
2030                         default:
2031                         case eDVBFrontendParametersSatellite::Inversion_Unknown:
2032                                 parm_inversion = INVERSION_AUTO;
2033                                 break;
2034                 }
2035                 if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S)
2036                 {
2037                         switch (feparm.fec)
2038                         {
2039                                 case eDVBFrontendParametersSatellite::FEC_None:
2040                                         parm_u_qpsk_fec_inner = FEC_NONE;
2041                                         break;
2042                                 case eDVBFrontendParametersSatellite::FEC_1_2:
2043                                         parm_u_qpsk_fec_inner = FEC_1_2;
2044                                         break;
2045                                 case eDVBFrontendParametersSatellite::FEC_2_3:
2046                                         parm_u_qpsk_fec_inner = FEC_2_3;
2047                                         break;
2048                                 case eDVBFrontendParametersSatellite::FEC_3_4:
2049                                         parm_u_qpsk_fec_inner = FEC_3_4;
2050                                         break;
2051                                 case eDVBFrontendParametersSatellite::FEC_5_6:
2052                                         parm_u_qpsk_fec_inner = FEC_5_6;
2053                                         break;
2054                                 case eDVBFrontendParametersSatellite::FEC_7_8:
2055                                         parm_u_qpsk_fec_inner = FEC_7_8;
2056                                         break;
2057                                 default:
2058                                         eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
2059                                 case eDVBFrontendParametersSatellite::FEC_Auto:
2060                                         parm_u_qpsk_fec_inner = FEC_AUTO;
2061                                         break;
2062                         }
2063                 }
2064 #if HAVE_DVB_API_VERSION >= 3
2065                 else // DVB_S2
2066                 {
2067                         switch (feparm.fec)
2068                         {
2069                                 case eDVBFrontendParametersSatellite::FEC_1_2:
2070                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
2071                                         break;
2072                                 case eDVBFrontendParametersSatellite::FEC_2_3:
2073                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
2074                                         break;
2075                                 case eDVBFrontendParametersSatellite::FEC_3_4:
2076                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
2077                                         break;
2078                                 case eDVBFrontendParametersSatellite::FEC_3_5:
2079                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
2080                                         break;
2081                                 case eDVBFrontendParametersSatellite::FEC_4_5:
2082                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
2083                                         break;
2084                                 case eDVBFrontendParametersSatellite::FEC_5_6:
2085                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
2086                                         break;
2087                                 case eDVBFrontendParametersSatellite::FEC_7_8:
2088                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
2089                                         break;
2090                                 case eDVBFrontendParametersSatellite::FEC_8_9:
2091                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
2092                                         break;
2093                                 case eDVBFrontendParametersSatellite::FEC_9_10:
2094                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
2095                                         break;
2096                                 default:
2097                                         eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
2098                                         return -EINVAL;
2099                         }
2100 #if HAVE_DVB_API_VERSION < 5
2101                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
2102                         parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
2103                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation_8PSK) 
2104                         {
2105                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
2106                                 // 8PSK fec driver values are decimal 9 bigger
2107                         }
2108 #endif
2109                 }
2110 #endif
2111                 // FIXME !!! get frequency range from tuner
2112                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
2113                 {
2114                         eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
2115                         return -EINVAL;
2116                 }
2117                 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
2118         }
2119         oparm.sat = feparm;
2120         return res;
2121 }
2122
2123 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
2124 {
2125 #if HAVE_DVB_API_VERSION < 3
2126         parm_frequency = feparm.frequency;
2127 #else
2128         parm_frequency = feparm.frequency * 1000;
2129 #endif
2130         parm_u_qam_symbol_rate = feparm.symbol_rate;
2131         switch (feparm.modulation)
2132         {
2133         case eDVBFrontendParametersCable::Modulation_QAM16:
2134                 parm_u_qam_modulation = QAM_16;
2135                 break;
2136         case eDVBFrontendParametersCable::Modulation_QAM32:
2137                 parm_u_qam_modulation = QAM_32;
2138                 break;
2139         case eDVBFrontendParametersCable::Modulation_QAM64:
2140                 parm_u_qam_modulation = QAM_64;
2141                 break;
2142         case eDVBFrontendParametersCable::Modulation_QAM128:
2143                 parm_u_qam_modulation = QAM_128;
2144                 break;
2145         case eDVBFrontendParametersCable::Modulation_QAM256:
2146                 parm_u_qam_modulation = QAM_256;
2147                 break;
2148         default:
2149         case eDVBFrontendParametersCable::Modulation_Auto:
2150                 parm_u_qam_modulation = QAM_AUTO;
2151                 break;
2152         }
2153         switch (feparm.inversion)
2154         {
2155         case eDVBFrontendParametersCable::Inversion_On:
2156                 parm_inversion = INVERSION_ON;
2157                 break;
2158         case eDVBFrontendParametersCable::Inversion_Off:
2159                 parm_inversion = INVERSION_OFF;
2160                 break;
2161         default:
2162         case eDVBFrontendParametersCable::Inversion_Unknown:
2163                 parm_inversion = INVERSION_AUTO;
2164                 break;
2165         }
2166         switch (feparm.fec_inner)
2167         {
2168         case eDVBFrontendParametersCable::FEC_None:
2169                 parm_u_qam_fec_inner = FEC_NONE;
2170                 break;
2171         case eDVBFrontendParametersCable::FEC_1_2:
2172                 parm_u_qam_fec_inner = FEC_1_2;
2173                 break;
2174         case eDVBFrontendParametersCable::FEC_2_3:
2175                 parm_u_qam_fec_inner = FEC_2_3;
2176                 break;
2177         case eDVBFrontendParametersCable::FEC_3_4:
2178                 parm_u_qam_fec_inner = FEC_3_4;
2179                 break;
2180         case eDVBFrontendParametersCable::FEC_5_6:
2181                 parm_u_qam_fec_inner = FEC_5_6;
2182                 break;
2183         case eDVBFrontendParametersCable::FEC_7_8:
2184                 parm_u_qam_fec_inner = FEC_7_8;
2185                 break;
2186 #if HAVE_DVB_API_VERSION >= 3
2187         case eDVBFrontendParametersCable::FEC_8_9:
2188                 parm_u_qam_fec_inner = FEC_8_9;
2189                 break;
2190 #endif
2191         default:
2192         case eDVBFrontendParametersCable::FEC_Auto:
2193                 parm_u_qam_fec_inner = FEC_AUTO;
2194                 break;
2195         }
2196         eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
2197                 parm_frequency/1000,
2198                 parm_u_qam_symbol_rate,
2199                 parm_u_qam_fec_inner,
2200                 parm_u_qam_modulation,
2201                 parm_inversion);
2202         oparm.cab = feparm;
2203         return 0;
2204 }
2205
2206 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
2207 {
2208         parm_frequency = feparm.frequency;
2209
2210         switch (feparm.bandwidth)
2211         {
2212         case eDVBFrontendParametersTerrestrial::Bandwidth_8MHz:
2213                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
2214                 break;
2215         case eDVBFrontendParametersTerrestrial::Bandwidth_7MHz:
2216                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
2217                 break;
2218         case eDVBFrontendParametersTerrestrial::Bandwidth_6MHz:
2219                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2220                 break;
2221         default:
2222         case eDVBFrontendParametersTerrestrial::Bandwidth_Auto:
2223                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2224                 break;
2225         }
2226         switch (feparm.code_rate_LP)
2227         {
2228         case eDVBFrontendParametersTerrestrial::FEC_1_2:
2229                 parm_u_ofdm_code_rate_LP = FEC_1_2;
2230                 break;
2231         case eDVBFrontendParametersTerrestrial::FEC_2_3:
2232                 parm_u_ofdm_code_rate_LP = FEC_2_3;
2233                 break;
2234         case eDVBFrontendParametersTerrestrial::FEC_3_4:
2235                 parm_u_ofdm_code_rate_LP = FEC_3_4;
2236                 break;
2237         case eDVBFrontendParametersTerrestrial::FEC_5_6:
2238                 parm_u_ofdm_code_rate_LP = FEC_5_6;
2239                 break;
2240         case eDVBFrontendParametersTerrestrial::FEC_7_8:
2241                 parm_u_ofdm_code_rate_LP = FEC_7_8;
2242                 break;
2243         default:
2244         case eDVBFrontendParametersTerrestrial::FEC_Auto:
2245                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2246                 break;
2247         }
2248         switch (feparm.code_rate_HP)
2249         {
2250         case eDVBFrontendParametersTerrestrial::FEC_1_2:
2251                 parm_u_ofdm_code_rate_HP = FEC_1_2;
2252                 break;
2253         case eDVBFrontendParametersTerrestrial::FEC_2_3:
2254                 parm_u_ofdm_code_rate_HP = FEC_2_3;
2255                 break;
2256         case eDVBFrontendParametersTerrestrial::FEC_3_4:
2257                 parm_u_ofdm_code_rate_HP = FEC_3_4;
2258                 break;
2259         case eDVBFrontendParametersTerrestrial::FEC_5_6:
2260                 parm_u_ofdm_code_rate_HP = FEC_5_6;
2261                 break;
2262         case eDVBFrontendParametersTerrestrial::FEC_7_8:
2263                 parm_u_ofdm_code_rate_HP = FEC_7_8;
2264                 break;
2265         default:
2266         case eDVBFrontendParametersTerrestrial::FEC_Auto:
2267                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2268                 break;
2269         }
2270         switch (feparm.modulation)
2271         {
2272         case eDVBFrontendParametersTerrestrial::Modulation_QPSK:
2273                 parm_u_ofdm_constellation = QPSK;
2274                 break;
2275         case eDVBFrontendParametersTerrestrial::Modulation_QAM16:
2276                 parm_u_ofdm_constellation = QAM_16;
2277                 break;
2278         case eDVBFrontendParametersTerrestrial::Modulation_QAM64:
2279                 parm_u_ofdm_constellation = QAM_64;
2280                 break;
2281         default:
2282         case eDVBFrontendParametersTerrestrial::Modulation_Auto:
2283                 parm_u_ofdm_constellation = QAM_AUTO;
2284                 break;
2285         }
2286         switch (feparm.transmission_mode)
2287         {
2288         case eDVBFrontendParametersTerrestrial::TransmissionMode_2k:
2289                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2290                 break;
2291         case eDVBFrontendParametersTerrestrial::TransmissionMode_8k:
2292                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2293                 break;
2294         default:
2295         case eDVBFrontendParametersTerrestrial::TransmissionMode_Auto:
2296                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2297                 break;
2298         }
2299         switch (feparm.guard_interval)
2300         {
2301                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_32:
2302                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2303                         break;
2304                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_16:
2305                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2306                         break;
2307                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_8:
2308                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2309                         break;
2310                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_4:
2311                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2312                         break;
2313                 default:
2314                 case eDVBFrontendParametersTerrestrial::GuardInterval_Auto:
2315                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2316                         break;
2317         }
2318         switch (feparm.hierarchy)
2319         {
2320                 case eDVBFrontendParametersTerrestrial::Hierarchy_None:
2321                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2322                         break;
2323                 case eDVBFrontendParametersTerrestrial::Hierarchy_1:
2324                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2325                         break;
2326                 case eDVBFrontendParametersTerrestrial::Hierarchy_2:
2327                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2328                         break;
2329                 case eDVBFrontendParametersTerrestrial::Hierarchy_4:
2330                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2331                         break;
2332                 default:
2333                 case eDVBFrontendParametersTerrestrial::Hierarchy_Auto:
2334                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2335                         break;
2336         }
2337         switch (feparm.inversion)
2338         {
2339         case eDVBFrontendParametersTerrestrial::Inversion_On:
2340                 parm_inversion = INVERSION_ON;
2341                 break;
2342         case eDVBFrontendParametersTerrestrial::Inversion_Off:
2343                 parm_inversion = INVERSION_OFF;
2344                 break;
2345         default:
2346         case eDVBFrontendParametersTerrestrial::Inversion_Unknown:
2347                 parm_inversion = INVERSION_AUTO;
2348                 break;
2349         }
2350         oparm.ter = feparm;
2351         return 0;
2352 }
2353
2354 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2355 {
2356         unsigned int timeout = 5000;
2357         eDebugNoSimulate("(%d)tune", m_dvbid);
2358
2359         m_timeout->stop();
2360
2361         int res=0;
2362
2363         if (!m_sn && !m_simulate)
2364         {
2365                 eDebug("no frontend device opened... do not try to tune !!!");
2366                 res = -ENODEV;
2367                 goto tune_error;
2368         }
2369
2370         if (m_type == -1)
2371         {
2372                 res = -ENODEV;
2373                 goto tune_error;
2374         }
2375
2376         if (!m_simulate)
2377                 m_sn->stop();
2378
2379         m_sec_sequence.clear();
2380
2381         where.calcLockTimeout(timeout);
2382
2383         switch (m_type)
2384         {
2385         case feSatellite:
2386         {
2387                 eDVBFrontendParametersSatellite feparm;
2388                 if (where.getDVBS(feparm))
2389                 {
2390                         eDebug("no dvbs data!");
2391                         res = -EINVAL;
2392                         goto tune_error;
2393                 }
2394                 if (m_rotor_mode != feparm.no_rotor_command_on_tune && !feparm.no_rotor_command_on_tune)
2395                 {
2396                         eDVBFrontend *sec_fe = this;
2397                         long tmp = m_data[LINKED_PREV_PTR];
2398                         while (tmp != -1)
2399                         {
2400                                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
2401                                 sec_fe = linked_fe->m_frontend;
2402                                 sec_fe->getData(LINKED_NEXT_PTR, tmp);
2403                         }
2404                         eDebug("(fe%d) reset diseqc after leave rotor mode!", m_dvbid);
2405                         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
2406                 }
2407                 m_rotor_mode = feparm.no_rotor_command_on_tune;
2408                 if (!m_simulate)
2409                         m_sec->setRotorMoving(m_slotid, false);
2410                 res=prepare_sat(feparm, timeout);
2411                 if (res)
2412                         goto tune_error;
2413
2414                 break;
2415         }
2416         case feCable:
2417         {
2418                 eDVBFrontendParametersCable feparm;
2419                 if (where.getDVBC(feparm))
2420                 {
2421                         res = -EINVAL;
2422                         goto tune_error;
2423                 }
2424                 res=prepare_cable(feparm);
2425                 if (res)
2426                         goto tune_error;
2427
2428                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2429                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND, 1) );
2430                 break;
2431         }
2432         case feTerrestrial:
2433         {
2434                 eDVBFrontendParametersTerrestrial feparm;
2435                 if (where.getDVBT(feparm))
2436                 {
2437                         eDebug("no -T data");
2438                         res = -EINVAL;
2439                         goto tune_error;
2440                 }
2441                 res=prepare_terrestrial(feparm);
2442                 if (res)
2443                         goto tune_error;
2444
2445                 std::string enable_5V;
2446                 char configStr[255];
2447                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2448                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2449                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2450                 if (enable_5V == "True")
2451                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2452                 else
2453                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2454                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND, 1) );
2455
2456                 break;
2457         }
2458         }
2459
2460         m_sec_sequence.current() = m_sec_sequence.begin();
2461
2462         if (!m_simulate)
2463         {
2464                 m_tuneTimer->start(0,true);
2465                 m_tuning = 1;
2466                 if (m_state != stateTuning)
2467                 {
2468                         m_state = stateTuning;
2469                         m_stateChanged(this);
2470                 }
2471         }
2472         else
2473                 tuneLoop();
2474
2475         return res;
2476
2477 tune_error:
2478         m_tuneTimer->stop();
2479         return res;
2480 }
2481
2482 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2483 {
2484         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2485         return 0;
2486 }
2487
2488 RESULT eDVBFrontend::setVoltage(int voltage)
2489 {
2490         if (m_type == feCable)
2491                 return -1;
2492 #if HAVE_DVB_API_VERSION < 3
2493         secVoltage vlt;
2494 #else
2495         bool increased=false;
2496         fe_sec_voltage_t vlt;
2497 #endif
2498         m_data[CUR_VOLTAGE]=voltage;
2499         switch (voltage)
2500         {
2501         case voltageOff:
2502                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2503                 vlt = SEC_VOLTAGE_OFF;
2504                 break;
2505         case voltage13_5:
2506 #if HAVE_DVB_API_VERSION < 3
2507                 vlt = SEC_VOLTAGE_13_5;
2508                 break;
2509 #else
2510                 increased = true;
2511 #endif
2512         case voltage13:
2513                 vlt = SEC_VOLTAGE_13;
2514                 break;
2515         case voltage18_5:
2516 #if HAVE_DVB_API_VERSION < 3
2517                 vlt = SEC_VOLTAGE_18_5;
2518                 break;
2519 #else
2520                 increased = true;
2521 #endif
2522         case voltage18:
2523                 vlt = SEC_VOLTAGE_18;
2524                 break;
2525         default:
2526                 return -ENODEV;
2527         }
2528         if (m_simulate)
2529                 return 0;
2530 #if HAVE_DVB_API_VERSION < 3
2531         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2532 #else
2533         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2534                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2535         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2536 #endif
2537 }
2538
2539 RESULT eDVBFrontend::getState(int &state)
2540 {
2541         state = m_state;
2542         return 0;
2543 }
2544
2545 RESULT eDVBFrontend::setTone(int t)
2546 {
2547         if (m_type != feSatellite)
2548                 return -1;
2549 #if HAVE_DVB_API_VERSION < 3
2550         secToneMode_t tone;
2551 #else
2552         fe_sec_tone_mode_t tone;
2553 #endif
2554         m_data[CUR_TONE]=t;
2555         switch (t)
2556         {
2557         case toneOn:
2558                 tone = SEC_TONE_ON;
2559                 break;
2560         case toneOff:
2561                 tone = SEC_TONE_OFF;
2562                 break;
2563         default:
2564                 return -ENODEV;
2565         }
2566         if (m_simulate)
2567                 return 0;
2568 #if HAVE_DVB_API_VERSION < 3    
2569         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2570 #else   
2571         return ::ioctl(m_fd, FE_SET_TONE, tone);
2572 #endif
2573 }
2574
2575 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2576         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2577 #endif
2578
2579 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2580 {
2581         if (m_simulate)
2582                 return 0;
2583 #if HAVE_DVB_API_VERSION < 3
2584         struct secCommand cmd;
2585         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2586         cmd.u.diseqc.cmdtype = diseqc.data[0];
2587         cmd.u.diseqc.addr = diseqc.data[1];
2588         cmd.u.diseqc.cmd = diseqc.data[2];
2589         cmd.u.diseqc.numParams = diseqc.len-3;
2590         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2591         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2592 #else
2593         struct dvb_diseqc_master_cmd cmd;
2594         memcpy(cmd.msg, diseqc.data, diseqc.len);
2595         cmd.msg_len = diseqc.len;
2596         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2597 #endif
2598                 return -EINVAL;
2599         return 0;
2600 }
2601
2602 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2603         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2604 #endif
2605 RESULT eDVBFrontend::sendToneburst(int burst)
2606 {
2607         if (m_simulate)
2608                 return 0;
2609 #if HAVE_DVB_API_VERSION < 3
2610         secMiniCmd cmd = SEC_MINI_NONE;
2611 #else
2612         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2613 #endif
2614         if ( burst == eDVBSatelliteDiseqcParameters::A )
2615                 cmd = SEC_MINI_A;
2616         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2617                 cmd = SEC_MINI_B;
2618 #if HAVE_DVB_API_VERSION < 3
2619         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2620                 return -EINVAL;
2621 #else
2622         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2623                 return -EINVAL;
2624 #endif
2625         return 0;
2626 }
2627
2628 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2629 {
2630         m_sec = sec;
2631         return 0;
2632 }
2633
2634 RESULT eDVBFrontend::setSecSequence(eSecCommandList &list)
2635 {
2636         if (m_data[SATCR] != -1 && m_sec_sequence.current() != m_sec_sequence.end())
2637                 m_sec_sequence.push_back(list);
2638         else
2639                 m_sec_sequence = list;
2640         return 0;
2641 }
2642
2643 RESULT eDVBFrontend::getData(int num, long &data)
2644 {
2645         if ( num < NUM_DATA_ENTRIES )
2646         {
2647                 data = m_data[num];
2648                 return 0;
2649         }
2650         return -EINVAL;
2651 }
2652
2653 RESULT eDVBFrontend::setData(int num, long val)
2654 {
2655         if ( num < NUM_DATA_ENTRIES )
2656         {
2657                 m_data[num] = val;
2658                 return 0;
2659         }
2660         return -EINVAL;
2661 }
2662
2663 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2664 {
2665         int type;
2666         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2667                 return 0;
2668         if (m_type == eDVBFrontend::feSatellite)
2669         {
2670                 ASSERT(m_sec);
2671                 eDVBFrontendParametersSatellite sat_parm;
2672                 int ret = feparm->getDVBS(sat_parm);
2673                 ASSERT(!ret);
2674                 if (sat_parm.system == eDVBFrontendParametersSatellite::System_DVB_S2 && !m_can_handle_dvbs2)
2675                         return 0;
2676                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2677                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System_DVB_S && m_can_handle_dvbs2)
2678                         ret -= 1;
2679                 return ret;
2680         }
2681         else if (m_type == eDVBFrontend::feCable)
2682                 return 2;  // more prio for cable frontends
2683         else if (m_type == eDVBFrontend::feTerrestrial)
2684                 return 1;
2685         return 0;
2686 }
2687
2688 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2689 {
2690         ePyObject Id, Descr, Enabled, IsDVBS2;
2691         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2692                 goto arg_error;
2693         Id = PyTuple_GET_ITEM(obj, 0);
2694         Descr = PyTuple_GET_ITEM(obj, 1);
2695         Enabled = PyTuple_GET_ITEM(obj, 2);
2696         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2697         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2698                 goto arg_error;
2699         strcpy(m_description, PyString_AS_STRING(Descr));
2700         m_slotid = PyInt_AsLong(Id);
2701         m_enabled = Enabled == Py_True;
2702         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2703         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2704                 !!strstr(m_description, "Alps BSBE2") ||
2705                 !!strstr(m_description, "Alps -S") ||
2706                 !!strstr(m_description, "BCM4501");
2707         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2708         eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2709                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2710         return true;
2711 arg_error:
2712         PyErr_SetString(PyExc_StandardError,
2713                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2714         return false;
2715 }