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