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