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