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