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