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