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