also use refcounting for eTimers
[enigma2.git] / lib / dvb / frontend.cpp
1 #include <lib/dvb/dvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/base/nconfig.h> // access to python config
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8
9 #ifndef I2C_SLAVE_FORCE
10 #define I2C_SLAVE_FORCE 0x0706
11 #endif
12
13 #if HAVE_DVB_API_VERSION < 3
14 #include <ost/frontend.h>
15 #include <ost/sec.h>
16 #define QAM_AUTO                                (Modulation)6
17 #define TRANSMISSION_MODE_AUTO  (TransmitMode)2
18 #define BANDWIDTH_AUTO                  (BandWidth)3
19 #define GUARD_INTERVAL_AUTO             (GuardInterval)4
20 #define HIERARCHY_AUTO                  (Hierarchy)4
21 #define parm_frequency parm.Frequency
22 #define parm_inversion parm.Inversion
23 #define parm_u_qpsk_symbol_rate parm.u.qpsk.SymbolRate
24 #define parm_u_qpsk_fec_inner parm.u.qpsk.FEC_inner
25 #define parm_u_qam_symbol_rate parm.u.qam.SymbolRate
26 #define parm_u_qam_fec_inner parm.u.qam.FEC_inner
27 #define parm_u_qam_modulation parm.u.qam.QAM
28 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandWidth
29 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.LP_CodeRate
30 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.HP_CodeRate
31 #define parm_u_ofdm_constellation parm.u.ofdm.Constellation
32 #define parm_u_ofdm_transmission_mode parm.u.ofdm.TransmissionMode
33 #define parm_u_ofdm_guard_interval parm.u.ofdm.guardInterval
34 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.HierarchyInformation
35 #else
36 #include <linux/dvb/frontend.h>
37 #define parm_frequency parm.frequency
38 #define parm_inversion parm.inversion
39 #define parm_u_qpsk_symbol_rate parm.u.qpsk.symbol_rate
40 #define parm_u_qpsk_fec_inner parm.u.qpsk.fec_inner
41 #define parm_u_qam_symbol_rate parm.u.qam.symbol_rate
42 #define parm_u_qam_fec_inner parm.u.qam.fec_inner
43 #define parm_u_qam_modulation parm.u.qam.modulation
44 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandwidth
45 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.code_rate_LP
46 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.code_rate_HP
47 #define parm_u_ofdm_constellation parm.u.ofdm.constellation
48 #define parm_u_ofdm_transmission_mode parm.u.ofdm.transmission_mode
49 #define parm_u_ofdm_guard_interval parm.u.ofdm.guard_interval
50 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.hierarchy_information
51 #ifdef FEC_9_10
52         #warning "FEC_9_10 already exist in dvb api ... it seems it is now ready for DVB-S2"
53 #else
54         #define FEC_S2_QPSK_1_2 (fe_code_rate_t)(FEC_AUTO+1)
55         #define FEC_S2_QPSK_2_3 (fe_code_rate_t)(FEC_S2_QPSK_1_2+1)
56         #define FEC_S2_QPSK_3_4 (fe_code_rate_t)(FEC_S2_QPSK_2_3+1)
57         #define FEC_S2_QPSK_5_6 (fe_code_rate_t)(FEC_S2_QPSK_3_4+1)
58         #define FEC_S2_QPSK_7_8 (fe_code_rate_t)(FEC_S2_QPSK_5_6+1)
59         #define FEC_S2_QPSK_8_9 (fe_code_rate_t)(FEC_S2_QPSK_7_8+1)
60         #define FEC_S2_QPSK_3_5 (fe_code_rate_t)(FEC_S2_QPSK_8_9+1)
61         #define FEC_S2_QPSK_4_5 (fe_code_rate_t)(FEC_S2_QPSK_3_5+1)
62         #define FEC_S2_QPSK_9_10 (fe_code_rate_t)(FEC_S2_QPSK_4_5+1)
63         #define FEC_S2_8PSK_1_2 (fe_code_rate_t)(FEC_S2_QPSK_9_10+1)
64         #define FEC_S2_8PSK_2_3 (fe_code_rate_t)(FEC_S2_8PSK_1_2+1)
65         #define FEC_S2_8PSK_3_4 (fe_code_rate_t)(FEC_S2_8PSK_2_3+1)
66         #define FEC_S2_8PSK_5_6 (fe_code_rate_t)(FEC_S2_8PSK_3_4+1)
67         #define FEC_S2_8PSK_7_8 (fe_code_rate_t)(FEC_S2_8PSK_5_6+1)
68         #define FEC_S2_8PSK_8_9 (fe_code_rate_t)(FEC_S2_8PSK_7_8+1)
69         #define FEC_S2_8PSK_3_5 (fe_code_rate_t)(FEC_S2_8PSK_8_9+1)
70         #define FEC_S2_8PSK_4_5 (fe_code_rate_t)(FEC_S2_8PSK_3_5+1)
71         #define FEC_S2_8PSK_9_10 (fe_code_rate_t)(FEC_S2_8PSK_4_5+1)
72 #endif
73 #endif
74
75 #include <dvbsi++/satellite_delivery_system_descriptor.h>
76 #include <dvbsi++/cable_delivery_system_descriptor.h>
77 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
78
79 #define eDebugNoSimulate(x...) \
80         do { \
81                 if (!m_simulate) \
82                         eDebug(x); \
83         } while(0)
84 //              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                                 eDebugNoSimulate("");
1496                                 ++m_sec_sequence.current();
1497                                 break;
1498                         case eSecCommand::SEND_TONEBURST:
1499                                 eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1500                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1501                                 break;
1502                         case eSecCommand::SET_FRONTEND:
1503                                 eDebugNoSimulate("[SEC] setFrontend");
1504                                 setFrontend();
1505                                 ++m_sec_sequence.current();
1506                                 break;
1507                         case eSecCommand::START_TUNE_TIMEOUT:
1508                         {
1509                                 if (!m_simulate)
1510                                         m_timeout->start(m_sec_sequence.current()->timeout, 1);
1511                                 ++m_sec_sequence.current();
1512                                 break;
1513                         }
1514                         case eSecCommand::SET_TIMEOUT:
1515                                 m_timeoutCount = m_sec_sequence.current()++->val;
1516                                 eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
1517                                 break;
1518                         case eSecCommand::IF_TIMEOUT_GOTO:
1519                                 if (!m_timeoutCount)
1520                                 {
1521                                         eDebugNoSimulate("[SEC] rotor timout");
1522                                         setSecSequencePos(m_sec_sequence.current()->steps);
1523                                 }
1524                                 else
1525                                         ++m_sec_sequence.current();
1526                                 break;
1527                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1528                         {
1529                                 int idx = m_sec_sequence.current()++->val;
1530                                 if ( idx == 0 || idx == 1 )
1531                                 {
1532                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1533                                         eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1534                                 }
1535                                 else
1536                                         eDebugNoSimulate("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1537                                 break;
1538                         }
1539                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1540                         {
1541                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1542                                 int idx = compare.val;
1543                                 if ( !m_simulate && (idx == 0 || idx == 1) )
1544                                 {
1545                                         int idle = sec_fe->readInputpower();
1546                                         int diff = abs(idle-m_idleInputpower[idx]);
1547                                         if ( diff > 0)
1548                                         {
1549                                                 eDebugNoSimulate("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1550                                                 setSecSequencePos(compare.steps);
1551                                                 break;
1552                                         }
1553                                 }
1554                                 ++m_sec_sequence.current();
1555                                 break;
1556                         }
1557                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1558                         {
1559                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1560                                 if (m_simulate)
1561                                 {
1562                                         setSecSequencePos(cmd.steps);
1563                                         break;
1564                                 }
1565                                 int signal = 0;
1566                                 int isLocked = readFrontendData(locked);
1567                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1568                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1569                                 {
1570                                         if (cmd.lastSignal)
1571                                                 eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1572                                         else
1573                                         {
1574                                                 eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
1575                                                 cmd.lastSignal = signal;
1576                                         }
1577                                         ++cmd.okcount;
1578                                         if (cmd.okcount > 4)
1579                                         {
1580                                                 eDebugNoSimulate("ok > 4 .. goto %d\n",cmd.steps);
1581                                                 setSecSequencePos(cmd.steps);
1582                                                 m_state = stateLock;
1583                                                 m_stateChanged(this);
1584                                                 feEvent(-1);
1585                                                 m_sn->start();
1586                                                 break;
1587                                         }
1588                                 }
1589                                 else
1590                                 {
1591                                         if (isLocked)
1592                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1593                                         else
1594                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1595                                         --m_timeoutCount;
1596                                         if (!m_timeoutCount && m_retryCount > 0)
1597                                                 --m_retryCount;
1598                                         cmd.okcount=0;
1599                                         cmd.lastSignal=0;
1600                                 }
1601                                 ++m_sec_sequence.current();
1602                                 break;
1603                         }
1604                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1605                                 m_runningInputpower = sec_fe->readInputpower();
1606                                 eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
1607                                 ++m_sec_sequence.current();
1608                                 break;
1609                         case eSecCommand::SET_ROTOR_MOVING:
1610                                 if (!m_simulate)
1611                                         m_sec->setRotorMoving(true);
1612                                 ++m_sec_sequence.current();
1613                                 break;
1614                         case eSecCommand::SET_ROTOR_STOPPED:
1615                                 if (!m_simulate)
1616                                         m_sec->setRotorMoving(false);
1617                                 ++m_sec_sequence.current();
1618                                 break;
1619                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1620                         {
1621                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1622                                 if (m_simulate)
1623                                 {
1624                                         setSecSequencePos(cmd.steps);
1625                                         break;
1626                                 }
1627                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1628                                 const char *txt = cmd.direction ? "running" : "stopped";
1629                                 eDebugNoSimulate("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1630                                         txt,
1631                                         m_runningInputpower,
1632                                         idleInputpower,
1633                                         cmd.deltaA);
1634                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1635                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1636                                 {
1637                                         ++cmd.okcount;
1638                                         eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1639                                         if ( cmd.okcount > 6 )
1640                                         {
1641                                                 eDebugNoSimulate("[SEC] rotor is %s", txt);
1642                                                 if (setSecSequencePos(cmd.steps))
1643                                                         break;
1644                                         }
1645                                 }
1646                                 else
1647                                 {
1648                                         eDebugNoSimulate("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1649                                         --m_timeoutCount;
1650                                         if (!m_timeoutCount && m_retryCount > 0)
1651                                                 --m_retryCount;
1652                                         cmd.okcount=0;
1653                                 }
1654                                 ++m_sec_sequence.current();
1655                                 break;
1656                         }
1657                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1658                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1659                                         setSecSequencePos(m_sec_sequence.current()->steps);
1660                                 else
1661                                         ++m_sec_sequence.current();
1662                                 break;
1663                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1664                                 eDebugNoSimulate("[SEC] invalidate current switch params");
1665                                 sec_fe_data[CSW] = -1;
1666                                 sec_fe_data[UCSW] = -1;
1667                                 sec_fe_data[TONEBURST] = -1;
1668                                 ++m_sec_sequence.current();
1669                                 break;
1670                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1671                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1672                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1673                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1674                                 eDebugNoSimulate("[SEC] update current switch params");
1675                                 ++m_sec_sequence.current();
1676                                 break;
1677                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1678                                 eDebugNoSimulate("[SEC] invalidate current rotorparams");
1679                                 sec_fe_data[ROTOR_CMD] = -1;
1680                                 sec_fe_data[ROTOR_POS] = -1;
1681                                 ++m_sec_sequence.current();
1682                                 break;
1683                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1684                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1685                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1686                                 eDebugNoSimulate("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1687                                 ++m_sec_sequence.current();
1688                                 break;
1689                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1690                                 m_retryCount = m_sec_sequence.current()++->val;
1691                                 eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
1692                                 break;
1693                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1694                                 if (!m_retryCount)
1695                                 {
1696                                         eDebugNoSimulate("[SEC] no more rotor retrys");
1697                                         setSecSequencePos(m_sec_sequence.current()->steps);
1698                                 }
1699                                 else
1700                                         ++m_sec_sequence.current();
1701                                 break;
1702                         case eSecCommand::SET_POWER_LIMITING_MODE:
1703                         {
1704                                 if (!m_simulate)
1705                                 {
1706                                         char proc_name[64];
1707                                         sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1708                                         FILE *f=fopen(proc_name, "w");
1709                                         if (f) // new interface exist?
1710                                         {
1711                                                 bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1712                                                 if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1713                                                         eDebugNoSimulate("write %s failed!! (%m)", proc_name);
1714                                                 else
1715                                                         eDebugNoSimulate("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1716                                                 fclose(f);
1717                                         }
1718                                         else if (sec_fe->m_need_rotor_workaround)
1719                                         {
1720                                                 char dev[16];
1721                                                 int slotid = sec_fe->m_slotid;
1722                                                 // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1723                                                 if (slotid < 2)
1724                                                         sprintf(dev, "/dev/i2c/%d", slotid);
1725                                                 else if (slotid == 2)
1726                                                         sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1727                                                 else if (slotid == 3)
1728                                                         sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1729                                                 int fd = ::open(dev, O_RDWR);
1730
1731                                                 unsigned char data[2];
1732                                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1733                                                 if(::read(fd, data, 1) != 1)
1734                                                         eDebugNoSimulate("[SEC] error read lnbp (%m)");
1735                                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1736                                                 {
1737                                                         data[0] |= 0x80;  // enable static current limiting
1738                                                         eDebugNoSimulate("[SEC] set static current limiting");
1739                                                 }
1740                                                 else
1741                                                 {
1742                                                         data[0] &= ~0x80;  // enable dynamic current limiting
1743                                                         eDebugNoSimulate("[SEC] set dynamic current limiting");
1744                                                 }
1745                                                 if(::write(fd, data, 1) != 1)
1746                                                         eDebugNoSimulate("[SEC] error write lnbp (%m)");
1747                                                 ::close(fd);
1748                                         }
1749                                 }
1750                                 ++m_sec_sequence.current();
1751                                 break;
1752                         }
1753                         default:
1754                                 eDebugNoSimulate("[SEC] unhandled sec command %d",
1755                                         ++m_sec_sequence.current()->cmd);
1756                                 ++m_sec_sequence.current();
1757                 }
1758                 if (!m_simulate)
1759                         m_tuneTimer->start(delay,true);
1760         }
1761         if (regFE)
1762                 regFE->dec_use();
1763         if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
1764                 tuneLoop();
1765 }
1766
1767 void eDVBFrontend::setFrontend()
1768 {
1769         if (!m_simulate)
1770         {
1771                 eDebug("setting frontend %d", m_dvbid);
1772                 m_sn->start();
1773                 feEvent(-1);
1774                 if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1775                 {
1776                         perror("FE_SET_FRONTEND failed");
1777                         return;
1778                 }
1779         }
1780 }
1781
1782 RESULT eDVBFrontend::getFrontendType(int &t)
1783 {
1784         if (m_type == -1)
1785                 return -ENODEV;
1786         t = m_type;
1787         return 0;
1788 }
1789
1790 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1791 {
1792         int res;
1793         if (!m_sec)
1794         {
1795                 eWarning("no SEC module active!");
1796                 return -ENOENT;
1797         }
1798         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1799         if (!res)
1800         {
1801                 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1802                         feparm.system,
1803                         feparm.frequency,
1804                         feparm.polarisation,
1805                         feparm.symbol_rate,
1806                         feparm.inversion,
1807                         feparm.fec,
1808                         feparm.orbital_position);
1809                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1810                 switch (feparm.inversion)
1811                 {
1812                         case eDVBFrontendParametersSatellite::Inversion::On:
1813                                 parm_inversion = INVERSION_ON;
1814                                 break;
1815                         case eDVBFrontendParametersSatellite::Inversion::Off:
1816                                 parm_inversion = INVERSION_OFF;
1817                                 break;
1818                         default:
1819                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1820                                 parm_inversion = INVERSION_AUTO;
1821                                 break;
1822                 }
1823                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1824                         switch (feparm.fec)
1825                         {
1826                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1827                                         parm_u_qpsk_fec_inner = FEC_NONE;
1828                                         break;
1829                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1830                                         parm_u_qpsk_fec_inner = FEC_1_2;
1831                                         break;
1832                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1833                                         parm_u_qpsk_fec_inner = FEC_2_3;
1834                                         break;
1835                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1836                                         parm_u_qpsk_fec_inner = FEC_3_4;
1837                                         break;
1838                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1839                                         parm_u_qpsk_fec_inner = FEC_5_6;
1840                                         break;
1841                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1842                                         parm_u_qpsk_fec_inner = FEC_7_8;
1843                                         break;
1844                                 default:
1845                                         eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
1846                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1847                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1848                                         break;
1849                         }
1850 #if HAVE_DVB_API_VERSION >= 3
1851                 else // DVB_S2
1852                 {
1853                         switch (feparm.fec)
1854                         {
1855                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1856                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1857                                         break;
1858                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1859                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1860                                         break;
1861                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1862                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1863                                         break;
1864                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1865                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1866                                         break;
1867                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1868                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1869                                         break;
1870                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1871                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1872                                         break;
1873                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1874                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1875                                         break;
1876                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1877                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1878                                         break;
1879                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1880                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1881                                         break;
1882                                 default:
1883                                         eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
1884                                         return -EINVAL;
1885                         }
1886                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1887                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1888                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1889                                 // 8PSK fec driver values are decimal 9 bigger
1890                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1891                         }
1892                 }
1893 #endif
1894                 // FIXME !!! get frequency range from tuner
1895                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1896                 {
1897                         eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1898                         return -EINVAL;
1899                 }
1900                 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
1901         }
1902         return res;
1903 }
1904
1905 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1906 {
1907 #if HAVE_DVB_API_VERSION < 3
1908         parm_frequency = feparm.frequency;
1909 #else
1910         parm_frequency = feparm.frequency * 1000;
1911 #endif
1912         parm_u_qam_symbol_rate = feparm.symbol_rate;
1913         switch (feparm.modulation)
1914         {
1915         case eDVBFrontendParametersCable::Modulation::QAM16:
1916                 parm_u_qam_modulation = QAM_16;
1917                 break;
1918         case eDVBFrontendParametersCable::Modulation::QAM32:
1919                 parm_u_qam_modulation = QAM_32;
1920                 break;
1921         case eDVBFrontendParametersCable::Modulation::QAM64:
1922                 parm_u_qam_modulation = QAM_64;
1923                 break;
1924         case eDVBFrontendParametersCable::Modulation::QAM128:
1925                 parm_u_qam_modulation = QAM_128;
1926                 break;
1927         case eDVBFrontendParametersCable::Modulation::QAM256:
1928                 parm_u_qam_modulation = QAM_256;
1929                 break;
1930         default:
1931         case eDVBFrontendParametersCable::Modulation::Auto:
1932                 parm_u_qam_modulation = QAM_AUTO;
1933                 break;
1934         }
1935         switch (feparm.inversion)
1936         {
1937         case eDVBFrontendParametersCable::Inversion::On:
1938                 parm_inversion = INVERSION_ON;
1939                 break;
1940         case eDVBFrontendParametersCable::Inversion::Off:
1941                 parm_inversion = INVERSION_OFF;
1942                 break;
1943         default:
1944         case eDVBFrontendParametersCable::Inversion::Unknown:
1945                 parm_inversion = INVERSION_AUTO;
1946                 break;
1947         }
1948         switch (feparm.fec_inner)
1949         {
1950         case eDVBFrontendParametersCable::FEC::fNone:
1951                 parm_u_qam_fec_inner = FEC_NONE;
1952                 break;
1953         case eDVBFrontendParametersCable::FEC::f1_2:
1954                 parm_u_qam_fec_inner = FEC_1_2;
1955                 break;
1956         case eDVBFrontendParametersCable::FEC::f2_3:
1957                 parm_u_qam_fec_inner = FEC_2_3;
1958                 break;
1959         case eDVBFrontendParametersCable::FEC::f3_4:
1960                 parm_u_qam_fec_inner = FEC_3_4;
1961                 break;
1962         case eDVBFrontendParametersCable::FEC::f5_6:
1963                 parm_u_qam_fec_inner = FEC_5_6;
1964                 break;
1965         case eDVBFrontendParametersCable::FEC::f7_8:
1966                 parm_u_qam_fec_inner = FEC_7_8;
1967                 break;
1968 #if HAVE_DVB_API_VERSION >= 3
1969         case eDVBFrontendParametersCable::FEC::f8_9:
1970                 parm_u_qam_fec_inner = FEC_8_9;
1971                 break;
1972 #endif
1973         default:
1974         case eDVBFrontendParametersCable::FEC::fAuto:
1975                 parm_u_qam_fec_inner = FEC_AUTO;
1976                 break;
1977         }
1978         eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1979                 parm_frequency/1000,
1980                 parm_u_qam_symbol_rate,
1981                 parm_u_qam_fec_inner,
1982                 parm_u_qam_modulation,
1983                 parm_inversion);
1984         return 0;
1985 }
1986
1987 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1988 {
1989         parm_frequency = feparm.frequency;
1990
1991         switch (feparm.bandwidth)
1992         {
1993         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1994                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1995                 break;
1996         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1997                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1998                 break;
1999         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
2000                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2001                 break;
2002         default:
2003         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
2004                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2005                 break;
2006         }
2007         switch (feparm.code_rate_LP)
2008         {
2009         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2010                 parm_u_ofdm_code_rate_LP = FEC_1_2;
2011                 break;
2012         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2013                 parm_u_ofdm_code_rate_LP = FEC_2_3;
2014                 break;
2015         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2016                 parm_u_ofdm_code_rate_LP = FEC_3_4;
2017                 break;
2018         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2019                 parm_u_ofdm_code_rate_LP = FEC_5_6;
2020                 break;
2021         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2022                 parm_u_ofdm_code_rate_LP = FEC_7_8;
2023                 break;
2024         default:
2025         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2026                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2027                 break;
2028         }
2029         switch (feparm.code_rate_HP)
2030         {
2031         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2032                 parm_u_ofdm_code_rate_HP = FEC_1_2;
2033                 break;
2034         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2035                 parm_u_ofdm_code_rate_HP = FEC_2_3;
2036                 break;
2037         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2038                 parm_u_ofdm_code_rate_HP = FEC_3_4;
2039                 break;
2040         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2041                 parm_u_ofdm_code_rate_HP = FEC_5_6;
2042                 break;
2043         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2044                 parm_u_ofdm_code_rate_HP = FEC_7_8;
2045                 break;
2046         default:
2047         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2048                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2049                 break;
2050         }
2051         switch (feparm.modulation)
2052         {
2053         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
2054                 parm_u_ofdm_constellation = QPSK;
2055                 break;
2056         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
2057                 parm_u_ofdm_constellation = QAM_16;
2058                 break;
2059         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
2060                 parm_u_ofdm_constellation = QAM_64;
2061                 break;
2062         default:
2063         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
2064                 parm_u_ofdm_constellation = QAM_AUTO;
2065                 break;
2066         }
2067         switch (feparm.transmission_mode)
2068         {
2069         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
2070                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2071                 break;
2072         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
2073                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2074                 break;
2075         default:
2076         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
2077                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2078                 break;
2079         }
2080         switch (feparm.guard_interval)
2081         {
2082                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
2083                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2084                         break;
2085                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2086                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2087                         break;
2088                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2089                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2090                         break;
2091                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2092                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2093                         break;
2094                 default:
2095                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2096                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2097                         break;
2098         }
2099         switch (feparm.hierarchy)
2100         {
2101                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2102                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2103                         break;
2104                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2105                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2106                         break;
2107                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2108                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2109                         break;
2110                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2111                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2112                         break;
2113                 default:
2114                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2115                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2116                         break;
2117         }
2118         switch (feparm.inversion)
2119         {
2120         case eDVBFrontendParametersTerrestrial::Inversion::On:
2121                 parm_inversion = INVERSION_ON;
2122                 break;
2123         case eDVBFrontendParametersTerrestrial::Inversion::Off:
2124                 parm_inversion = INVERSION_OFF;
2125                 break;
2126         default:
2127         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2128                 parm_inversion = INVERSION_AUTO;
2129                 break;
2130         }
2131         return 0;
2132 }
2133
2134 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2135 {
2136         unsigned int timeout = 5000;
2137         eDebugNoSimulate("(%d)tune", m_dvbid);
2138
2139         m_timeout->stop();
2140
2141         int res=0;
2142
2143         if (!m_sn && !m_simulate)
2144         {
2145                 eDebug("no frontend device opened... do not try to tune !!!");
2146                 res = -ENODEV;
2147                 goto tune_error;
2148         }
2149
2150         if (m_type == -1)
2151         {
2152                 res = -ENODEV;
2153                 goto tune_error;
2154         }
2155
2156         if (!m_simulate)
2157                 m_sn->stop();
2158
2159         m_sec_sequence.clear();
2160
2161         where.calcLockTimeout(timeout);
2162
2163         switch (m_type)
2164         {
2165         case feSatellite:
2166         {
2167                 eDVBFrontendParametersSatellite feparm;
2168                 if (where.getDVBS(feparm))
2169                 {
2170                         eDebug("no dvbs data!");
2171                         res = -EINVAL;
2172                         goto tune_error;
2173                 }
2174                 if (!m_simulate)
2175                         m_sec->setRotorMoving(false);
2176                 res=prepare_sat(feparm, timeout);
2177                 if (res)
2178                         goto tune_error;
2179
2180                 break;
2181         }
2182         case feCable:
2183         {
2184                 eDVBFrontendParametersCable feparm;
2185                 if (where.getDVBC(feparm))
2186                 {
2187                         res = -EINVAL;
2188                         goto tune_error;
2189                 }
2190                 res=prepare_cable(feparm);
2191                 if (res)
2192                         goto tune_error;
2193
2194                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2195                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2196                 break;
2197         }
2198         case feTerrestrial:
2199         {
2200                 eDVBFrontendParametersTerrestrial feparm;
2201                 if (where.getDVBT(feparm))
2202                 {
2203                         eDebug("no -T data");
2204                         res = -EINVAL;
2205                         goto tune_error;
2206                 }
2207                 res=prepare_terrestrial(feparm);
2208                 if (res)
2209                         goto tune_error;
2210
2211                 std::string enable_5V;
2212                 char configStr[255];
2213                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2214                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2215                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2216                 if (enable_5V == "True")
2217                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2218                 else
2219                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2220                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2221
2222                 break;
2223         }
2224         }
2225
2226         m_sec_sequence.current() = m_sec_sequence.begin();
2227
2228         if (!m_simulate)
2229         {
2230                 m_tuneTimer->start(0,true);
2231                 if (m_state != stateTuning)
2232                 {
2233                         m_tuning = 1;
2234                         m_state = stateTuning;
2235                         m_stateChanged(this);
2236                 }
2237         }
2238         else
2239                 tuneLoop();
2240
2241         return res;
2242
2243 tune_error:
2244         m_tuneTimer->stop();
2245         return res;
2246 }
2247
2248 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2249 {
2250         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2251         return 0;
2252 }
2253
2254 RESULT eDVBFrontend::setVoltage(int voltage)
2255 {
2256         if (m_type == feCable)
2257                 return -1;
2258 #if HAVE_DVB_API_VERSION < 3
2259         secVoltage vlt;
2260 #else
2261         bool increased=false;
2262         fe_sec_voltage_t vlt;
2263 #endif
2264         m_data[CUR_VOLTAGE]=voltage;
2265         switch (voltage)
2266         {
2267         case voltageOff:
2268                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2269                 vlt = SEC_VOLTAGE_OFF;
2270                 break;
2271         case voltage13_5:
2272 #if HAVE_DVB_API_VERSION < 3
2273                 vlt = SEC_VOLTAGE_13_5;
2274                 break;
2275 #else
2276                 increased = true;
2277 #endif
2278         case voltage13:
2279                 vlt = SEC_VOLTAGE_13;
2280                 break;
2281         case voltage18_5:
2282 #if HAVE_DVB_API_VERSION < 3
2283                 vlt = SEC_VOLTAGE_18_5;
2284                 break;
2285 #else
2286                 increased = true;
2287 #endif
2288         case voltage18:
2289                 vlt = SEC_VOLTAGE_18;
2290                 break;
2291         default:
2292                 return -ENODEV;
2293         }
2294         if (m_simulate)
2295                 return 0;
2296 #if HAVE_DVB_API_VERSION < 3
2297         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2298 #else
2299         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2300                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2301         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2302 #endif
2303 }
2304
2305 RESULT eDVBFrontend::getState(int &state)
2306 {
2307         state = m_state;
2308         return 0;
2309 }
2310
2311 RESULT eDVBFrontend::setTone(int t)
2312 {
2313         if (m_type != feSatellite)
2314                 return -1;
2315 #if HAVE_DVB_API_VERSION < 3
2316         secToneMode_t tone;
2317 #else
2318         fe_sec_tone_mode_t tone;
2319 #endif
2320         m_data[CUR_TONE]=t;
2321         switch (t)
2322         {
2323         case toneOn:
2324                 tone = SEC_TONE_ON;
2325                 break;
2326         case toneOff:
2327                 tone = SEC_TONE_OFF;
2328                 break;
2329         default:
2330                 return -ENODEV;
2331         }
2332         if (m_simulate)
2333                 return 0;
2334 #if HAVE_DVB_API_VERSION < 3    
2335         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2336 #else   
2337         return ::ioctl(m_fd, FE_SET_TONE, tone);
2338 #endif
2339 }
2340
2341 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2342         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2343 #endif
2344
2345 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2346 {
2347         if (m_simulate)
2348                 return 0;
2349 #if HAVE_DVB_API_VERSION < 3
2350         struct secCommand cmd;
2351         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2352         cmd.u.diseqc.cmdtype = diseqc.data[0];
2353         cmd.u.diseqc.addr = diseqc.data[1];
2354         cmd.u.diseqc.cmd = diseqc.data[2];
2355         cmd.u.diseqc.numParams = diseqc.len-3;
2356         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2357         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2358 #else
2359         struct dvb_diseqc_master_cmd cmd;
2360         memcpy(cmd.msg, diseqc.data, diseqc.len);
2361         cmd.msg_len = diseqc.len;
2362         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2363 #endif
2364                 return -EINVAL;
2365         return 0;
2366 }
2367
2368 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2369         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2370 #endif
2371 RESULT eDVBFrontend::sendToneburst(int burst)
2372 {
2373         if (m_simulate)
2374                 return 0;
2375 #if HAVE_DVB_API_VERSION < 3
2376         secMiniCmd cmd = SEC_MINI_NONE;
2377 #else
2378         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2379 #endif
2380         if ( burst == eDVBSatelliteDiseqcParameters::A )
2381                 cmd = SEC_MINI_A;
2382         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2383                 cmd = SEC_MINI_B;
2384 #if HAVE_DVB_API_VERSION < 3
2385         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2386                 return -EINVAL;
2387 #else
2388         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2389                 return -EINVAL;
2390 #endif
2391         return 0;
2392 }
2393
2394 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2395 {
2396         m_sec = sec;
2397         return 0;
2398 }
2399
2400 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2401 {
2402         m_sec_sequence = list;
2403         return 0;
2404 }
2405
2406 RESULT eDVBFrontend::getData(int num, long &data)
2407 {
2408         if ( num < NUM_DATA_ENTRIES )
2409         {
2410                 data = m_data[num];
2411                 return 0;
2412         }
2413         return -EINVAL;
2414 }
2415
2416 RESULT eDVBFrontend::setData(int num, long val)
2417 {
2418         if ( num < NUM_DATA_ENTRIES )
2419         {
2420                 m_data[num] = val;
2421                 return 0;
2422         }
2423         return -EINVAL;
2424 }
2425
2426 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2427 {
2428         int type;
2429         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2430                 return 0;
2431         if (m_type == eDVBFrontend::feSatellite)
2432         {
2433                 ASSERT(m_sec);
2434                 eDVBFrontendParametersSatellite sat_parm;
2435                 int ret = feparm->getDVBS(sat_parm);
2436                 ASSERT(!ret);
2437                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2438                         return 0;
2439                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2440                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2441                         ret -= 1;
2442                 return ret;
2443         }
2444         else if (m_type == eDVBFrontend::feCable)
2445                 return 2;  // more prio for cable frontends
2446         else if (m_type == eDVBFrontend::feTerrestrial)
2447                 return 1;
2448         return 0;
2449 }
2450
2451 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2452 {
2453         ePyObject Id, Descr, Enabled, IsDVBS2;
2454         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2455                 goto arg_error;
2456         Id = PyTuple_GET_ITEM(obj, 0);
2457         Descr = PyTuple_GET_ITEM(obj, 1);
2458         Enabled = PyTuple_GET_ITEM(obj, 2);
2459         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2460         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2461                 goto arg_error;
2462         strcpy(m_description, PyString_AS_STRING(Descr));
2463         m_slotid = PyInt_AsLong(Id);
2464         m_enabled = Enabled == Py_True;
2465         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2466         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2467                 !!strstr(m_description, "Alps BSBE2") ||
2468                 !!strstr(m_description, "Alps -S") ||
2469                 !!strstr(m_description, "BCM4501");
2470         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2471         eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2472                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2473         return true;
2474 arg_error:
2475         PyErr_SetString(PyExc_StandardError,
2476                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2477         return false;
2478 }