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