create index files for plugin metadata
[enigma2.git] / 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 (parm_u_qpsk_fec_inner <= FEC_AUTO) // 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 (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1849 #if HAVE_DVB_API_VERSION >= 5
1850                 if (m_type == iDVBFrontend::feSatellite)
1851                 {
1852                         fe_rolloff_t rolloff = ROLLOFF_35;
1853                         fe_pilot_t pilot = PILOT_OFF;
1854                         fe_modulation_t modulation = QPSK;
1855                         fe_delivery_system_t system = SYS_DVBS;
1856                         switch(oparm.sat.system)
1857                         {
1858                         case eDVBFrontendParametersSatellite::System_DVB_S: system = SYS_DVBS; break;
1859                         case eDVBFrontendParametersSatellite::System_DVB_S2: system = SYS_DVBS2; break;
1860                         };
1861                         switch(oparm.sat.modulation)
1862                         {
1863                         case eDVBFrontendParametersSatellite::Modulation_QPSK: modulation = QPSK; break;
1864                         case eDVBFrontendParametersSatellite::Modulation_8PSK: modulation = PSK_8; break;
1865                         case eDVBFrontendParametersSatellite::Modulation_QAM16: modulation = QAM_16; break;
1866                         };
1867                         switch(oparm.sat.pilot)
1868                         {
1869                         case eDVBFrontendParametersSatellite::Pilot_Off: pilot = PILOT_OFF; break;
1870                         case eDVBFrontendParametersSatellite::Pilot_On: pilot = PILOT_ON; break;
1871                         case eDVBFrontendParametersSatellite::Pilot_Unknown: pilot = PILOT_AUTO; break;
1872                         };
1873                         switch(oparm.sat.rolloff)
1874                         {
1875                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_20: rolloff = ROLLOFF_20; break;
1876                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_25: rolloff = ROLLOFF_25; break;
1877                         case eDVBFrontendParametersSatellite::RollOff_alpha_0_35: rolloff = ROLLOFF_35; break;
1878                         };
1879                         struct dtv_property p[10];
1880                         struct dtv_properties cmdseq;
1881                         cmdseq.props = p;
1882                         p[0].cmd = DTV_CLEAR;
1883                         p[1].cmd = DTV_DELIVERY_SYSTEM, p[1].u.data = system;
1884                         p[2].cmd = DTV_FREQUENCY,       p[1].u.data = parm_frequency;
1885                         p[3].cmd = DTV_MODULATION,      p[3].u.data = modulation;
1886                         p[4].cmd = DTV_SYMBOL_RATE,     p[4].u.data = parm_u_qpsk_symbol_rate;
1887                         p[5].cmd = DTV_INNER_FEC,       p[5].u.data = parm_u_qpsk_fec_inner;
1888                         p[6].cmd = DTV_INVERSION,       p[6].u.data = parm_inversion;
1889                         if (system = SYS_DVBS2)
1890                         {
1891                                 p[7].cmd = DTV_ROLLOFF,         p[7].u.data = rolloff;
1892                                 p[8].cmd = DTV_PILOT,           p[8].u.data = pilot;
1893                                 p[9].cmd = DTV_TUNE;
1894                                 cmdseq.num = 10;
1895                         }
1896                         else
1897                         {
1898                                 p[7].cmd = DTV_TUNE;
1899                                 cmdseq.num = 8;
1900                         }
1901                         if (ioctl(m_fd, FE_SET_PROPERTY, &cmdseq) == -1)
1902                         {
1903                                 perror("FE_SET_PROPERTY failed");
1904                                 return;
1905                         }
1906                 }
1907                 else
1908 #endif
1909                 {
1910                         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1911                         {
1912                                 perror("FE_SET_FRONTEND failed");
1913                                 return;
1914                         }
1915                 }
1916         }
1917 }
1918
1919 RESULT eDVBFrontend::getFrontendType(int &t)
1920 {
1921         if (m_type == -1)
1922                 return -ENODEV;
1923         t = m_type;
1924         return 0;
1925 }
1926
1927 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1928 {
1929         int res;
1930         if (!m_sec)
1931         {
1932                 eWarning("no SEC module active!");
1933                 return -ENOENT;
1934         }
1935         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1936         if (!res)
1937         {
1938 #if HAVE_DVB_API_VERSION >= 3
1939                 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",
1940                         feparm.system,
1941                         feparm.frequency,
1942                         feparm.polarisation,
1943                         feparm.symbol_rate,
1944                         feparm.inversion,
1945                         feparm.fec,
1946                         feparm.orbital_position,
1947                         feparm.system,
1948                         feparm.modulation,
1949                         feparm.pilot,
1950                         feparm.rolloff);
1951 #else
1952                 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1953                         feparm.system,
1954                         feparm.frequency,
1955                         feparm.polarisation,
1956                         feparm.symbol_rate,
1957                         feparm.inversion,
1958                         feparm.fec,
1959                         feparm.orbital_position);
1960 #endif
1961                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1962                 switch (feparm.inversion)
1963                 {
1964                         case eDVBFrontendParametersSatellite::Inversion_On:
1965                                 parm_inversion = INVERSION_ON;
1966                                 break;
1967                         case eDVBFrontendParametersSatellite::Inversion_Off:
1968                                 parm_inversion = INVERSION_OFF;
1969                                 break;
1970                         default:
1971                         case eDVBFrontendParametersSatellite::Inversion_Unknown:
1972                                 parm_inversion = INVERSION_AUTO;
1973                                 break;
1974                 }
1975                 if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S)
1976                 {
1977                         switch (feparm.fec)
1978                         {
1979                                 case eDVBFrontendParametersSatellite::FEC_None:
1980                                         parm_u_qpsk_fec_inner = FEC_NONE;
1981                                         break;
1982                                 case eDVBFrontendParametersSatellite::FEC_1_2:
1983                                         parm_u_qpsk_fec_inner = FEC_1_2;
1984                                         break;
1985                                 case eDVBFrontendParametersSatellite::FEC_2_3:
1986                                         parm_u_qpsk_fec_inner = FEC_2_3;
1987                                         break;
1988                                 case eDVBFrontendParametersSatellite::FEC_3_4:
1989                                         parm_u_qpsk_fec_inner = FEC_3_4;
1990                                         break;
1991                                 case eDVBFrontendParametersSatellite::FEC_5_6:
1992                                         parm_u_qpsk_fec_inner = FEC_5_6;
1993                                         break;
1994                                 case eDVBFrontendParametersSatellite::FEC_7_8:
1995                                         parm_u_qpsk_fec_inner = FEC_7_8;
1996                                         break;
1997                                 default:
1998                                         eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
1999                                 case eDVBFrontendParametersSatellite::FEC_Auto:
2000                                         parm_u_qpsk_fec_inner = FEC_AUTO;
2001                                         break;
2002                         }
2003                 }
2004 #if HAVE_DVB_API_VERSION >= 3
2005                 else // DVB_S2
2006                 {
2007                         switch (feparm.fec)
2008                         {
2009                                 case eDVBFrontendParametersSatellite::FEC_1_2:
2010                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
2011                                         break;
2012                                 case eDVBFrontendParametersSatellite::FEC_2_3:
2013                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
2014                                         break;
2015                                 case eDVBFrontendParametersSatellite::FEC_3_4:
2016                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
2017                                         break;
2018                                 case eDVBFrontendParametersSatellite::FEC_3_5:
2019                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
2020                                         break;
2021                                 case eDVBFrontendParametersSatellite::FEC_4_5:
2022                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
2023                                         break;
2024                                 case eDVBFrontendParametersSatellite::FEC_5_6:
2025                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
2026                                         break;
2027                                 case eDVBFrontendParametersSatellite::FEC_7_8:
2028                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
2029                                         break;
2030                                 case eDVBFrontendParametersSatellite::FEC_8_9:
2031                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
2032                                         break;
2033                                 case eDVBFrontendParametersSatellite::FEC_9_10:
2034                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
2035                                         break;
2036                                 default:
2037                                         eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
2038                                         return -EINVAL;
2039                         }
2040 #if HAVE_DVB_API_VERSION < 5
2041                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
2042                         parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
2043                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation_8PSK) 
2044                         {
2045                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
2046                                 // 8PSK fec driver values are decimal 9 bigger
2047                         }
2048 #endif
2049                 }
2050 #endif
2051                 // FIXME !!! get frequency range from tuner
2052                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
2053                 {
2054                         eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
2055                         return -EINVAL;
2056                 }
2057                 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
2058         }
2059         oparm.sat = feparm;
2060         return res;
2061 }
2062
2063 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
2064 {
2065 #if HAVE_DVB_API_VERSION < 3
2066         parm_frequency = feparm.frequency;
2067 #else
2068         parm_frequency = feparm.frequency * 1000;
2069 #endif
2070         parm_u_qam_symbol_rate = feparm.symbol_rate;
2071         switch (feparm.modulation)
2072         {
2073         case eDVBFrontendParametersCable::Modulation_QAM16:
2074                 parm_u_qam_modulation = QAM_16;
2075                 break;
2076         case eDVBFrontendParametersCable::Modulation_QAM32:
2077                 parm_u_qam_modulation = QAM_32;
2078                 break;
2079         case eDVBFrontendParametersCable::Modulation_QAM64:
2080                 parm_u_qam_modulation = QAM_64;
2081                 break;
2082         case eDVBFrontendParametersCable::Modulation_QAM128:
2083                 parm_u_qam_modulation = QAM_128;
2084                 break;
2085         case eDVBFrontendParametersCable::Modulation_QAM256:
2086                 parm_u_qam_modulation = QAM_256;
2087                 break;
2088         default:
2089         case eDVBFrontendParametersCable::Modulation_Auto:
2090                 parm_u_qam_modulation = QAM_AUTO;
2091                 break;
2092         }
2093         switch (feparm.inversion)
2094         {
2095         case eDVBFrontendParametersCable::Inversion_On:
2096                 parm_inversion = INVERSION_ON;
2097                 break;
2098         case eDVBFrontendParametersCable::Inversion_Off:
2099                 parm_inversion = INVERSION_OFF;
2100                 break;
2101         default:
2102         case eDVBFrontendParametersCable::Inversion_Unknown:
2103                 parm_inversion = INVERSION_AUTO;
2104                 break;
2105         }
2106         switch (feparm.fec_inner)
2107         {
2108         case eDVBFrontendParametersCable::FEC_None:
2109                 parm_u_qam_fec_inner = FEC_NONE;
2110                 break;
2111         case eDVBFrontendParametersCable::FEC_1_2:
2112                 parm_u_qam_fec_inner = FEC_1_2;
2113                 break;
2114         case eDVBFrontendParametersCable::FEC_2_3:
2115                 parm_u_qam_fec_inner = FEC_2_3;
2116                 break;
2117         case eDVBFrontendParametersCable::FEC_3_4:
2118                 parm_u_qam_fec_inner = FEC_3_4;
2119                 break;
2120         case eDVBFrontendParametersCable::FEC_5_6:
2121                 parm_u_qam_fec_inner = FEC_5_6;
2122                 break;
2123         case eDVBFrontendParametersCable::FEC_7_8:
2124                 parm_u_qam_fec_inner = FEC_7_8;
2125                 break;
2126 #if HAVE_DVB_API_VERSION >= 3
2127         case eDVBFrontendParametersCable::FEC_8_9:
2128                 parm_u_qam_fec_inner = FEC_8_9;
2129                 break;
2130 #endif
2131         default:
2132         case eDVBFrontendParametersCable::FEC_Auto:
2133                 parm_u_qam_fec_inner = FEC_AUTO;
2134                 break;
2135         }
2136         eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
2137                 parm_frequency/1000,
2138                 parm_u_qam_symbol_rate,
2139                 parm_u_qam_fec_inner,
2140                 parm_u_qam_modulation,
2141                 parm_inversion);
2142         oparm.cab = feparm;
2143         return 0;
2144 }
2145
2146 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
2147 {
2148         parm_frequency = feparm.frequency;
2149
2150         switch (feparm.bandwidth)
2151         {
2152         case eDVBFrontendParametersTerrestrial::Bandwidth_8MHz:
2153                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
2154                 break;
2155         case eDVBFrontendParametersTerrestrial::Bandwidth_7MHz:
2156                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
2157                 break;
2158         case eDVBFrontendParametersTerrestrial::Bandwidth_6MHz:
2159                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2160                 break;
2161         default:
2162         case eDVBFrontendParametersTerrestrial::Bandwidth_Auto:
2163                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2164                 break;
2165         }
2166         switch (feparm.code_rate_LP)
2167         {
2168         case eDVBFrontendParametersTerrestrial::FEC_1_2:
2169                 parm_u_ofdm_code_rate_LP = FEC_1_2;
2170                 break;
2171         case eDVBFrontendParametersTerrestrial::FEC_2_3:
2172                 parm_u_ofdm_code_rate_LP = FEC_2_3;
2173                 break;
2174         case eDVBFrontendParametersTerrestrial::FEC_3_4:
2175                 parm_u_ofdm_code_rate_LP = FEC_3_4;
2176                 break;
2177         case eDVBFrontendParametersTerrestrial::FEC_5_6:
2178                 parm_u_ofdm_code_rate_LP = FEC_5_6;
2179                 break;
2180         case eDVBFrontendParametersTerrestrial::FEC_7_8:
2181                 parm_u_ofdm_code_rate_LP = FEC_7_8;
2182                 break;
2183         default:
2184         case eDVBFrontendParametersTerrestrial::FEC_Auto:
2185                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2186                 break;
2187         }
2188         switch (feparm.code_rate_HP)
2189         {
2190         case eDVBFrontendParametersTerrestrial::FEC_1_2:
2191                 parm_u_ofdm_code_rate_HP = FEC_1_2;
2192                 break;
2193         case eDVBFrontendParametersTerrestrial::FEC_2_3:
2194                 parm_u_ofdm_code_rate_HP = FEC_2_3;
2195                 break;
2196         case eDVBFrontendParametersTerrestrial::FEC_3_4:
2197                 parm_u_ofdm_code_rate_HP = FEC_3_4;
2198                 break;
2199         case eDVBFrontendParametersTerrestrial::FEC_5_6:
2200                 parm_u_ofdm_code_rate_HP = FEC_5_6;
2201                 break;
2202         case eDVBFrontendParametersTerrestrial::FEC_7_8:
2203                 parm_u_ofdm_code_rate_HP = FEC_7_8;
2204                 break;
2205         default:
2206         case eDVBFrontendParametersTerrestrial::FEC_Auto:
2207                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2208                 break;
2209         }
2210         switch (feparm.modulation)
2211         {
2212         case eDVBFrontendParametersTerrestrial::Modulation_QPSK:
2213                 parm_u_ofdm_constellation = QPSK;
2214                 break;
2215         case eDVBFrontendParametersTerrestrial::Modulation_QAM16:
2216                 parm_u_ofdm_constellation = QAM_16;
2217                 break;
2218         case eDVBFrontendParametersTerrestrial::Modulation_QAM64:
2219                 parm_u_ofdm_constellation = QAM_64;
2220                 break;
2221         default:
2222         case eDVBFrontendParametersTerrestrial::Modulation_Auto:
2223                 parm_u_ofdm_constellation = QAM_AUTO;
2224                 break;
2225         }
2226         switch (feparm.transmission_mode)
2227         {
2228         case eDVBFrontendParametersTerrestrial::TransmissionMode_2k:
2229                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2230                 break;
2231         case eDVBFrontendParametersTerrestrial::TransmissionMode_8k:
2232                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2233                 break;
2234         default:
2235         case eDVBFrontendParametersTerrestrial::TransmissionMode_Auto:
2236                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2237                 break;
2238         }
2239         switch (feparm.guard_interval)
2240         {
2241                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_32:
2242                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2243                         break;
2244                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_16:
2245                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2246                         break;
2247                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_8:
2248                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2249                         break;
2250                 case eDVBFrontendParametersTerrestrial::GuardInterval_1_4:
2251                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2252                         break;
2253                 default:
2254                 case eDVBFrontendParametersTerrestrial::GuardInterval_Auto:
2255                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2256                         break;
2257         }
2258         switch (feparm.hierarchy)
2259         {
2260                 case eDVBFrontendParametersTerrestrial::Hierarchy_None:
2261                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2262                         break;
2263                 case eDVBFrontendParametersTerrestrial::Hierarchy_1:
2264                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2265                         break;
2266                 case eDVBFrontendParametersTerrestrial::Hierarchy_2:
2267                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2268                         break;
2269                 case eDVBFrontendParametersTerrestrial::Hierarchy_4:
2270                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2271                         break;
2272                 default:
2273                 case eDVBFrontendParametersTerrestrial::Hierarchy_Auto:
2274                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2275                         break;
2276         }
2277         switch (feparm.inversion)
2278         {
2279         case eDVBFrontendParametersTerrestrial::Inversion_On:
2280                 parm_inversion = INVERSION_ON;
2281                 break;
2282         case eDVBFrontendParametersTerrestrial::Inversion_Off:
2283                 parm_inversion = INVERSION_OFF;
2284                 break;
2285         default:
2286         case eDVBFrontendParametersTerrestrial::Inversion_Unknown:
2287                 parm_inversion = INVERSION_AUTO;
2288                 break;
2289         }
2290         oparm.ter = feparm;
2291         return 0;
2292 }
2293
2294 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2295 {
2296         unsigned int timeout = 5000;
2297         eDebugNoSimulate("(%d)tune", m_dvbid);
2298
2299         m_timeout->stop();
2300
2301         int res=0;
2302
2303         if (!m_sn && !m_simulate)
2304         {
2305                 eDebug("no frontend device opened... do not try to tune !!!");
2306                 res = -ENODEV;
2307                 goto tune_error;
2308         }
2309
2310         if (m_type == -1)
2311         {
2312                 res = -ENODEV;
2313                 goto tune_error;
2314         }
2315
2316         if (!m_simulate)
2317                 m_sn->stop();
2318
2319         m_sec_sequence.clear();
2320
2321         where.calcLockTimeout(timeout);
2322
2323         switch (m_type)
2324         {
2325         case feSatellite:
2326         {
2327                 eDVBFrontendParametersSatellite feparm;
2328                 if (where.getDVBS(feparm))
2329                 {
2330                         eDebug("no dvbs data!");
2331                         res = -EINVAL;
2332                         goto tune_error;
2333                 }
2334                 if (!m_simulate)
2335                         m_sec->setRotorMoving(false);
2336                 res=prepare_sat(feparm, timeout);
2337                 if (res)
2338                         goto tune_error;
2339
2340                 break;
2341         }
2342         case feCable:
2343         {
2344                 eDVBFrontendParametersCable feparm;
2345                 if (where.getDVBC(feparm))
2346                 {
2347                         res = -EINVAL;
2348                         goto tune_error;
2349                 }
2350                 res=prepare_cable(feparm);
2351                 if (res)
2352                         goto tune_error;
2353
2354                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2355                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND, 1) );
2356                 break;
2357         }
2358         case feTerrestrial:
2359         {
2360                 eDVBFrontendParametersTerrestrial feparm;
2361                 if (where.getDVBT(feparm))
2362                 {
2363                         eDebug("no -T data");
2364                         res = -EINVAL;
2365                         goto tune_error;
2366                 }
2367                 res=prepare_terrestrial(feparm);
2368                 if (res)
2369                         goto tune_error;
2370
2371                 std::string enable_5V;
2372                 char configStr[255];
2373                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2374                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2375                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2376                 if (enable_5V == "True")
2377                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2378                 else
2379                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2380                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND, 1) );
2381
2382                 break;
2383         }
2384         }
2385
2386         m_sec_sequence.current() = m_sec_sequence.begin();
2387
2388         if (!m_simulate)
2389         {
2390                 m_tuneTimer->start(0,true);
2391                 if (m_state != stateTuning)
2392                 {
2393                         m_tuning = 1;
2394                         m_state = stateTuning;
2395                         m_stateChanged(this);
2396                 }
2397         }
2398         else
2399                 tuneLoop();
2400
2401         return res;
2402
2403 tune_error:
2404         m_tuneTimer->stop();
2405         return res;
2406 }
2407
2408 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2409 {
2410         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2411         return 0;
2412 }
2413
2414 RESULT eDVBFrontend::setVoltage(int voltage)
2415 {
2416         if (m_type == feCable)
2417                 return -1;
2418 #if HAVE_DVB_API_VERSION < 3
2419         secVoltage vlt;
2420 #else
2421         bool increased=false;
2422         fe_sec_voltage_t vlt;
2423 #endif
2424         m_data[CUR_VOLTAGE]=voltage;
2425         switch (voltage)
2426         {
2427         case voltageOff:
2428                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2429                 vlt = SEC_VOLTAGE_OFF;
2430                 break;
2431         case voltage13_5:
2432 #if HAVE_DVB_API_VERSION < 3
2433                 vlt = SEC_VOLTAGE_13_5;
2434                 break;
2435 #else
2436                 increased = true;
2437 #endif
2438         case voltage13:
2439                 vlt = SEC_VOLTAGE_13;
2440                 break;
2441         case voltage18_5:
2442 #if HAVE_DVB_API_VERSION < 3
2443                 vlt = SEC_VOLTAGE_18_5;
2444                 break;
2445 #else
2446                 increased = true;
2447 #endif
2448         case voltage18:
2449                 vlt = SEC_VOLTAGE_18;
2450                 break;
2451         default:
2452                 return -ENODEV;
2453         }
2454         if (m_simulate)
2455                 return 0;
2456 #if HAVE_DVB_API_VERSION < 3
2457         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2458 #else
2459         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2460                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2461         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2462 #endif
2463 }
2464
2465 RESULT eDVBFrontend::getState(int &state)
2466 {
2467         state = m_state;
2468         return 0;
2469 }
2470
2471 RESULT eDVBFrontend::setTone(int t)
2472 {
2473         if (m_type != feSatellite)
2474                 return -1;
2475 #if HAVE_DVB_API_VERSION < 3
2476         secToneMode_t tone;
2477 #else
2478         fe_sec_tone_mode_t tone;
2479 #endif
2480         m_data[CUR_TONE]=t;
2481         switch (t)
2482         {
2483         case toneOn:
2484                 tone = SEC_TONE_ON;
2485                 break;
2486         case toneOff:
2487                 tone = SEC_TONE_OFF;
2488                 break;
2489         default:
2490                 return -ENODEV;
2491         }
2492         if (m_simulate)
2493                 return 0;
2494 #if HAVE_DVB_API_VERSION < 3    
2495         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2496 #else   
2497         return ::ioctl(m_fd, FE_SET_TONE, tone);
2498 #endif
2499 }
2500
2501 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2502         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2503 #endif
2504
2505 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2506 {
2507         if (m_simulate)
2508                 return 0;
2509 #if HAVE_DVB_API_VERSION < 3
2510         struct secCommand cmd;
2511         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2512         cmd.u.diseqc.cmdtype = diseqc.data[0];
2513         cmd.u.diseqc.addr = diseqc.data[1];
2514         cmd.u.diseqc.cmd = diseqc.data[2];
2515         cmd.u.diseqc.numParams = diseqc.len-3;
2516         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2517         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2518 #else
2519         struct dvb_diseqc_master_cmd cmd;
2520         memcpy(cmd.msg, diseqc.data, diseqc.len);
2521         cmd.msg_len = diseqc.len;
2522         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2523 #endif
2524                 return -EINVAL;
2525         return 0;
2526 }
2527
2528 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2529         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2530 #endif
2531 RESULT eDVBFrontend::sendToneburst(int burst)
2532 {
2533         if (m_simulate)
2534                 return 0;
2535 #if HAVE_DVB_API_VERSION < 3
2536         secMiniCmd cmd = SEC_MINI_NONE;
2537 #else
2538         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2539 #endif
2540         if ( burst == eDVBSatelliteDiseqcParameters::A )
2541                 cmd = SEC_MINI_A;
2542         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2543                 cmd = SEC_MINI_B;
2544 #if HAVE_DVB_API_VERSION < 3
2545         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2546                 return -EINVAL;
2547 #else
2548         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2549                 return -EINVAL;
2550 #endif
2551         return 0;
2552 }
2553
2554 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2555 {
2556         m_sec = sec;
2557         return 0;
2558 }
2559
2560 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2561 {
2562         m_sec_sequence = list;
2563         return 0;
2564 }
2565
2566 RESULT eDVBFrontend::getData(int num, long &data)
2567 {
2568         if ( num < NUM_DATA_ENTRIES )
2569         {
2570                 data = m_data[num];
2571                 return 0;
2572         }
2573         return -EINVAL;
2574 }
2575
2576 RESULT eDVBFrontend::setData(int num, long val)
2577 {
2578         if ( num < NUM_DATA_ENTRIES )
2579         {
2580                 m_data[num] = val;
2581                 return 0;
2582         }
2583         return -EINVAL;
2584 }
2585
2586 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2587 {
2588         int type;
2589         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2590                 return 0;
2591         if (m_type == eDVBFrontend::feSatellite)
2592         {
2593                 ASSERT(m_sec);
2594                 eDVBFrontendParametersSatellite sat_parm;
2595                 int ret = feparm->getDVBS(sat_parm);
2596                 ASSERT(!ret);
2597                 if (sat_parm.system == eDVBFrontendParametersSatellite::System_DVB_S2 && !m_can_handle_dvbs2)
2598                         return 0;
2599                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2600                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System_DVB_S && m_can_handle_dvbs2)
2601                         ret -= 1;
2602                 return ret;
2603         }
2604         else if (m_type == eDVBFrontend::feCable)
2605                 return 2;  // more prio for cable frontends
2606         else if (m_type == eDVBFrontend::feTerrestrial)
2607                 return 1;
2608         return 0;
2609 }
2610
2611 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2612 {
2613         ePyObject Id, Descr, Enabled, IsDVBS2;
2614         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2615                 goto arg_error;
2616         Id = PyTuple_GET_ITEM(obj, 0);
2617         Descr = PyTuple_GET_ITEM(obj, 1);
2618         Enabled = PyTuple_GET_ITEM(obj, 2);
2619         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2620         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2621                 goto arg_error;
2622         strcpy(m_description, PyString_AS_STRING(Descr));
2623         m_slotid = PyInt_AsLong(Id);
2624         m_enabled = Enabled == Py_True;
2625         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2626         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2627                 !!strstr(m_description, "Alps BSBE2") ||
2628                 !!strstr(m_description, "Alps -S") ||
2629                 !!strstr(m_description, "BCM4501");
2630         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2631         eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2632                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2633         return true;
2634 arg_error:
2635         PyErr_SetString(PyExc_StandardError,
2636                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2637         return false;
2638 }
2639
2640 RESULT eDVBFrontend::turnOffSatCR(int satcr)
2641 {
2642         eSecCommandList sec_sequence;
2643         // check if voltage is disabled
2644         eSecCommand::pair compare;
2645         compare.steps = +9;     //nothing to do
2646         compare.voltage = iDVBFrontend::voltageOff;
2647         sec_sequence.push_back( eSecCommand(eSecCommand::IF_NOT_VOLTAGE_GOTO, compare) );
2648         sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2649         sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 50 ) );
2650
2651         sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage18_5) );
2652         sec_sequence.push_back( eSecCommand(eSecCommand::SET_TONE, iDVBFrontend::toneOff) );
2653         sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 250) );
2654
2655         eDVBDiseqcCommand diseqc;
2656         memset(diseqc.data, 0, MAX_DISEQC_LENGTH);
2657         diseqc.len = 5;
2658         diseqc.data[0] = 0xE0;
2659         diseqc.data[1] = 0x10;
2660         diseqc.data[2] = 0x5A;
2661         diseqc.data[3] = satcr << 5;
2662         diseqc.data[4] = 0x00;
2663
2664         sec_sequence.push_back( eSecCommand(eSecCommand::SEND_DISEQC, diseqc) );
2665         sec_sequence.push_back( eSecCommand(eSecCommand::SLEEP, 50+20+14*diseqc.len) );
2666         sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2667         setSecSequence(sec_sequence);
2668         return 0;
2669 }
2670
2671 RESULT eDVBFrontend::ScanSatCR()
2672 {
2673         setFrontend();
2674         usleep(20000);
2675         setTone(iDVBFrontend::toneOff);
2676         return 0;
2677 }