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