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