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