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