bfb82a9246c8e29f236fe6fdd3b89fe258cbd70c
[enigma2.git] / lib / dvb / frontend.cpp
1 #include <lib/dvb/dvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/base/nconfig.h> // access to python config
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8
9 #ifndef I2C_SLAVE_FORCE
10 #define I2C_SLAVE_FORCE 0x0706
11 #endif
12
13 #if HAVE_DVB_API_VERSION < 3
14 #include <ost/frontend.h>
15 #include <ost/sec.h>
16 #define QAM_AUTO                                (Modulation)6
17 #define TRANSMISSION_MODE_AUTO  (TransmitMode)2
18 #define BANDWIDTH_AUTO                  (BandWidth)3
19 #define GUARD_INTERVAL_AUTO             (GuardInterval)4
20 #define HIERARCHY_AUTO                  (Hierarchy)4
21 #define parm_frequency parm.Frequency
22 #define parm_inversion parm.Inversion
23 #define parm_u_qpsk_symbol_rate parm.u.qpsk.SymbolRate
24 #define parm_u_qpsk_fec_inner parm.u.qpsk.FEC_inner
25 #define parm_u_qam_symbol_rate parm.u.qam.SymbolRate
26 #define parm_u_qam_fec_inner parm.u.qam.FEC_inner
27 #define parm_u_qam_modulation parm.u.qam.QAM
28 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandWidth
29 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.LP_CodeRate
30 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.HP_CodeRate
31 #define parm_u_ofdm_constellation parm.u.ofdm.Constellation
32 #define parm_u_ofdm_transmission_mode parm.u.ofdm.TransmissionMode
33 #define parm_u_ofdm_guard_interval parm.u.ofdm.guardInterval
34 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.HierarchyInformation
35 #else
36 #include <linux/dvb/frontend.h>
37 #define parm_frequency parm.frequency
38 #define parm_inversion parm.inversion
39 #define parm_u_qpsk_symbol_rate parm.u.qpsk.symbol_rate
40 #define parm_u_qpsk_fec_inner parm.u.qpsk.fec_inner
41 #define parm_u_qam_symbol_rate parm.u.qam.symbol_rate
42 #define parm_u_qam_fec_inner parm.u.qam.fec_inner
43 #define parm_u_qam_modulation parm.u.qam.modulation
44 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandwidth
45 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.code_rate_LP
46 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.code_rate_HP
47 #define parm_u_ofdm_constellation parm.u.ofdm.constellation
48 #define parm_u_ofdm_transmission_mode parm.u.ofdm.transmission_mode
49 #define parm_u_ofdm_guard_interval parm.u.ofdm.guard_interval
50 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.hierarchy_information
51 #ifdef FEC_9_10
52         #warning "FEC_9_10 already exist in dvb api ... it seems it is now ready for DVB-S2"
53 #else
54         #define FEC_S2_QPSK_1_2 (fe_code_rate_t)(FEC_AUTO+1)
55         #define FEC_S2_QPSK_2_3 (fe_code_rate_t)(FEC_S2_QPSK_1_2+1)
56         #define FEC_S2_QPSK_3_4 (fe_code_rate_t)(FEC_S2_QPSK_2_3+1)
57         #define FEC_S2_QPSK_5_6 (fe_code_rate_t)(FEC_S2_QPSK_3_4+1)
58         #define FEC_S2_QPSK_7_8 (fe_code_rate_t)(FEC_S2_QPSK_5_6+1)
59         #define FEC_S2_QPSK_8_9 (fe_code_rate_t)(FEC_S2_QPSK_7_8+1)
60         #define FEC_S2_QPSK_3_5 (fe_code_rate_t)(FEC_S2_QPSK_8_9+1)
61         #define FEC_S2_QPSK_4_5 (fe_code_rate_t)(FEC_S2_QPSK_3_5+1)
62         #define FEC_S2_QPSK_9_10 (fe_code_rate_t)(FEC_S2_QPSK_4_5+1)
63         #define FEC_S2_8PSK_1_2 (fe_code_rate_t)(FEC_S2_QPSK_9_10+1)
64         #define FEC_S2_8PSK_2_3 (fe_code_rate_t)(FEC_S2_8PSK_1_2+1)
65         #define FEC_S2_8PSK_3_4 (fe_code_rate_t)(FEC_S2_8PSK_2_3+1)
66         #define FEC_S2_8PSK_5_6 (fe_code_rate_t)(FEC_S2_8PSK_3_4+1)
67         #define FEC_S2_8PSK_7_8 (fe_code_rate_t)(FEC_S2_8PSK_5_6+1)
68         #define FEC_S2_8PSK_8_9 (fe_code_rate_t)(FEC_S2_8PSK_7_8+1)
69         #define FEC_S2_8PSK_3_5 (fe_code_rate_t)(FEC_S2_8PSK_8_9+1)
70         #define FEC_S2_8PSK_4_5 (fe_code_rate_t)(FEC_S2_8PSK_3_5+1)
71         #define FEC_S2_8PSK_9_10 (fe_code_rate_t)(FEC_S2_8PSK_4_5+1)
72 #endif
73 #endif
74
75 #include <dvbsi++/satellite_delivery_system_descriptor.h>
76 #include <dvbsi++/cable_delivery_system_descriptor.h>
77 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
78
79 #define eDebugNoSimulate(x...) \
80         do { \
81                 if (!m_simulate) \
82                         eDebug(x); \
83         } while(0)
84 //              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 (m_fd == -1 && !original)
1280                                         original = true;
1281                                 else if (ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1282                                 {
1283                                         eDebug("FE_GET_FRONTEND failed (%m)");
1284                                         original = true;
1285                                 }
1286                                 {
1287                                         const FRONTENDPARAMETERS &parm = original || m_simulate ? this->parm : front;
1288                                         const char *tmp = "INVERSION_AUTO";
1289                                         switch(parm_inversion)
1290                                         {
1291                                                 case INVERSION_ON:
1292                                                         tmp = "INVERSION_ON";
1293                                                         break;
1294                                                 case INVERSION_OFF:
1295                                                         tmp = "INVERSION_OFF";
1296                                                         break;
1297                                                 default:
1298                                                         break;
1299                                         }
1300                                         if (tmp)
1301                                                 PutToDict(dest, "inversion", tmp);
1302
1303                                         switch(m_type)
1304                                         {
1305                                                 case feSatellite:
1306                                                         fillDictWithSatelliteData(dest, original?parm:front, this);
1307                                                         break;
1308                                                 case feCable:
1309                                                         fillDictWithCableData(dest, original?parm:front);
1310                                                         break;
1311                                                 case feTerrestrial:
1312                                                         fillDictWithTerrestrialData(dest, original?parm:front);
1313                                                         break;
1314                                         }
1315                                 }
1316                         }
1317                         default:
1318                                 break;
1319                 }
1320         }
1321 }
1322
1323 void eDVBFrontend::getFrontendData(ePyObject dest)
1324 {
1325         if (dest && PyDict_Check(dest))
1326         {
1327                 const char *tmp=0;
1328                 PutToDict(dest, "tuner_number", m_slotid);
1329                 switch(m_type)
1330                 {
1331                         case feSatellite:
1332                                 tmp = "DVB-S";
1333                                 break;
1334                         case feCable:
1335                                 tmp = "DVB-C";
1336                                 break;
1337                         case feTerrestrial:
1338                                 tmp = "DVB-T";
1339                                 break;
1340                         default:
1341                                 tmp = "UNKNOWN";
1342                                 break;
1343                 }
1344                 PutToDict(dest, "tuner_type", tmp);
1345         }
1346 }
1347
1348 #ifndef FP_IOCTL_GET_ID
1349 #define FP_IOCTL_GET_ID 0
1350 #endif
1351 int eDVBFrontend::readInputpower()
1352 {
1353         if (m_simulate)
1354                 return 0;
1355         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1356         char proc_name[64];
1357         sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1358         FILE *f=fopen(proc_name, "r");
1359         if (f)
1360         {
1361                 if (fscanf(f, "%d", &power) != 1)
1362                         eDebug("read %s failed!! (%m)", proc_name);
1363                 else
1364                         eDebug("%s is %d\n", proc_name, power);
1365                 fclose(f);
1366         }
1367         else
1368         {
1369                 // open front prozessor
1370                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1371                 if (fp < 0)
1372                 {
1373                         eDebug("couldn't open fp");
1374                         return -1;
1375                 }
1376                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1377                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1378                 {
1379                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1380                         return -1;
1381                 }
1382                 ::close(fp);
1383         }
1384
1385         return power;
1386 }
1387
1388 bool eDVBFrontend::setSecSequencePos(int steps)
1389 {
1390         eDebugNoSimulate("set sequence pos %d", steps);
1391         if (!steps)
1392                 return false;
1393         while( steps > 0 )
1394         {
1395                 if (m_sec_sequence.current() != m_sec_sequence.end())
1396                         ++m_sec_sequence.current();
1397                 --steps;
1398         }
1399         while( steps < 0 )
1400         {
1401                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1402                         --m_sec_sequence.current();
1403                 ++steps;
1404         }
1405         return true;
1406 }
1407
1408 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1409 {
1410         int delay=0;
1411         eDVBFrontend *sec_fe = this;
1412         eDVBRegisteredFrontend *regFE = 0;
1413         long tmp = m_data[LINKED_PREV_PTR];
1414         while ( tmp != -1 )
1415         {
1416                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1417                 sec_fe = prev->m_frontend;
1418                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1419                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1420                         int state = sec_fe->m_state;
1421                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1422                         {
1423                                 sec_fe->closeFrontend(true);
1424                                 state = sec_fe->m_state;
1425                         }
1426                         if (state == eDVBFrontend::stateClosed)
1427                         {
1428                                 regFE = prev;
1429                                 prev->inc_use();
1430                         }
1431                 }
1432         }
1433
1434         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1435         {
1436                 long *sec_fe_data = sec_fe->m_data;
1437 //              eDebugNoSimulate("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1438                 switch (m_sec_sequence.current()->cmd)
1439                 {
1440                         case eSecCommand::SLEEP:
1441                                 delay = m_sec_sequence.current()++->msec;
1442                                 eDebugNoSimulate("[SEC] sleep %dms", delay);
1443                                 break;
1444                         case eSecCommand::GOTO:
1445                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1446                                         ++m_sec_sequence.current();
1447                                 break;
1448                         case eSecCommand::SET_VOLTAGE:
1449                         {
1450                                 int voltage = m_sec_sequence.current()++->voltage;
1451                                 eDebugNoSimulate("[SEC] setVoltage %d", voltage);
1452                                 sec_fe->setVoltage(voltage);
1453                                 break;
1454                         }
1455                         case eSecCommand::IF_VOLTAGE_GOTO:
1456                         {
1457                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1458                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1459                                         break;
1460                                 ++m_sec_sequence.current();
1461                                 break;
1462                         }
1463                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1464                         {
1465                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1466                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1467                                         break;
1468                                 ++m_sec_sequence.current();
1469                                 break;
1470                         }
1471                         case eSecCommand::IF_TONE_GOTO:
1472                         {
1473                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1474                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1475                                         break;
1476                                 ++m_sec_sequence.current();
1477                                 break;
1478                         }
1479                         case eSecCommand::IF_NOT_TONE_GOTO:
1480                         {
1481                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1482                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1483                                         break;
1484                                 ++m_sec_sequence.current();
1485                                 break;
1486                         }
1487                         case eSecCommand::SET_TONE:
1488                                 eDebugNoSimulate("[SEC] setTone %d", m_sec_sequence.current()->tone);
1489                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1490                                 break;
1491                         case eSecCommand::SEND_DISEQC:
1492                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1493                                 eDebugNoSimulateNoNewLine("[SEC] sendDiseqc: ");
1494                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1495                                     eDebugNoSimulateNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1496                                 eDebugNoSimulate("");
1497                                 ++m_sec_sequence.current();
1498                                 break;
1499                         case eSecCommand::SEND_TONEBURST:
1500                                 eDebugNoSimulate("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1501                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1502                                 break;
1503                         case eSecCommand::SET_FRONTEND:
1504                                 eDebugNoSimulate("[SEC] setFrontend");
1505                                 setFrontend();
1506                                 ++m_sec_sequence.current();
1507                                 break;
1508                         case eSecCommand::START_TUNE_TIMEOUT:
1509                         {
1510                                 if (!m_simulate)
1511                                         m_timeout->start(m_sec_sequence.current()->timeout, 1);
1512                                 ++m_sec_sequence.current();
1513                                 break;
1514                         }
1515                         case eSecCommand::SET_TIMEOUT:
1516                                 m_timeoutCount = m_sec_sequence.current()++->val;
1517                                 eDebugNoSimulate("[SEC] set timeout %d", m_timeoutCount);
1518                                 break;
1519                         case eSecCommand::IF_TIMEOUT_GOTO:
1520                                 if (!m_timeoutCount)
1521                                 {
1522                                         eDebugNoSimulate("[SEC] rotor timout");
1523                                         setSecSequencePos(m_sec_sequence.current()->steps);
1524                                 }
1525                                 else
1526                                         ++m_sec_sequence.current();
1527                                 break;
1528                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1529                         {
1530                                 int idx = m_sec_sequence.current()++->val;
1531                                 if ( idx == 0 || idx == 1 )
1532                                 {
1533                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1534                                         eDebugNoSimulate("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1535                                 }
1536                                 else
1537                                         eDebugNoSimulate("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1538                                 break;
1539                         }
1540                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1541                         {
1542                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1543                                 int idx = compare.val;
1544                                 if ( !m_simulate && (idx == 0 || idx == 1) )
1545                                 {
1546                                         int idle = sec_fe->readInputpower();
1547                                         int diff = abs(idle-m_idleInputpower[idx]);
1548                                         if ( diff > 0)
1549                                         {
1550                                                 eDebugNoSimulate("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1551                                                 setSecSequencePos(compare.steps);
1552                                                 break;
1553                                         }
1554                                 }
1555                                 ++m_sec_sequence.current();
1556                                 break;
1557                         }
1558                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1559                         {
1560                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1561                                 if (m_simulate)
1562                                 {
1563                                         setSecSequencePos(cmd.steps);
1564                                         break;
1565                                 }
1566                                 int signal = 0;
1567                                 int isLocked = readFrontendData(locked);
1568                                 m_idleInputpower[0] = m_idleInputpower[1] = 0;
1569                                 if (isLocked && ((abs((signal = readFrontendData(signalQualitydB)) - cmd.lastSignal) < 50) || !cmd.lastSignal))
1570                                 {
1571                                         if (cmd.lastSignal)
1572                                                 eDebugNoSimulate("[SEC] locked step %d ok (%d %d)", cmd.okcount, signal, cmd.lastSignal);
1573                                         else
1574                                         {
1575                                                 eDebugNoSimulate("[SEC] locked step %d ok", cmd.okcount);
1576                                                 cmd.lastSignal = signal;
1577                                         }
1578                                         ++cmd.okcount;
1579                                         if (cmd.okcount > 4)
1580                                         {
1581                                                 eDebugNoSimulate("ok > 4 .. goto %d\n",cmd.steps);
1582                                                 setSecSequencePos(cmd.steps);
1583                                                 m_state = stateLock;
1584                                                 m_stateChanged(this);
1585                                                 feEvent(-1);
1586                                                 m_sn->start();
1587                                                 break;
1588                                         }
1589                                 }
1590                                 else
1591                                 {
1592                                         if (isLocked)
1593                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (oldSignal %d, curSignal %d)", cmd.okcount, signal, cmd.lastSignal);
1594                                         else
1595                                                 eDebugNoSimulate("[SEC] rotor locked step %d failed (not locked)", cmd.okcount);
1596                                         --m_timeoutCount;
1597                                         if (!m_timeoutCount && m_retryCount > 0)
1598                                                 --m_retryCount;
1599                                         cmd.okcount=0;
1600                                         cmd.lastSignal=0;
1601                                 }
1602                                 ++m_sec_sequence.current();
1603                                 break;
1604                         }
1605                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1606                                 m_runningInputpower = sec_fe->readInputpower();
1607                                 eDebugNoSimulate("[SEC] runningInputpower is %d", m_runningInputpower);
1608                                 ++m_sec_sequence.current();
1609                                 break;
1610                         case eSecCommand::SET_ROTOR_MOVING:
1611                                 if (!m_simulate)
1612                                         m_sec->setRotorMoving(true);
1613                                 ++m_sec_sequence.current();
1614                                 break;
1615                         case eSecCommand::SET_ROTOR_STOPPED:
1616                                 if (!m_simulate)
1617                                         m_sec->setRotorMoving(false);
1618                                 ++m_sec_sequence.current();
1619                                 break;
1620                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1621                         {
1622                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1623                                 if (m_simulate)
1624                                 {
1625                                         setSecSequencePos(cmd.steps);
1626                                         break;
1627                                 }
1628                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1629                                 const char *txt = cmd.direction ? "running" : "stopped";
1630                                 eDebugNoSimulate("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1631                                         txt,
1632                                         m_runningInputpower,
1633                                         idleInputpower,
1634                                         cmd.deltaA);
1635                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1636                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1637                                 {
1638                                         ++cmd.okcount;
1639                                         eDebugNoSimulate("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1640                                         if ( cmd.okcount > 6 )
1641                                         {
1642                                                 eDebugNoSimulate("[SEC] rotor is %s", txt);
1643                                                 if (setSecSequencePos(cmd.steps))
1644                                                         break;
1645                                         }
1646                                 }
1647                                 else
1648                                 {
1649                                         eDebugNoSimulate("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1650                                         --m_timeoutCount;
1651                                         if (!m_timeoutCount && m_retryCount > 0)
1652                                                 --m_retryCount;
1653                                         cmd.okcount=0;
1654                                 }
1655                                 ++m_sec_sequence.current();
1656                                 break;
1657                         }
1658                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1659                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1660                                         setSecSequencePos(m_sec_sequence.current()->steps);
1661                                 else
1662                                         ++m_sec_sequence.current();
1663                                 break;
1664                         case eSecCommand::INVALIDATE_CURRENT_SWITCHPARMS:
1665                                 eDebugNoSimulate("[SEC] invalidate current switch params");
1666                                 sec_fe_data[CSW] = -1;
1667                                 sec_fe_data[UCSW] = -1;
1668                                 sec_fe_data[TONEBURST] = -1;
1669                                 ++m_sec_sequence.current();
1670                                 break;
1671                         case eSecCommand::UPDATE_CURRENT_SWITCHPARMS:
1672                                 sec_fe_data[CSW] = sec_fe_data[NEW_CSW];
1673                                 sec_fe_data[UCSW] = sec_fe_data[NEW_UCSW];
1674                                 sec_fe_data[TONEBURST] = sec_fe_data[NEW_TONEBURST];
1675                                 eDebugNoSimulate("[SEC] update current switch params");
1676                                 ++m_sec_sequence.current();
1677                                 break;
1678                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1679                                 eDebugNoSimulate("[SEC] invalidate current rotorparams");
1680                                 sec_fe_data[ROTOR_CMD] = -1;
1681                                 sec_fe_data[ROTOR_POS] = -1;
1682                                 ++m_sec_sequence.current();
1683                                 break;
1684                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1685                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1686                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1687                                 eDebugNoSimulate("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1688                                 ++m_sec_sequence.current();
1689                                 break;
1690                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1691                                 m_retryCount = m_sec_sequence.current()++->val;
1692                                 eDebugNoSimulate("[SEC] set rotor retries %d", m_retryCount);
1693                                 break;
1694                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1695                                 if (!m_retryCount)
1696                                 {
1697                                         eDebugNoSimulate("[SEC] no more rotor retrys");
1698                                         setSecSequencePos(m_sec_sequence.current()->steps);
1699                                 }
1700                                 else
1701                                         ++m_sec_sequence.current();
1702                                 break;
1703                         case eSecCommand::SET_POWER_LIMITING_MODE:
1704                         {
1705                                 if (!m_simulate)
1706                                 {
1707                                         char proc_name[64];
1708                                         sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1709                                         FILE *f=fopen(proc_name, "w");
1710                                         if (f) // new interface exist?
1711                                         {
1712                                                 bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1713                                                 if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1714                                                         eDebugNoSimulate("write %s failed!! (%m)", proc_name);
1715                                                 else
1716                                                         eDebugNoSimulate("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1717                                                 fclose(f);
1718                                         }
1719                                         else if (sec_fe->m_need_rotor_workaround)
1720                                         {
1721                                                 char dev[16];
1722                                                 int slotid = sec_fe->m_slotid;
1723                                                 // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1724                                                 if (slotid < 2)
1725                                                         sprintf(dev, "/dev/i2c/%d", slotid);
1726                                                 else if (slotid == 2)
1727                                                         sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1728                                                 else if (slotid == 3)
1729                                                         sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1730                                                 int fd = ::open(dev, O_RDWR);
1731
1732                                                 unsigned char data[2];
1733                                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1734                                                 if(::read(fd, data, 1) != 1)
1735                                                         eDebugNoSimulate("[SEC] error read lnbp (%m)");
1736                                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1737                                                 {
1738                                                         data[0] |= 0x80;  // enable static current limiting
1739                                                         eDebugNoSimulate("[SEC] set static current limiting");
1740                                                 }
1741                                                 else
1742                                                 {
1743                                                         data[0] &= ~0x80;  // enable dynamic current limiting
1744                                                         eDebugNoSimulate("[SEC] set dynamic current limiting");
1745                                                 }
1746                                                 if(::write(fd, data, 1) != 1)
1747                                                         eDebugNoSimulate("[SEC] error write lnbp (%m)");
1748                                                 ::close(fd);
1749                                         }
1750                                 }
1751                                 ++m_sec_sequence.current();
1752                                 break;
1753                         }
1754                         default:
1755                                 eDebugNoSimulate("[SEC] unhandled sec command %d",
1756                                         ++m_sec_sequence.current()->cmd);
1757                                 ++m_sec_sequence.current();
1758                 }
1759                 if (!m_simulate)
1760                         m_tuneTimer->start(delay,true);
1761         }
1762         if (regFE)
1763                 regFE->dec_use();
1764         if (m_simulate && m_sec_sequence.current() != m_sec_sequence.end())
1765                 tuneLoop();
1766 }
1767
1768 void eDVBFrontend::setFrontend()
1769 {
1770         if (!m_simulate)
1771         {
1772                 eDebug("setting frontend %d", m_dvbid);
1773                 m_sn->start();
1774                 feEvent(-1);
1775                 if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1776                 {
1777                         perror("FE_SET_FRONTEND failed");
1778                         return;
1779                 }
1780         }
1781 }
1782
1783 RESULT eDVBFrontend::getFrontendType(int &t)
1784 {
1785         if (m_type == -1)
1786                 return -ENODEV;
1787         t = m_type;
1788         return 0;
1789 }
1790
1791 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1792 {
1793         int res;
1794         if (!m_sec)
1795         {
1796                 eWarning("no SEC module active!");
1797                 return -ENOENT;
1798         }
1799         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1800         if (!res)
1801         {
1802                 eDebugNoSimulate("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1803                         feparm.system,
1804                         feparm.frequency,
1805                         feparm.polarisation,
1806                         feparm.symbol_rate,
1807                         feparm.inversion,
1808                         feparm.fec,
1809                         feparm.orbital_position);
1810                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1811                 switch (feparm.inversion)
1812                 {
1813                         case eDVBFrontendParametersSatellite::Inversion::On:
1814                                 parm_inversion = INVERSION_ON;
1815                                 break;
1816                         case eDVBFrontendParametersSatellite::Inversion::Off:
1817                                 parm_inversion = INVERSION_OFF;
1818                                 break;
1819                         default:
1820                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1821                                 parm_inversion = INVERSION_AUTO;
1822                                 break;
1823                 }
1824                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1825                         switch (feparm.fec)
1826                         {
1827                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1828                                         parm_u_qpsk_fec_inner = FEC_NONE;
1829                                         break;
1830                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1831                                         parm_u_qpsk_fec_inner = FEC_1_2;
1832                                         break;
1833                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1834                                         parm_u_qpsk_fec_inner = FEC_2_3;
1835                                         break;
1836                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1837                                         parm_u_qpsk_fec_inner = FEC_3_4;
1838                                         break;
1839                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1840                                         parm_u_qpsk_fec_inner = FEC_5_6;
1841                                         break;
1842                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1843                                         parm_u_qpsk_fec_inner = FEC_7_8;
1844                                         break;
1845                                 default:
1846                                         eDebugNoSimulate("no valid fec for DVB-S set.. assume auto");
1847                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1848                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1849                                         break;
1850                         }
1851 #if HAVE_DVB_API_VERSION >= 3
1852                 else // DVB_S2
1853                 {
1854                         switch (feparm.fec)
1855                         {
1856                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1857                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1858                                         break;
1859                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1860                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1861                                         break;
1862                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1863                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1864                                         break;
1865                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1866                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1867                                         break;
1868                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1869                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1870                                         break;
1871                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1872                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1873                                         break;
1874                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1875                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1876                                         break;
1877                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1878                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1879                                         break;
1880                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1881                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1882                                         break;
1883                                 default:
1884                                         eDebugNoSimulate("no valid fec for DVB-S2 set.. abort !!");
1885                                         return -EINVAL;
1886                         }
1887                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1888                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1889                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1890                                 // 8PSK fec driver values are decimal 9 bigger
1891                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1892                         }
1893                 }
1894 #endif
1895                 // FIXME !!! get frequency range from tuner
1896                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1897                 {
1898                         eDebugNoSimulate("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1899                         return -EINVAL;
1900                 }
1901                 eDebugNoSimulate("tuning to %d mhz", parm_frequency/1000);
1902         }
1903         return res;
1904 }
1905
1906 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1907 {
1908 #if HAVE_DVB_API_VERSION < 3
1909         parm_frequency = feparm.frequency;
1910 #else
1911         parm_frequency = feparm.frequency * 1000;
1912 #endif
1913         parm_u_qam_symbol_rate = feparm.symbol_rate;
1914         switch (feparm.modulation)
1915         {
1916         case eDVBFrontendParametersCable::Modulation::QAM16:
1917                 parm_u_qam_modulation = QAM_16;
1918                 break;
1919         case eDVBFrontendParametersCable::Modulation::QAM32:
1920                 parm_u_qam_modulation = QAM_32;
1921                 break;
1922         case eDVBFrontendParametersCable::Modulation::QAM64:
1923                 parm_u_qam_modulation = QAM_64;
1924                 break;
1925         case eDVBFrontendParametersCable::Modulation::QAM128:
1926                 parm_u_qam_modulation = QAM_128;
1927                 break;
1928         case eDVBFrontendParametersCable::Modulation::QAM256:
1929                 parm_u_qam_modulation = QAM_256;
1930                 break;
1931         default:
1932         case eDVBFrontendParametersCable::Modulation::Auto:
1933                 parm_u_qam_modulation = QAM_AUTO;
1934                 break;
1935         }
1936         switch (feparm.inversion)
1937         {
1938         case eDVBFrontendParametersCable::Inversion::On:
1939                 parm_inversion = INVERSION_ON;
1940                 break;
1941         case eDVBFrontendParametersCable::Inversion::Off:
1942                 parm_inversion = INVERSION_OFF;
1943                 break;
1944         default:
1945         case eDVBFrontendParametersCable::Inversion::Unknown:
1946                 parm_inversion = INVERSION_AUTO;
1947                 break;
1948         }
1949         switch (feparm.fec_inner)
1950         {
1951         case eDVBFrontendParametersCable::FEC::fNone:
1952                 parm_u_qam_fec_inner = FEC_NONE;
1953                 break;
1954         case eDVBFrontendParametersCable::FEC::f1_2:
1955                 parm_u_qam_fec_inner = FEC_1_2;
1956                 break;
1957         case eDVBFrontendParametersCable::FEC::f2_3:
1958                 parm_u_qam_fec_inner = FEC_2_3;
1959                 break;
1960         case eDVBFrontendParametersCable::FEC::f3_4:
1961                 parm_u_qam_fec_inner = FEC_3_4;
1962                 break;
1963         case eDVBFrontendParametersCable::FEC::f5_6:
1964                 parm_u_qam_fec_inner = FEC_5_6;
1965                 break;
1966         case eDVBFrontendParametersCable::FEC::f7_8:
1967                 parm_u_qam_fec_inner = FEC_7_8;
1968                 break;
1969 #if HAVE_DVB_API_VERSION >= 3
1970         case eDVBFrontendParametersCable::FEC::f8_9:
1971                 parm_u_qam_fec_inner = FEC_8_9;
1972                 break;
1973 #endif
1974         default:
1975         case eDVBFrontendParametersCable::FEC::fAuto:
1976                 parm_u_qam_fec_inner = FEC_AUTO;
1977                 break;
1978         }
1979         eDebugNoSimulate("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1980                 parm_frequency/1000,
1981                 parm_u_qam_symbol_rate,
1982                 parm_u_qam_fec_inner,
1983                 parm_u_qam_modulation,
1984                 parm_inversion);
1985         return 0;
1986 }
1987
1988 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1989 {
1990         parm_frequency = feparm.frequency;
1991
1992         switch (feparm.bandwidth)
1993         {
1994         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1995                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1996                 break;
1997         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1998                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1999                 break;
2000         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
2001                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
2002                 break;
2003         default:
2004         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
2005                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
2006                 break;
2007         }
2008         switch (feparm.code_rate_LP)
2009         {
2010         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2011                 parm_u_ofdm_code_rate_LP = FEC_1_2;
2012                 break;
2013         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2014                 parm_u_ofdm_code_rate_LP = FEC_2_3;
2015                 break;
2016         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2017                 parm_u_ofdm_code_rate_LP = FEC_3_4;
2018                 break;
2019         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2020                 parm_u_ofdm_code_rate_LP = FEC_5_6;
2021                 break;
2022         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2023                 parm_u_ofdm_code_rate_LP = FEC_7_8;
2024                 break;
2025         default:
2026         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2027                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
2028                 break;
2029         }
2030         switch (feparm.code_rate_HP)
2031         {
2032         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
2033                 parm_u_ofdm_code_rate_HP = FEC_1_2;
2034                 break;
2035         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
2036                 parm_u_ofdm_code_rate_HP = FEC_2_3;
2037                 break;
2038         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
2039                 parm_u_ofdm_code_rate_HP = FEC_3_4;
2040                 break;
2041         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
2042                 parm_u_ofdm_code_rate_HP = FEC_5_6;
2043                 break;
2044         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
2045                 parm_u_ofdm_code_rate_HP = FEC_7_8;
2046                 break;
2047         default:
2048         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
2049                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
2050                 break;
2051         }
2052         switch (feparm.modulation)
2053         {
2054         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
2055                 parm_u_ofdm_constellation = QPSK;
2056                 break;
2057         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
2058                 parm_u_ofdm_constellation = QAM_16;
2059                 break;
2060         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
2061                 parm_u_ofdm_constellation = QAM_64;
2062                 break;
2063         default:
2064         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
2065                 parm_u_ofdm_constellation = QAM_AUTO;
2066                 break;
2067         }
2068         switch (feparm.transmission_mode)
2069         {
2070         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
2071                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
2072                 break;
2073         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
2074                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
2075                 break;
2076         default:
2077         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
2078                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
2079                 break;
2080         }
2081         switch (feparm.guard_interval)
2082         {
2083                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
2084                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
2085                         break;
2086                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
2087                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
2088                         break;
2089                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
2090                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
2091                         break;
2092                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
2093                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
2094                         break;
2095                 default:
2096                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
2097                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
2098                         break;
2099         }
2100         switch (feparm.hierarchy)
2101         {
2102                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
2103                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
2104                         break;
2105                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
2106                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
2107                         break;
2108                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
2109                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
2110                         break;
2111                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
2112                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
2113                         break;
2114                 default:
2115                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
2116                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
2117                         break;
2118         }
2119         switch (feparm.inversion)
2120         {
2121         case eDVBFrontendParametersTerrestrial::Inversion::On:
2122                 parm_inversion = INVERSION_ON;
2123                 break;
2124         case eDVBFrontendParametersTerrestrial::Inversion::Off:
2125                 parm_inversion = INVERSION_OFF;
2126                 break;
2127         default:
2128         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
2129                 parm_inversion = INVERSION_AUTO;
2130                 break;
2131         }
2132         return 0;
2133 }
2134
2135 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
2136 {
2137         unsigned int timeout = 5000;
2138         eDebugNoSimulate("(%d)tune", m_dvbid);
2139
2140         m_timeout->stop();
2141
2142         int res=0;
2143
2144         if (!m_sn && !m_simulate)
2145         {
2146                 eDebug("no frontend device opened... do not try to tune !!!");
2147                 res = -ENODEV;
2148                 goto tune_error;
2149         }
2150
2151         if (m_type == -1)
2152         {
2153                 res = -ENODEV;
2154                 goto tune_error;
2155         }
2156
2157         if (!m_simulate)
2158                 m_sn->stop();
2159
2160         m_sec_sequence.clear();
2161
2162         where.calcLockTimeout(timeout);
2163
2164         switch (m_type)
2165         {
2166         case feSatellite:
2167         {
2168                 eDVBFrontendParametersSatellite feparm;
2169                 if (where.getDVBS(feparm))
2170                 {
2171                         eDebug("no dvbs data!");
2172                         res = -EINVAL;
2173                         goto tune_error;
2174                 }
2175                 if (!m_simulate)
2176                         m_sec->setRotorMoving(false);
2177                 res=prepare_sat(feparm, timeout);
2178                 if (res)
2179                         goto tune_error;
2180
2181                 break;
2182         }
2183         case feCable:
2184         {
2185                 eDVBFrontendParametersCable feparm;
2186                 if (where.getDVBC(feparm))
2187                 {
2188                         res = -EINVAL;
2189                         goto tune_error;
2190                 }
2191                 res=prepare_cable(feparm);
2192                 if (res)
2193                         goto tune_error;
2194
2195                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2196                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2197                 break;
2198         }
2199         case feTerrestrial:
2200         {
2201                 eDVBFrontendParametersTerrestrial feparm;
2202                 if (where.getDVBT(feparm))
2203                 {
2204                         eDebug("no -T data");
2205                         res = -EINVAL;
2206                         goto tune_error;
2207                 }
2208                 res=prepare_terrestrial(feparm);
2209                 if (res)
2210                         goto tune_error;
2211
2212                 std::string enable_5V;
2213                 char configStr[255];
2214                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2215                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2216                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2217                 if (enable_5V == "True")
2218                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2219                 else
2220                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2221                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2222
2223                 break;
2224         }
2225         }
2226
2227         m_sec_sequence.current() = m_sec_sequence.begin();
2228
2229         if (!m_simulate)
2230         {
2231                 m_tuneTimer->start(0,true);
2232                 if (m_state != stateTuning)
2233                 {
2234                         m_tuning = 1;
2235                         m_state = stateTuning;
2236                         m_stateChanged(this);
2237                 }
2238         }
2239         else
2240                 tuneLoop();
2241
2242         return res;
2243
2244 tune_error:
2245         m_tuneTimer->stop();
2246         return res;
2247 }
2248
2249 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2250 {
2251         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2252         return 0;
2253 }
2254
2255 RESULT eDVBFrontend::setVoltage(int voltage)
2256 {
2257         if (m_type == feCable)
2258                 return -1;
2259 #if HAVE_DVB_API_VERSION < 3
2260         secVoltage vlt;
2261 #else
2262         bool increased=false;
2263         fe_sec_voltage_t vlt;
2264 #endif
2265         m_data[CUR_VOLTAGE]=voltage;
2266         switch (voltage)
2267         {
2268         case voltageOff:
2269                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2270                 vlt = SEC_VOLTAGE_OFF;
2271                 break;
2272         case voltage13_5:
2273 #if HAVE_DVB_API_VERSION < 3
2274                 vlt = SEC_VOLTAGE_13_5;
2275                 break;
2276 #else
2277                 increased = true;
2278 #endif
2279         case voltage13:
2280                 vlt = SEC_VOLTAGE_13;
2281                 break;
2282         case voltage18_5:
2283 #if HAVE_DVB_API_VERSION < 3
2284                 vlt = SEC_VOLTAGE_18_5;
2285                 break;
2286 #else
2287                 increased = true;
2288 #endif
2289         case voltage18:
2290                 vlt = SEC_VOLTAGE_18;
2291                 break;
2292         default:
2293                 return -ENODEV;
2294         }
2295         if (m_simulate)
2296                 return 0;
2297 #if HAVE_DVB_API_VERSION < 3
2298         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2299 #else
2300         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2301                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2302         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2303 #endif
2304 }
2305
2306 RESULT eDVBFrontend::getState(int &state)
2307 {
2308         state = m_state;
2309         return 0;
2310 }
2311
2312 RESULT eDVBFrontend::setTone(int t)
2313 {
2314         if (m_type != feSatellite)
2315                 return -1;
2316 #if HAVE_DVB_API_VERSION < 3
2317         secToneMode_t tone;
2318 #else
2319         fe_sec_tone_mode_t tone;
2320 #endif
2321         m_data[CUR_TONE]=t;
2322         switch (t)
2323         {
2324         case toneOn:
2325                 tone = SEC_TONE_ON;
2326                 break;
2327         case toneOff:
2328                 tone = SEC_TONE_OFF;
2329                 break;
2330         default:
2331                 return -ENODEV;
2332         }
2333         if (m_simulate)
2334                 return 0;
2335 #if HAVE_DVB_API_VERSION < 3    
2336         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2337 #else   
2338         return ::ioctl(m_fd, FE_SET_TONE, tone);
2339 #endif
2340 }
2341
2342 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2343         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2344 #endif
2345
2346 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2347 {
2348         if (m_simulate)
2349                 return 0;
2350 #if HAVE_DVB_API_VERSION < 3
2351         struct secCommand cmd;
2352         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2353         cmd.u.diseqc.cmdtype = diseqc.data[0];
2354         cmd.u.diseqc.addr = diseqc.data[1];
2355         cmd.u.diseqc.cmd = diseqc.data[2];
2356         cmd.u.diseqc.numParams = diseqc.len-3;
2357         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2358         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2359 #else
2360         struct dvb_diseqc_master_cmd cmd;
2361         memcpy(cmd.msg, diseqc.data, diseqc.len);
2362         cmd.msg_len = diseqc.len;
2363         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2364 #endif
2365                 return -EINVAL;
2366         return 0;
2367 }
2368
2369 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2370         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2371 #endif
2372 RESULT eDVBFrontend::sendToneburst(int burst)
2373 {
2374         if (m_simulate)
2375                 return 0;
2376 #if HAVE_DVB_API_VERSION < 3
2377         secMiniCmd cmd = SEC_MINI_NONE;
2378 #else
2379         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2380 #endif
2381         if ( burst == eDVBSatelliteDiseqcParameters::A )
2382                 cmd = SEC_MINI_A;
2383         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2384                 cmd = SEC_MINI_B;
2385 #if HAVE_DVB_API_VERSION < 3
2386         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2387                 return -EINVAL;
2388 #else
2389         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2390                 return -EINVAL;
2391 #endif
2392         return 0;
2393 }
2394
2395 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2396 {
2397         m_sec = sec;
2398         return 0;
2399 }
2400
2401 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2402 {
2403         m_sec_sequence = list;
2404         return 0;
2405 }
2406
2407 RESULT eDVBFrontend::getData(int num, long &data)
2408 {
2409         if ( num < NUM_DATA_ENTRIES )
2410         {
2411                 data = m_data[num];
2412                 return 0;
2413         }
2414         return -EINVAL;
2415 }
2416
2417 RESULT eDVBFrontend::setData(int num, long val)
2418 {
2419         if ( num < NUM_DATA_ENTRIES )
2420         {
2421                 m_data[num] = val;
2422                 return 0;
2423         }
2424         return -EINVAL;
2425 }
2426
2427 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2428 {
2429         int type;
2430         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2431                 return 0;
2432         if (m_type == eDVBFrontend::feSatellite)
2433         {
2434                 ASSERT(m_sec);
2435                 eDVBFrontendParametersSatellite sat_parm;
2436                 int ret = feparm->getDVBS(sat_parm);
2437                 ASSERT(!ret);
2438                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2439                         return 0;
2440                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2441                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2442                         ret -= 1;
2443                 return ret;
2444         }
2445         else if (m_type == eDVBFrontend::feCable)
2446                 return 2;  // more prio for cable frontends
2447         else if (m_type == eDVBFrontend::feTerrestrial)
2448                 return 1;
2449         return 0;
2450 }
2451
2452 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2453 {
2454         ePyObject Id, Descr, Enabled, IsDVBS2;
2455         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 4)
2456                 goto arg_error;
2457         Id = PyTuple_GET_ITEM(obj, 0);
2458         Descr = PyTuple_GET_ITEM(obj, 1);
2459         Enabled = PyTuple_GET_ITEM(obj, 2);
2460         IsDVBS2 = PyTuple_GET_ITEM(obj, 3);
2461         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled) || !PyBool_Check(IsDVBS2))
2462                 goto arg_error;
2463         strcpy(m_description, PyString_AS_STRING(Descr));
2464         m_slotid = PyInt_AsLong(Id);
2465         m_enabled = Enabled == Py_True;
2466         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2467         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2468                 !!strstr(m_description, "Alps BSBE2") ||
2469                 !!strstr(m_description, "Alps -S") ||
2470                 !!strstr(m_description, "BCM4501");
2471         m_can_handle_dvbs2 = IsDVBS2 == Py_True;
2472         eDebugNoSimulate("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2473                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2474         return true;
2475 arg_error:
2476         PyErr_SetString(PyExc_StandardError,
2477                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2478         return false;
2479 }