small SNRdb correction for latest 4501 firmware
[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                                 ret -= 150; // -1.5db for latest bcm4501 firmware..
784                         }
785                         else if (strstr(m_description, "Alps BSBE1 C01A") ||
786                                 !strcmp(m_description, "Alps -S(STV0288)"))
787                         {
788                                 if (snr == 0)
789                                         ret = 0;
790                                 else if (snr == 0xFFFF) // i think this should not happen
791                                         ret = 100*100;
792                                 else
793                                 {
794                                         enum { REALVAL, REGVAL };
795                                         const long CN_lookup[31][2] = {
796                                                 {20,8900}, {25,8680}, {30,8420}, {35,8217}, {40,7897},
797                                                 {50,7333}, {60,6747}, {70,6162}, {80,5580}, {90,5029},
798                                                 {100,4529}, {110,4080}, {120,3685}, {130,3316}, {140,2982},
799                                                 {150,2688}, {160,2418}, {170,2188}, {180,1982}, {190,1802},
800                                                 {200,1663}, {210,1520}, {220,1400}, {230,1295}, {240,1201},
801                                                 {250,1123}, {260,1058}, {270,1004}, {280,957}, {290,920},
802                                                 {300,890}
803                                         };
804                                         int add=strchr(m_description, '.') ? 0xA250 : 0xA100;
805                                         long regval = 0xFFFF - ((snr / 3) + add), // revert some dvb api calulations to get the real register value
806                                                 Imin=0,
807                                                 Imax=30,
808                                                 i;
809                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[Imax][REGVAL]))
810                                         {
811                                                 while((Imax-Imin)>1)
812                                                 {
813                                                         i=(Imax+Imin)/2;
814                                                         if(INRANGE(CN_lookup[Imin][REGVAL],regval,CN_lookup[i][REGVAL]))
815                                                                 Imax = i;
816                                                         else
817                                                                 Imin = i;
818                                                 }
819                                                 ret = (((regval - CN_lookup[Imin][REGVAL])
820                                                                 * (CN_lookup[Imax][REALVAL] - CN_lookup[Imin][REALVAL])
821                                                                 / (CN_lookup[Imax][REGVAL] - CN_lookup[Imin][REGVAL]))
822                                                                 + CN_lookup[Imin][REALVAL]) * 10;
823                                         }
824                                         else
825                                                 ret = 100;
826                                 }
827                         }
828                         else if (!strcmp(m_description, "Alps BSBE1 702A") ||  // some frontends with STV0299
829                                 !strcmp(m_description, "Alps -S") ||
830                                 !strcmp(m_description, "Philips -S") ||
831                                 !strcmp(m_description, "LG -S") )
832                         {
833                                 ret = (int)((snr-39075)/17.647);
834                         } else if (!strcmp(m_description, "Alps BSBE2"))
835                         {
836                                 ret = (int)((snr >> 7) * 10);
837                         } else if (!strcmp(m_description, "Philips CU1216Mk3"))
838                         {
839                                 int mse = (~snr) & 0xFF;
840                                 switch (parm_u_qam_modulation) {
841                                 case QAM_16: ret = fe_udiv(1950000, (32 * mse) + 138) + 1000; break;
842                                 case QAM_32: ret = fe_udiv(2150000, (40 * mse) + 500) + 1350; break;
843                                 case QAM_64: ret = fe_udiv(2100000, (40 * mse) + 500) + 1250; break;
844                                 case QAM_128: ret = fe_udiv(1850000, (38 * mse) + 400) + 1380; break;
845                                 case QAM_256: ret = fe_udiv(1800000, (100 * mse) + 40) + 2030; break;
846                                 default: break;
847                                 }
848                         } else if (!strcmp(m_description, "Philips TU1216"))
849                         {
850                                 snr = 0xFF - (snr & 0xFF);
851                                 if (snr != 0)
852                                         ret = 10 * (int)(-100 * (log10(snr) - log10(255)));
853                         }
854
855                         if (type == signalQuality)
856                         {
857                                 if (ret == 0x12345678) // no snr db calculation avail.. return untouched snr value..
858                                         return snr;
859                                 switch(m_type)
860                                 {
861                                         case feSatellite: // we assume a max of 16.0db here
862                                                 return ret >= 1600 ? 65536 : ret * 65536 / 1600;
863                                         case feCable: // we assume a max of 42db here
864                                                 return ret >= 4200 ? 65536 : ret * 65536 / 4200;
865                                         case feTerrestrial: // we assume a max of 24db here
866                                                 return ret >= 2400 ? 65536 : ret * 65536 / 2400;
867                                 }
868                         }
869 /* else
870                                 eDebug("no SNR dB calculation for frontendtype %s yet", m_description); */
871                         return ret;
872                 }
873                 case signalPower:
874                 {
875                         uint16_t strength=0;
876                         if (!m_simulate)
877                         {
878                                 if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
879                                         eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
880                         }
881                         return strength;
882                 }
883                 case locked:
884                 {
885 #if HAVE_DVB_API_VERSION < 3
886                         FrontendStatus status=0;
887 #else
888                         fe_status_t status;
889 #endif
890                         if (!m_simulate)
891                         {
892                                 if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
893                                         eDebug("FE_READ_STATUS failed (%m)");
894                                 return !!(status&FE_HAS_LOCK);
895                         }
896                         return 1;
897                 }
898                 case synced:
899                 {
900 #if HAVE_DVB_API_VERSION < 3
901                         FrontendStatus status=0;
902 #else
903                         fe_status_t status;
904 #endif
905                         if (!m_simulate)
906                         {
907                                 if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
908                                         eDebug("FE_READ_STATUS failed (%m)");
909                                 return !!(status&FE_HAS_SYNC);
910                         }
911                         return 1;
912                 }
913                 case frontendNumber:
914                         return m_slotid;
915         }
916         return 0;
917 }
918
919 void PutToDict(ePyObject &dict, const char*key, long value)
920 {
921         ePyObject item = PyInt_FromLong(value);
922         if (item)
923         {
924                 if (PyDict_SetItemString(dict, key, item))
925                         eDebug("put %s to dict failed", key);
926                 Py_DECREF(item);
927         }
928         else
929                 eDebug("could not create PyObject for %s", key);
930 }
931
932 void PutToDict(ePyObject &dict, const char*key, ePyObject item)
933 {
934         if (item)
935         {
936                 if (PyDict_SetItemString(dict, key, item))
937                         eDebug("put %s to dict failed", key);
938                 Py_DECREF(item);
939         }
940         else
941                 eDebug("invalid PyObject for %s", key);
942 }
943
944 void PutToDict(ePyObject &dict, const char*key, const char *value)
945 {
946         ePyObject item = PyString_FromString(value);
947         if (item)
948         {
949                 if (PyDict_SetItemString(dict, key, item))
950                         eDebug("put %s to dict failed", key);
951                 Py_DECREF(item);
952         }
953         else
954                 eDebug("could not create PyObject for %s", key);
955 }
956
957 void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
958 {
959         long freq_offset=0;
960         const char *tmp=0;
961         fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
962         int frequency = parm_frequency + freq_offset;
963         PutToDict(dict, "frequency", frequency);
964         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
965         switch(parm_u_qpsk_fec_inner)
966         {
967         case FEC_1_2:
968                 tmp = "FEC_1_2";
969                 break;
970         case FEC_2_3:
971                 tmp = "FEC_2_3";
972                 break;
973         case FEC_3_4:
974                 tmp = "FEC_3_4";
975                 break;
976         case FEC_5_6:
977                 tmp = "FEC_5_6";
978                 break;
979         case FEC_7_8:
980                 tmp = "FEC_7_8";
981                 break;
982         case FEC_NONE:
983                 tmp = "FEC_NONE";
984         default:
985         case FEC_AUTO:
986                 tmp = "FEC_AUTO";
987                 break;
988 #if HAVE_DVB_API_VERSION >=3
989         case FEC_S2_8PSK_1_2:
990         case FEC_S2_QPSK_1_2:
991                 tmp = "FEC_1_2";
992                 break;
993         case FEC_S2_8PSK_2_3:
994         case FEC_S2_QPSK_2_3:
995                 tmp = "FEC_2_3";
996                 break;
997         case FEC_S2_8PSK_3_4:
998         case FEC_S2_QPSK_3_4:
999                 tmp = "FEC_3_4";
1000                 break;
1001         case FEC_S2_8PSK_5_6:
1002         case FEC_S2_QPSK_5_6:
1003                 tmp = "FEC_5_6";
1004                 break;
1005         case FEC_S2_8PSK_7_8:
1006         case FEC_S2_QPSK_7_8:
1007                 tmp = "FEC_7_8";
1008                 break;
1009         case FEC_S2_8PSK_8_9:
1010         case FEC_S2_QPSK_8_9:
1011                 tmp = "FEC_8_9";
1012                 break;
1013         case FEC_S2_8PSK_3_5:
1014         case FEC_S2_QPSK_3_5:
1015                 tmp = "FEC_3_5";
1016                 break;
1017         case FEC_S2_8PSK_4_5:
1018         case FEC_S2_QPSK_4_5:
1019                 tmp = "FEC_4_5";
1020                 break;
1021         case FEC_S2_8PSK_9_10:
1022         case FEC_S2_QPSK_9_10:
1023                 tmp = "FEC_9_10";
1024                 break;
1025 #endif
1026         }
1027         PutToDict(dict, "fec_inner", tmp);
1028 #if HAVE_DVB_API_VERSION >=3
1029         PutToDict(dict, "modulation",
1030                 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
1031         if (parm_u_qpsk_fec_inner > FEC_AUTO)
1032         {
1033                 switch(parm_inversion & 0xc)
1034                 {
1035                 default: // unknown rolloff
1036                 case 0: // 0.35
1037                         tmp = "ROLLOFF_0_35";
1038                         break;
1039                 case 4: // 0.25
1040                         tmp = "ROLLOFF_0_25";
1041                         break;
1042                 case 8: // 0.20
1043                         tmp = "ROLLOFF_0_20";
1044                         break;
1045                 }
1046                 PutToDict(dict, "rolloff", tmp);
1047                 switch(parm_inversion & 0x30)
1048                 {
1049                 case 0: // pilot off
1050                         tmp = "PILOT_OFF";
1051                         break;
1052                 case 0x10: // pilot on
1053                         tmp = "PILOT_ON";
1054                         break;
1055                 case 0x20: // pilot auto
1056                         tmp = "PILOT_AUTO";
1057                         break;
1058                 }
1059                 PutToDict(dict, "pilot", tmp);
1060                 tmp = "DVB-S2";
1061         }
1062         else
1063                 tmp = "DVB-S";
1064 #else
1065         PutToDict(dict, "modulation", "QPSK" );
1066         tmp = "DVB-S";
1067 #endif
1068         PutToDict(dict, "system", tmp);
1069 }
1070
1071 void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1072 {
1073         const char *tmp=0;
1074 #if HAVE_DVB_API_VERSION < 3
1075         PutToDict(dict, "frequency", parm_frequency);
1076 #else
1077         PutToDict(dict, "frequency", parm_frequency/1000);
1078 #endif
1079         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
1080         switch(parm_u_qam_fec_inner)
1081         {
1082         case FEC_NONE:
1083                 tmp = "FEC_NONE";
1084                 break;
1085         case FEC_1_2:
1086                 tmp = "FEC_1_2";
1087                 break;
1088         case FEC_2_3:
1089                 tmp = "FEC_2_3";
1090                 break;
1091         case FEC_3_4:
1092                 tmp = "FEC_3_4";
1093                 break;
1094         case FEC_5_6:
1095                 tmp = "FEC_5_6";
1096                 break;
1097         case FEC_7_8:
1098                 tmp = "FEC_7_8";
1099                 break;
1100 #if HAVE_DVB_API_VERSION >= 3
1101         case FEC_8_9:
1102                 tmp = "FEC_8_9";
1103                 break;
1104 #endif
1105         default:
1106         case FEC_AUTO:
1107                 tmp = "FEC_AUTO";
1108                 break;
1109         }
1110         PutToDict(dict, "fec_inner", tmp);
1111         switch(parm_u_qam_modulation)
1112         {
1113         case QAM_16:
1114                 tmp = "QAM_16";
1115                 break;
1116         case QAM_32:
1117                 tmp = "QAM_32";
1118                 break;
1119         case QAM_64:
1120                 tmp = "QAM_64";
1121                 break;
1122         case QAM_128:
1123                 tmp = "QAM_128";
1124                 break;
1125         case QAM_256:
1126                 tmp = "QAM_256";
1127                 break;
1128         default:
1129         case QAM_AUTO:
1130                 tmp = "QAM_AUTO";
1131                 break;
1132         }
1133         PutToDict(dict, "modulation", tmp);
1134 }
1135
1136 void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
1137 {
1138         const char *tmp=0;
1139         PutToDict(dict, "frequency", parm_frequency);
1140         switch (parm_u_ofdm_bandwidth)
1141         {
1142         case BANDWIDTH_8_MHZ:
1143                 tmp = "BANDWIDTH_8_MHZ";
1144                 break;
1145         case BANDWIDTH_7_MHZ:
1146                 tmp = "BANDWIDTH_7_MHZ";
1147                 break;
1148         case BANDWIDTH_6_MHZ:
1149                 tmp = "BANDWIDTH_6_MHZ";
1150                 break;
1151         default:
1152         case BANDWIDTH_AUTO:
1153                 tmp = "BANDWIDTH_AUTO";
1154                 break;
1155         }
1156         PutToDict(dict, "bandwidth", tmp);
1157         switch (parm_u_ofdm_code_rate_LP)
1158         {
1159         case FEC_1_2:
1160                 tmp = "FEC_1_2";
1161                 break;
1162         case FEC_2_3:
1163                 tmp = "FEC_2_3";
1164                 break;
1165         case FEC_3_4:
1166                 tmp = "FEC_3_4";
1167                 break;
1168         case FEC_5_6:
1169                 tmp = "FEC_5_6";
1170                 break;
1171         case FEC_7_8:
1172                 tmp = "FEC_7_8";
1173                 break;
1174         default:
1175         case FEC_AUTO:
1176                 tmp = "FEC_AUTO";
1177                 break;
1178         }
1179         PutToDict(dict, "code_rate_lp", tmp);
1180         switch (parm_u_ofdm_code_rate_HP)
1181         {
1182         case FEC_1_2:
1183                 tmp = "FEC_1_2";
1184                 break;
1185         case FEC_2_3:
1186                 tmp = "FEC_2_3";
1187                 break;
1188         case FEC_3_4:
1189                 tmp = "FEC_3_4";
1190                 break;
1191         case FEC_5_6:
1192                 tmp = "FEC_5_6";
1193                 break;
1194         case FEC_7_8:
1195                 tmp = "FEC_7_8";
1196                 break;
1197         default:
1198         case FEC_AUTO:
1199                 tmp = "FEC_AUTO";
1200                 break;
1201         }
1202         PutToDict(dict, "code_rate_hp", tmp);
1203         switch (parm_u_ofdm_constellation)
1204         {
1205         case QPSK:
1206                 tmp = "QPSK";
1207                 break;
1208         case QAM_16:
1209                 tmp = "QAM_16";
1210                 break;
1211         case QAM_64:
1212                 tmp = "QAM_64";
1213                 break;
1214         default:
1215         case QAM_AUTO:
1216                 tmp = "QAM_AUTO";
1217                 break;
1218         }
1219         PutToDict(dict, "constellation", tmp);
1220         switch (parm_u_ofdm_transmission_mode)
1221         {
1222         case TRANSMISSION_MODE_2K:
1223                 tmp = "TRANSMISSION_MODE_2K";
1224                 break;
1225         case TRANSMISSION_MODE_8K:
1226                 tmp = "TRANSMISSION_MODE_8K";
1227                 break;
1228         default:
1229         case TRANSMISSION_MODE_AUTO:
1230                 tmp = "TRANSMISSION_MODE_AUTO";
1231                 break;
1232         }
1233         PutToDict(dict, "transmission_mode", tmp);
1234         switch (parm_u_ofdm_guard_interval)
1235         {
1236                 case GUARD_INTERVAL_1_32:
1237                         tmp = "GUARD_INTERVAL_1_32";
1238                         break;
1239                 case GUARD_INTERVAL_1_16:
1240                         tmp = "GUARD_INTERVAL_1_16";
1241                         break;
1242                 case GUARD_INTERVAL_1_8:
1243                         tmp = "GUARD_INTERVAL_1_8";
1244                         break;
1245                 case GUARD_INTERVAL_1_4:
1246                         tmp = "GUARD_INTERVAL_1_4";
1247                         break;
1248                 default:
1249                 case GUARD_INTERVAL_AUTO:
1250                         tmp = "GUARD_INTERVAL_AUTO";
1251                         break;
1252         }
1253         PutToDict(dict, "guard_interval", tmp);
1254         switch (parm_u_ofdm_hierarchy_information)
1255         {
1256                 case HIERARCHY_NONE:
1257                         tmp = "HIERARCHY_NONE";
1258                         break;
1259                 case HIERARCHY_1:
1260                         tmp = "HIERARCHY_1";
1261                         break;
1262                 case HIERARCHY_2:
1263                         tmp = "HIERARCHY_2";
1264                         break;
1265                 case HIERARCHY_4:
1266                         tmp = "HIERARCHY_4";
1267                         break;
1268                 default:
1269                 case HIERARCHY_AUTO:
1270                         tmp = "HIERARCHY_AUTO";
1271                         break;
1272         }
1273         PutToDict(dict, "hierarchy_information", tmp);
1274 }
1275
1276 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1277 {
1278         if (dest && PyDict_Check(dest))
1279         {
1280                 const char *tmp = "UNKNOWN";
1281                 switch(m_state)
1282                 {
1283                         case stateIdle:
1284                                 tmp="IDLE";
1285                                 break;
1286                         case stateTuning:
1287                                 tmp="TUNING";
1288                                 break;
1289                         case stateFailed:
1290                                 tmp="FAILED";
1291                                 break;
1292                         case stateLock:
1293                                 tmp="LOCKED";
1294                                 break;
1295                         case stateLostLock:
1296                                 tmp="LOSTLOCK";
1297                                 break;
1298                         default:
1299                                 break;
1300                 }
1301                 PutToDict(dest, "tuner_state", tmp);
1302                 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1303                 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1304                 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1305                 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1306                 int sigQualitydB = readFrontendData(signalQualitydB);
1307                 if (sigQualitydB == 0x12345678) // not support yet
1308                 {
1309                         ePyObject obj=Py_None;
1310                         Py_INCREF(obj);
1311                         PutToDict(dest, "tuner_signal_quality_db", obj);
1312                 }
1313                 else
1314                         PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1315                 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1316         }
1317 }
1318
1319 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1320 {
1321         if (dest && PyDict_Check(dest))
1322         {
1323                 switch(m_type)
1324                 {
1325                         case feSatellite:
1326                         case feCable:
1327                         case feTerrestrial:
1328                         {
1329                                 FRONTENDPARAMETERS front;
1330                                 if (m_fd == -1 && !original)
1331                                         original = true;
1332                                 else if (ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1333                                 {
1334                                         eDebug("FE_GET_FRONTEND failed (%m)");
1335                                         original = true;
1336                                 }
1337                                 {
1338                                         const FRONTENDPARAMETERS &parm = original || m_simulate ? this->parm : front;
1339                                         const char *tmp = "INVERSION_AUTO";
1340                                         switch(parm_inversion & 3)
1341                                         {
1342                                                 case INVERSION_ON:
1343                                                         tmp = "INVERSION_ON";
1344                                                         break;
1345                                                 case INVERSION_OFF:
1346                                                         tmp = "INVERSION_OFF";
1347                                                         break;
1348                                                 default:
1349                                                         break;
1350                                         }
1351                                         if (tmp)
1352                                                 PutToDict(dest, "inversion", tmp);
1353
1354                                         switch(m_type)
1355                                         {
1356                                                 case feSatellite:
1357                                                         fillDictWithSatelliteData(dest, original?parm:front, this);
1358                                                         break;
1359                                                 case feCable:
1360                                                         fillDictWithCableData(dest, original?parm:front);
1361                                                         break;
1362                                                 case feTerrestrial:
1363                                                         fillDictWithTerrestrialData(dest, original?parm:front);
1364                                                         break;
1365                                         }
1366                                 }
1367                         }
1368                         default:
1369                                 break;
1370                 }
1371         }
1372 }
1373
1374 void eDVBFrontend::getFrontendData(ePyObject dest)
1375 {
1376         if (dest && PyDict_Check(dest))
1377         {
1378                 const char *tmp=0;
1379                 PutToDict(dest, "tuner_number", m_slotid);
1380                 switch(m_type)
1381                 {
1382                         case feSatellite:
1383                                 tmp = "DVB-S";
1384                                 break;
1385                         case feCable:
1386                                 tmp = "DVB-C";
1387                                 break;
1388                         case feTerrestrial:
1389                                 tmp = "DVB-T";
1390                                 break;
1391                         default:
1392                                 tmp = "UNKNOWN";
1393                                 break;
1394                 }
1395                 PutToDict(dest, "tuner_type", tmp);
1396         }
1397 }
1398
1399 #ifndef FP_IOCTL_GET_ID
1400 #define FP_IOCTL_GET_ID 0
1401 #endif
1402 int eDVBFrontend::readInputpower()
1403 {
1404         if (m_simulate)
1405                 return 0;
1406         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1407         char proc_name[64];
1408         sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1409         FILE *f=fopen(proc_name, "r");
1410         if (f)
1411         {
1412                 if (fscanf(f, "%d", &power) != 1)
1413                         eDebug("read %s failed!! (%m)", proc_name);
1414                 else
1415                         eDebug("%s is %d\n", proc_name, power);
1416                 fclose(f);
1417         }
1418         else
1419         {
1420                 // open front prozessor
1421                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1422                 if (fp < 0)
1423                 {
1424                         eDebug("couldn't open fp");
1425                         return -1;
1426                 }
1427                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1428                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1429                 {
1430                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1431                         return -1;
1432                 }
1433                 ::close(fp);
1434         }
1435
1436         return power;
1437 }
1438
1439 bool eDVBFrontend::setSecSequencePos(int steps)
1440 {
1441         eDebugNoSimulate("set sequence pos %d", steps);
1442         if (!steps)
1443                 return false;
1444         while( steps > 0 )
1445         {
1446                 if (m_sec_sequence.current() != m_sec_sequence.end())
1447                         ++m_sec_sequence.current();
1448                 --steps;
1449         }
1450         while( steps < 0 )
1451         {
1452                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1453                         --m_sec_sequence.current();
1454                 ++steps;
1455         }
1456         return true;
1457 }
1458
1459 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1460 {
1461         int delay=0;
1462         eDVBFrontend *sec_fe = this;
1463         eDVBRegisteredFrontend *regFE = 0;
1464         long tmp = m_data[LINKED_PREV_PTR];
1465         while ( tmp != -1 )
1466         {
1467                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1468                 sec_fe = prev->m_frontend;
1469                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1470                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1471                         int state = sec_fe->m_state;
1472                         // workaround to put the kernel frontend thread into idle state!
1473                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1474                         {
1475                                 sec_fe->closeFrontend(true);
1476                                 state = sec_fe->m_state;
1477                         }
1478                         // sec_fe is closed... we must reopen it here..
1479                         if (state == eDVBFrontend::stateClosed)
1480                         {
1481                                 regFE = prev;
1482                                 prev->inc_use();
1483                         }
1484                 }
1485         }
1486
1487         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1488         {
1489                 long *sec_fe_data = sec_fe->m_data;
1490 //              eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1491                 switch (m_sec_sequence.current()->cmd)
1492                 {
1493                         case eSecCommand::SLEEP:
1494                                 delay = m_sec_sequence.current()++->msec;
1495                                 eDebugNoSimulate("[SEC] sleep %dms", delay);
1496                                 break;
1497                         case eSecCommand::GOTO:
1498                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1499                                         ++m_sec_sequence.current();
1500                                 break;
1501                         case eSecCommand::SET_VOLTAGE:
1502                         {
1503                                 int voltage = m_sec_sequence.current()++->voltage;
1504                                 eDebugNoSimulate("[SEC] setVoltage %d", voltage);
1505                                 sec_fe->setVoltage(voltage);
1506                                 break;
1507                         }
1508                         case eSecCommand::IF_VOLTAGE_GOTO:
1509                         {
1510                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1511                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1512                                         break;
1513                                 ++m_sec_sequence.current();
1514                                 break;
1515                         }
1516                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1517                         {
1518                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1519                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1520                                         break;
1521                                 ++m_sec_sequence.current();
1522                                 break;
1523                         }
1524                         case eSecCommand::IF_TONE_GOTO:
1525                         {
1526                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1527                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1528                                         break;
1529                                 ++m_sec_sequence.current();
1530                                 break;
1531                         }
1532                         case eSecCommand::IF_NOT_TONE_GOTO:
1533                         {
1534                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1535                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1536                                         break;
1537                                 ++m_sec_sequence.current();
1538                                 break;
1539                         }
1540                         case eSecCommand::SET_TONE:
1541                                 eDebugNoSimulate("[SEC] setTone %d", m_sec_sequence.current()->tone);
1542                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1543                                 break;
1544                         case eSecCommand::SEND_DISEQC:
1545                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1546                                 eDebugNoSimulateNoNewLine("[SEC] sendDiseqc: ");
1547                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1548                                     eDebugNoSimulateNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1549                                 if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x00", 3))
1550                                         eDebugNoSimulate("(DiSEqC reset)");
1551                                 else if (!memcmp(m_sec_sequence.current()->diseqc.data, "\xE0\x00\x03", 3))
1552                                         eDebugNoSimulate("(DiSEqC peripherial power on)");
1553                                 else
1554                                         eDebugNoSimulate("");
1555                                 ++m_sec_sequence.current();
1556                                 break;
1557                         case eSecCommand::SEND_TONEBURST:
1558                                 eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1559                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1560                                 break;
1561                         case eSecCommand::SET_FRONTEND:
1562                                 eDebugNoSimulate("[SEC] setFrontend");
1563                                 setFrontend();
1564                                 ++m_sec_sequence.current();
1565                                 break;
1566                         case eSecCommand::START_TUNE_TIMEOUT:
1567                         {
1568                                 if (!m_simulate)
1569                                         m_timeout->start(m_sec_sequence.current()->timeout, 1);
1570                                 ++m_sec_sequence.current();
1571                                 break;
1572                         }
1573                         case eSecCommand::SET_TIMEOUT:
1574                                 m_timeoutCount = m_sec_sequence.current()++->val;
1575                                 eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
1576                                 break;
1577                         case eSecCommand::IF_TIMEOUT_GOTO:
1578                                 if (!m_timeoutCount)
1579                                 {
1580                                         eDebugNoSimulate("[SEC] rotor timout");
1581                                         setSecSequencePos(m_sec_sequence.current()->steps);
1582                                 }
1583                                 else
1584                                         ++m_sec_sequence.current();
1585                                 break;
1586                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1587                         {
1588                                 int idx = m_sec_sequence.current()++->val;
1589                                 if ( idx == 0 || idx == 1 )
1590                                 {
1591                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1592                                         eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1593                                 }
1594                                 else
1595                                         eDebugNoSimulate("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1596                                 break;
1597                         }
1598                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1599                         {
1600                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1601                                 int idx = compare.val;
1602                                 if ( !m_simulate && (idx == 0 || idx == 1) )
1603                                 {
1604                                         int idle = sec_fe->readInputpower();
1605                                         int diff = abs(idle-m_idleInputpower[idx]);
1606                                         if ( diff > 0)
1607                                         {
1608                                                 eDebugNoSimulate("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1609                                                 setSecSequencePos(compare.steps);
1610                                                 break;
1611                                         }
1612                                 }
1613                                 ++m_sec_sequence.current();
1614                                 break;
1615                         }
1616                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1617                         {
1618                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1619                                 if (m_simulate)
1620                                 {
1621                                         setSecSequencePos(cmd.steps);
1622                                         break;
1623                                 }
1624                                 int signal = 0;
1625                                 int isLocked = readFrontendData(locked);
1626                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1627                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1628                                 {
1629                                         if (cmd.lastSignal)
1630                                                 eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1631                                         else
1632                                         {
1633                                                 eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
1634                                                 cmd.lastSignal = signal;
1635                                         }
1636                                         ++cmd.okcount;
1637                                         if (cmd.okcount > 4)
1638                                         {
1639                                                 eDebugNoSimulate("ok > 4 .. goto %d\n",cmd.steps);
1640                                                 setSecSequencePos(cmd.steps);
1641                                                 m_state = stateLock;
1642                                                 m_stateChanged(this);
1643                                                 feEvent(-1);
1644                                                 m_sn->start();
1645                                                 break;
1646                                         }
1647                                 }
1648                                 else
1649                                 {
1650                                         if (isLocked)
1651                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1652                                         else
1653                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1654                                         --m_timeoutCount;
1655                                         if (!m_timeoutCount && m_retryCount > 0)
1656                                                 --m_retryCount;
1657                                         cmd.okcount=0;
1658                                         cmd.lastSignal=0;
1659                                 }
1660                                 ++m_sec_sequence.current();
1661                                 break;
1662                         }
1663                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1664                                 m_runningInputpower = sec_fe->readInputpower();
1665                                 eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
1666                                 ++m_sec_sequence.current();
1667                                 break;
1668                         case eSecCommand::SET_ROTOR_MOVING:
1669                                 if (!m_simulate)
1670                                         m_sec->setRotorMoving(true);
1671                                 ++m_sec_sequence.current();
1672                                 break;
1673                         case eSecCommand::SET_ROTOR_STOPPED:
1674                                 if (!m_simulate)
1675                                         m_sec->setRotorMoving(false);
1676                                 ++m_sec_sequence.current();
1677                                 break;
1678                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1679                         {
1680                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1681                                 if (m_simulate)
1682                                 {
1683                                         setSecSequencePos(cmd.steps);
1684                                         break;
1685                                 }
1686                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1687                                 const char *txt = cmd.direction ? "running" : "stopped";
1688                                 eDebugNoSimulate("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1689                                         txt,
1690                                         m_runningInputpower,
1691                                         idleInputpower,
1692                                         cmd.deltaA);
1693                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1694                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1695                                 {
1696                                         ++cmd.okcount;
1697                                         eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1698                                         if ( cmd.okcount > 6 )
1699                                         {
1700                                                 eDebugNoSimulate("[SEC] rotor is %s", txt);
1701                                                 if (setSecSequencePos(cmd.steps))
1702                                                         break;
1703                                         }
1704                                 }
1705                                 else
1706                                 {
1707                                         eDebugNoSimulate("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1708                                         --m_timeoutCount;
1709                                         if (!m_timeoutCount && m_retryCount > 0)
1710                                                 --m_retryCount;
1711                                         cmd.okcount=0;
1712                                 }
1713                                 ++m_sec_sequence.current();
1714                                 break;
1715                         }
1716                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1717                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1718                                         setSecSequencePos(m_sec_sequence.current()->steps);
1719                                 else
1720                                         ++m_sec_sequence.current();
1721                                 break;
1722                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1723                                 eDebugNoSimulate("[SEC] invalidate current switch params");
1724                                 sec_fe_data[CSW] = -1;
1725                                 sec_fe_data[UCSW] = -1;
1726                                 sec_fe_data[TONEBURST] = -1;
1727                                 ++m_sec_sequence.current();
1728                                 break;
1729                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1730                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1731                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1732                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1733                                 eDebugNoSimulate("[SEC] update current switch params");
1734                                 ++m_sec_sequence.current();
1735                                 break;
1736                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1737                                 eDebugNoSimulate("[SEC] invalidate current rotorparams");
1738                                 sec_fe_data[ROTOR_CMD] = -1;
1739                                 sec_fe_data[ROTOR_POS] = -1;
1740                                 ++m_sec_sequence.current();
1741                                 break;
1742                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1743                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1744                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1745                                 eDebugNoSimulate("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1746                                 ++m_sec_sequence.current();
1747                                 break;
1748                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1749                                 m_retryCount = m_sec_sequence.current()++->val;
1750                                 eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
1751                                 break;
1752                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1753                                 if (!m_retryCount)
1754                                 {
1755                                         eDebugNoSimulate("[SEC] no more rotor retrys");
1756                                         setSecSequencePos(m_sec_sequence.current()->steps);
1757                                 }
1758                                 else
1759                                         ++m_sec_sequence.current();
1760                                 break;
1761                         case eSecCommand::SET_POWER_LIMITING_MODE:
1762                         {
1763                                 if (!m_simulate)
1764                                 {
1765                                         char proc_name[64];
1766                                         sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1767                                         FILE *f=fopen(proc_name, "w");
1768                                         if (f) // new interface exist?
1769                                         {
1770                                                 bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1771                                                 if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1772                                                         eDebugNoSimulate("write %s failed!! (%m)", proc_name);
1773                                                 else
1774                                                         eDebugNoSimulate("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1775                                                 fclose(f);
1776                                         }
1777                                         else if (sec_fe->m_need_rotor_workaround)
1778                                         {
1779                                                 char dev[16];
1780                                                 int slotid = sec_fe->m_slotid;
1781                                                 // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1782                                                 if (slotid < 2)
1783                                                         sprintf(dev, "/dev/i2c/%d", slotid);
1784                                                 else if (slotid == 2)
1785                                                         sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1786                                                 else if (slotid == 3)
1787                                                         sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1788                                                 int fd = ::open(dev, O_RDWR);
1789
1790                                                 unsigned char data[2];
1791                                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1792                                                 if(::read(fd, data, 1) != 1)
1793                                                         eDebugNoSimulate("[SEC] error read lnbp (%m)");
1794                                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1795                                                 {
1796                                                         data[0] |= 0x80;  // enable static current limiting
1797                                                         eDebugNoSimulate("[SEC] set static current limiting");
1798                                                 }
1799                                                 else
1800                                                 {
1801                                                         data[0] &= ~0x80;  // enable dynamic current limiting
1802                                                         eDebugNoSimulate("[SEC] set dynamic current limiting");
1803                                                 }
1804                                                 if(::write(fd, data, 1) != 1)
1805                                                         eDebugNoSimulate("[SEC] error write lnbp (%m)");
1806                                                 ::close(fd);
1807                                         }
1808                                 }
1809                                 ++m_sec_sequence.current();
1810                                 break;
1811                         }
1812                         default:
1813                                 eDebugNoSimulate("[SEC] unhandled sec command %d",
1814                                         ++m_sec_sequence.current()->cmd);
1815                                 ++m_sec_sequence.current();
1816                 }
1817                 if (!m_simulate)
1818                         m_tuneTimer->start(delay,true);
1819         }
1820         if (regFE)
1821                 regFE->dec_use();
1822         if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
1823                 tuneLoop();
1824 }
1825
1826 void eDVBFrontend::setFrontend()
1827 {
1828         if (!m_simulate)
1829         {
1830                 eDebug("setting frontend %d", m_dvbid);
1831                 m_sn->start();
1832                 feEvent(-1);
1833                 if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1834                 {
1835                         perror("FE_SET_FRONTEND failed");
1836                         return;
1837                 }
1838         }
1839 }
1840
1841 RESULT eDVBFrontend::getFrontendType(int &t)
1842 {
1843         if (m_type == -1)
1844                 return -ENODEV;
1845         t = m_type;
1846         return 0;
1847 }
1848
1849 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1850 {
1851         int res;
1852         if (!m_sec)
1853         {
1854                 eWarning("no SEC module active!");
1855                 return -ENOENT;
1856         }
1857         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1858         if (!res)
1859         {
1860                 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1861                         feparm.system,
1862                         feparm.frequency,
1863                         feparm.polarisation,
1864                         feparm.symbol_rate,
1865                         feparm.inversion,
1866                         feparm.fec,
1867                         feparm.orbital_position);
1868                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1869                 switch (feparm.inversion)
1870                 {
1871                         case eDVBFrontendParametersSatellite::Inversion::On:
1872                                 parm_inversion = INVERSION_ON;
1873                                 break;
1874                         case eDVBFrontendParametersSatellite::Inversion::Off:
1875                                 parm_inversion = INVERSION_OFF;
1876                                 break;
1877                         default:
1878                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1879                                 parm_inversion = INVERSION_AUTO;
1880                                 break;
1881                 }
1882                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1883                         switch (feparm.fec)
1884                         {
1885                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1886                                         parm_u_qpsk_fec_inner = FEC_NONE;
1887                                         break;
1888                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1889                                         parm_u_qpsk_fec_inner = FEC_1_2;
1890                                         break;
1891                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1892                                         parm_u_qpsk_fec_inner = FEC_2_3;
1893                                         break;
1894                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1895                                         parm_u_qpsk_fec_inner = FEC_3_4;
1896                                         break;
1897                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1898                                         parm_u_qpsk_fec_inner = FEC_5_6;
1899                                         break;
1900                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1901                                         parm_u_qpsk_fec_inner = FEC_7_8;
1902                                         break;
1903                                 default:
1904                                         eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
1905                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1906                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1907                                         break;
1908                         }
1909 #if HAVE_DVB_API_VERSION >= 3
1910                 else // DVB_S2
1911                 {
1912                         switch (feparm.fec)
1913                         {
1914                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1915                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1916                                         break;
1917                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1918                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1919                                         break;
1920                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1921                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1922                                         break;
1923                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1924                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1925                                         break;
1926                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1927                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1928                                         break;
1929                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1930                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1931                                         break;
1932                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1933                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1934                                         break;
1935                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1936                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1937                                         break;
1938                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1939                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1940                                         break;
1941                                 default:
1942                                         eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
1943                                         return -EINVAL;
1944                         }
1945                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1946                         parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1947                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1948                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1949                                 // 8PSK fec driver values are decimal 9 bigger
1950                         }
1951                 }
1952 #endif
1953                 // FIXME !!! get frequency range from tuner
1954                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1955                 {
1956                         eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1957                         return -EINVAL;
1958                 }
1959                 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
1960         }
1961         return res;
1962 }
1963
1964 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1965 {
1966 #if HAVE_DVB_API_VERSION < 3
1967         parm_frequency = feparm.frequency;
1968 #else
1969         parm_frequency = feparm.frequency * 1000;
1970 #endif
1971         parm_u_qam_symbol_rate = feparm.symbol_rate;
1972         switch (feparm.modulation)
1973         {
1974         case eDVBFrontendParametersCable::Modulation::QAM16:
1975                 parm_u_qam_modulation = QAM_16;
1976                 break;
1977         case eDVBFrontendParametersCable::Modulation::QAM32:
1978                 parm_u_qam_modulation = QAM_32;
1979                 break;
1980         case eDVBFrontendParametersCable::Modulation::QAM64:
1981                 parm_u_qam_modulation = QAM_64;
1982                 break;
1983         case eDVBFrontendParametersCable::Modulation::QAM128:
1984                 parm_u_qam_modulation = QAM_128;
1985                 break;
1986         case eDVBFrontendParametersCable::Modulation::QAM256:
1987                 parm_u_qam_modulation = QAM_256;
1988                 break;
1989         default:
1990         case eDVBFrontendParametersCable::Modulation::Auto:
1991                 parm_u_qam_modulation = QAM_AUTO;
1992                 break;
1993         }
1994         switch (feparm.inversion)
1995         {
1996         case eDVBFrontendParametersCable::Inversion::On:
1997                 parm_inversion = INVERSION_ON;
1998                 break;
1999         case eDVBFrontendParametersCable::Inversion::Off:
2000                 parm_inversion = INVERSION_OFF;
2001                 break;
2002         default:
2003         case eDVBFrontendParametersCable::Inversion::Unknown:
2004                 parm_inversion = INVERSION_AUTO;
2005                 break;
2006         }
2007         switch (feparm.fec_inner)
2008         {
2009         case eDVBFrontendParametersCable::FEC::fNone:
2010                 parm_u_qam_fec_inner = FEC_NONE;
2011                 break;
2012         case eDVBFrontendParametersCable::FEC::f1_2:
2013                 parm_u_qam_fec_inner = FEC_1_2;
2014                 break;
2015         case eDVBFrontendParametersCable::FEC::f2_3:
2016                 parm_u_qam_fec_inner = FEC_2_3;
2017                 break;
2018         case eDVBFrontendParametersCable::FEC::f3_4:
2019                 parm_u_qam_fec_inner = FEC_3_4;
2020                 break;
2021         case eDVBFrontendParametersCable::FEC::f5_6:
2022                 parm_u_qam_fec_inner = FEC_5_6;
2023                 break;
2024         case eDVBFrontendParametersCable::FEC::f7_8:
2025                 parm_u_qam_fec_inner = FEC_7_8;
2026                 break;
2027 #if HAVE_DVB_API_VERSION >= 3
2028         case eDVBFrontendParametersCable::FEC::f8_9:
2029                 parm_u_qam_fec_inner = FEC_8_9;
2030                 break;
2031 #endif
2032         default:
2033         case eDVBFrontendParametersCable::FEC::fAuto:
2034                 parm_u_qam_fec_inner = FEC_AUTO;
2035                 break;
2036         }
2037         eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
2038                 parm_frequency/1000,
2039                 parm_u_qam_symbol_rate,
2040                 parm_u_qam_fec_inner,
2041                 parm_u_qam_modulation,
2042                 parm_inversion);
2043         return 0;
2044 }
2045
2046 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
2047 {
2048         parm_frequency = feparm.frequency;
2049
2050         switch (feparm.bandwidth)
2051         {
2052         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
2053                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
2054                 break;
2055         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
2056                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
2057                 break;
2058         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
2059                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2060                 break;
2061         default:
2062         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
2063                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2064                 break;
2065         }
2066         switch (feparm.code_rate_LP)
2067         {
2068         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2069                 parm_u_ofdm_code_rate_LP = FEC_1_2;
2070                 break;
2071         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2072                 parm_u_ofdm_code_rate_LP = FEC_2_3;
2073                 break;
2074         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2075                 parm_u_ofdm_code_rate_LP = FEC_3_4;
2076                 break;
2077         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2078                 parm_u_ofdm_code_rate_LP = FEC_5_6;
2079                 break;
2080         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2081                 parm_u_ofdm_code_rate_LP = FEC_7_8;
2082                 break;
2083         default:
2084         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2085                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2086                 break;
2087         }
2088         switch (feparm.code_rate_HP)
2089         {
2090         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2091                 parm_u_ofdm_code_rate_HP = FEC_1_2;
2092                 break;
2093         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2094                 parm_u_ofdm_code_rate_HP = FEC_2_3;
2095                 break;
2096         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2097                 parm_u_ofdm_code_rate_HP = FEC_3_4;
2098                 break;
2099         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2100                 parm_u_ofdm_code_rate_HP = FEC_5_6;
2101                 break;
2102         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2103                 parm_u_ofdm_code_rate_HP = FEC_7_8;
2104                 break;
2105         default:
2106         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2107                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2108                 break;
2109         }
2110         switch (feparm.modulation)
2111         {
2112         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
2113                 parm_u_ofdm_constellation = QPSK;
2114                 break;
2115         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
2116                 parm_u_ofdm_constellation = QAM_16;
2117                 break;
2118         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
2119                 parm_u_ofdm_constellation = QAM_64;
2120                 break;
2121         default:
2122         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
2123                 parm_u_ofdm_constellation = QAM_AUTO;
2124                 break;
2125         }
2126         switch (feparm.transmission_mode)
2127         {
2128         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
2129                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2130                 break;
2131         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
2132                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2133                 break;
2134         default:
2135         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
2136                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2137                 break;
2138         }
2139         switch (feparm.guard_interval)
2140         {
2141                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
2142                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2143                         break;
2144                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2145                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2146                         break;
2147                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2148                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2149                         break;
2150                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2151                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2152                         break;
2153                 default:
2154                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2155                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2156                         break;
2157         }
2158         switch (feparm.hierarchy)
2159         {
2160                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2161                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2162                         break;
2163                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2164                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2165                         break;
2166                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2167                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2168                         break;
2169                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2170                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2171                         break;
2172                 default:
2173                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2174                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2175                         break;
2176         }
2177         switch (feparm.inversion)
2178         {
2179         case eDVBFrontendParametersTerrestrial::Inversion::On:
2180                 parm_inversion = INVERSION_ON;
2181                 break;
2182         case eDVBFrontendParametersTerrestrial::Inversion::Off:
2183                 parm_inversion = INVERSION_OFF;
2184                 break;
2185         default:
2186         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2187                 parm_inversion = INVERSION_AUTO;
2188                 break;
2189         }
2190         return 0;
2191 }
2192
2193 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2194 {
2195         unsigned int timeout = 5000;
2196         eDebugNoSimulate("(%d)tune", m_dvbid);
2197
2198         m_timeout->stop();
2199
2200         int res=0;
2201
2202         if (!m_sn && !m_simulate)
2203         {
2204                 eDebug("no frontend device opened... do not try to tune !!!");
2205                 res = -ENODEV;
2206                 goto tune_error;
2207         }
2208
2209         if (m_type == -1)
2210         {
2211                 res = -ENODEV;
2212                 goto tune_error;
2213         }
2214
2215         if (!m_simulate)
2216                 m_sn->stop();
2217
2218         m_sec_sequence.clear();
2219
2220         where.calcLockTimeout(timeout);
2221
2222         switch (m_type)
2223         {
2224         case feSatellite:
2225         {
2226                 eDVBFrontendParametersSatellite feparm;
2227                 if (where.getDVBS(feparm))
2228                 {
2229                         eDebug("no dvbs data!");
2230                         res = -EINVAL;
2231                         goto tune_error;
2232                 }
2233                 if (!m_simulate)
2234                         m_sec->setRotorMoving(false);
2235                 res=prepare_sat(feparm, timeout);
2236                 if (res)
2237                         goto tune_error;
2238
2239                 break;
2240         }
2241         case feCable:
2242         {
2243                 eDVBFrontendParametersCable feparm;
2244                 if (where.getDVBC(feparm))
2245                 {
2246                         res = -EINVAL;
2247                         goto tune_error;
2248                 }
2249                 res=prepare_cable(feparm);
2250                 if (res)
2251                         goto tune_error;
2252
2253                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2254                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2255                 break;
2256         }
2257         case feTerrestrial:
2258         {
2259                 eDVBFrontendParametersTerrestrial feparm;
2260                 if (where.getDVBT(feparm))
2261                 {
2262                         eDebug("no -T data");
2263                         res = -EINVAL;
2264                         goto tune_error;
2265                 }
2266                 res=prepare_terrestrial(feparm);
2267                 if (res)
2268                         goto tune_error;
2269
2270                 std::string enable_5V;
2271                 char configStr[255];
2272                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2273                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2274                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2275                 if (enable_5V == "True")
2276                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2277                 else
2278                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2279                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2280
2281                 break;
2282         }
2283         }
2284
2285         m_sec_sequence.current() = m_sec_sequence.begin();
2286
2287         if (!m_simulate)
2288         {
2289                 m_tuneTimer->start(0,true);
2290                 if (m_state != stateTuning)
2291                 {
2292                         m_tuning = 1;
2293                         m_state = stateTuning;
2294                         m_stateChanged(this);
2295                 }
2296         }
2297         else
2298                 tuneLoop();
2299
2300         return res;
2301
2302 tune_error:
2303         m_tuneTimer->stop();
2304         return res;
2305 }
2306
2307 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2308 {
2309         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2310         return 0;
2311 }
2312
2313 RESULT eDVBFrontend::setVoltage(int voltage)
2314 {
2315         if (m_type == feCable)
2316                 return -1;
2317 #if HAVE_DVB_API_VERSION < 3
2318         secVoltage vlt;
2319 #else
2320         bool increased=false;
2321         fe_sec_voltage_t vlt;
2322 #endif
2323         m_data[CUR_VOLTAGE]=voltage;
2324         switch (voltage)
2325         {
2326         case voltageOff:
2327                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2328                 vlt = SEC_VOLTAGE_OFF;
2329                 break;
2330         case voltage13_5:
2331 #if HAVE_DVB_API_VERSION < 3
2332                 vlt = SEC_VOLTAGE_13_5;
2333                 break;
2334 #else
2335                 increased = true;
2336 #endif
2337         case voltage13:
2338                 vlt = SEC_VOLTAGE_13;
2339                 break;
2340         case voltage18_5:
2341 #if HAVE_DVB_API_VERSION < 3
2342                 vlt = SEC_VOLTAGE_18_5;
2343                 break;
2344 #else
2345                 increased = true;
2346 #endif
2347         case voltage18:
2348                 vlt = SEC_VOLTAGE_18;
2349                 break;
2350         default:
2351                 return -ENODEV;
2352         }
2353         if (m_simulate)
2354                 return 0;
2355 #if HAVE_DVB_API_VERSION < 3
2356         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2357 #else
2358         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2359                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2360         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2361 #endif
2362 }
2363
2364 RESULT eDVBFrontend::getState(int &state)
2365 {
2366         state = m_state;
2367         return 0;
2368 }
2369
2370 RESULT eDVBFrontend::setTone(int t)
2371 {
2372         if (m_type != feSatellite)
2373                 return -1;
2374 #if HAVE_DVB_API_VERSION < 3
2375         secToneMode_t tone;
2376 #else
2377         fe_sec_tone_mode_t tone;
2378 #endif
2379         m_data[CUR_TONE]=t;
2380         switch (t)
2381         {
2382         case toneOn:
2383                 tone = SEC_TONE_ON;
2384                 break;
2385         case toneOff:
2386                 tone = SEC_TONE_OFF;
2387                 break;
2388         default:
2389                 return -ENODEV;
2390         }
2391         if (m_simulate)
2392                 return 0;
2393 #if HAVE_DVB_API_VERSION < 3    
2394         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2395 #else   
2396         return ::ioctl(m_fd, FE_SET_TONE, tone);
2397 #endif
2398 }
2399
2400 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2401         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2402 #endif
2403
2404 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2405 {
2406         if (m_simulate)
2407                 return 0;
2408 #if HAVE_DVB_API_VERSION < 3
2409         struct secCommand cmd;
2410         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2411         cmd.u.diseqc.cmdtype = diseqc.data[0];
2412         cmd.u.diseqc.addr = diseqc.data[1];
2413         cmd.u.diseqc.cmd = diseqc.data[2];
2414         cmd.u.diseqc.numParams = diseqc.len-3;
2415         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2416         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2417 #else
2418         struct dvb_diseqc_master_cmd cmd;
2419         memcpy(cmd.msg, diseqc.data, diseqc.len);
2420         cmd.msg_len = diseqc.len;
2421         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2422 #endif
2423                 return -EINVAL;
2424         return 0;
2425 }
2426
2427 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2428         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2429 #endif
2430 RESULT eDVBFrontend::sendToneburst(int burst)
2431 {
2432         if (m_simulate)
2433                 return 0;
2434 #if HAVE_DVB_API_VERSION < 3
2435         secMiniCmd cmd = SEC_MINI_NONE;
2436 #else
2437         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2438 #endif
2439         if ( burst == eDVBSatelliteDiseqcParameters::A )
2440                 cmd = SEC_MINI_A;
2441         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2442                 cmd = SEC_MINI_B;
2443 #if HAVE_DVB_API_VERSION < 3
2444         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2445                 return -EINVAL;
2446 #else
2447         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2448                 return -EINVAL;
2449 #endif
2450         return 0;
2451 }
2452
2453 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2454 {
2455         m_sec = sec;
2456         return 0;
2457 }
2458
2459 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2460 {
2461         m_sec_sequence = list;
2462         return 0;
2463 }
2464
2465 RESULT eDVBFrontend::getData(int num, long &data)
2466 {
2467         if ( num < NUM_DATA_ENTRIES )
2468         {
2469                 data = m_data[num];
2470                 return 0;
2471         }
2472         return -EINVAL;
2473 }
2474
2475 RESULT eDVBFrontend::setData(int num, long val)
2476 {
2477         if ( num < NUM_DATA_ENTRIES )
2478         {
2479                 m_data[num] = val;
2480                 return 0;
2481         }
2482         return -EINVAL;
2483 }
2484
2485 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2486 {
2487         int type;
2488         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2489                 return 0;
2490         if (m_type == eDVBFrontend::feSatellite)
2491         {
2492                 ASSERT(m_sec);
2493                 eDVBFrontendParametersSatellite sat_parm;
2494                 int ret = feparm->getDVBS(sat_parm);
2495                 ASSERT(!ret);
2496                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2497                         return 0;
2498                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2499                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2500                         ret -= 1;
2501                 return ret;
2502         }
2503         else if (m_type == eDVBFrontend::feCable)
2504                 return 2;  // more prio for cable frontends
2505         else if (m_type == eDVBFrontend::feTerrestrial)
2506                 return 1;
2507         return 0;
2508 }
2509
2510 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2511 {
2512         ePyObject Id, Descr, Enabled, IsDVBS2;
2513         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2514                 goto arg_error;
2515         Id = PyTuple_GET_ITEM(obj, 0);
2516         Descr = PyTuple_GET_ITEM(obj, 1);
2517         Enabled = PyTuple_GET_ITEM(obj, 2);
2518         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2519         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2520                 goto arg_error;
2521         strcpy(m_description, PyString_AS_STRING(Descr));
2522         m_slotid = PyInt_AsLong(Id);
2523         m_enabled = Enabled == Py_True;
2524         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2525         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2526                 !!strstr(m_description, "Alps BSBE2") ||
2527                 !!strstr(m_description, "Alps -S") ||
2528                 !!strstr(m_description, "BCM4501");
2529         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2530         eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2531                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2532         return true;
2533 arg_error:
2534         PyErr_SetString(PyExc_StandardError,
2535                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2536         return false;
2537 }