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