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