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