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