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