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