add support for new frontend to set power limiting mode
[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                                 char proc_name[64];
1539                                 sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", m_dvbid);
1540                                 FILE *f=fopen(proc_name, "w");
1541                                 if (f) // new interface exist?
1542                                 {
1543                                         bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1544                                         if (fprintf(f, "%s", slimiting ? "on" : "off") != 1)
1545                                                 eDebug("write %s failed!! (%m)", proc_name);
1546                                         else
1547                                                 eDebug("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1548                                         fclose(f);
1549                                 }
1550                                 else if (m_need_rotor_workaround)
1551                                 {
1552                                         char dev[16];
1553
1554                                         // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1555                                         if (m_slotid < 2)
1556                                                 sprintf(dev, "/dev/i2c/%d", m_slotid);
1557                                         else if (m_slotid == 2)
1558                                                 sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1559                                         else if (m_slotid == 3)
1560                                                 sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1561                                         int fd = ::open(dev, O_RDWR);
1562
1563                                         unsigned char data[2];
1564                                         ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1565                                         if(::read(fd, data, 1) != 1)
1566                                                 eDebug("[SEC] error read lnbp (%m)");
1567                                         if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1568                                         {
1569                                                 data[0] |= 0x80;  // enable static current limiting
1570                                                 eDebug("[SEC] set static current limiting");
1571                                         }
1572                                         else
1573                                         {
1574                                                 data[0] &= ~0x80;  // enable dynamic current limiting
1575                                                 eDebug("[SEC] set dynamic current limiting");
1576                                         }
1577                                         if(::write(fd, data, 1) != 1)
1578                                                 eDebug("[SEC] error write lnbp (%m)");
1579                                         ::close(fd);
1580                                 }
1581                                 ++m_sec_sequence.current();
1582                                 break;
1583                         }
1584                         default:
1585                                 eDebug("[SEC] unhandled sec command %d",
1586                                         ++m_sec_sequence.current()->cmd);
1587                                 ++m_sec_sequence.current();
1588                 }
1589                 m_tuneTimer->start(delay,true);
1590         }
1591 }
1592
1593 void eDVBFrontend::setFrontend()
1594 {
1595         eDebug("setting frontend %d", m_dvbid);
1596         m_sn->start();
1597         feEvent(-1);
1598         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1599         {
1600                 perror("FE_SET_FRONTEND failed");
1601                 return;
1602         }
1603 }
1604
1605 RESULT eDVBFrontend::getFrontendType(int &t)
1606 {
1607         if (m_type == -1)
1608                 return -ENODEV;
1609         t = m_type;
1610         return 0;
1611 }
1612
1613 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1614 {
1615         int res;
1616         if (!m_sec)
1617         {
1618                 eWarning("no SEC module active!");
1619                 return -ENOENT;
1620         }
1621         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1622         if (!res)
1623         {
1624                 eDebug("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1625                         feparm.system,
1626                         feparm.frequency,
1627                         feparm.polarisation,
1628                         feparm.symbol_rate,
1629                         feparm.inversion,
1630                         feparm.fec,
1631                         feparm.orbital_position);
1632                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1633                 switch (feparm.inversion)
1634                 {
1635                         case eDVBFrontendParametersSatellite::Inversion::On:
1636                                 parm_inversion = INVERSION_ON;
1637                                 break;
1638                         case eDVBFrontendParametersSatellite::Inversion::Off:
1639                                 parm_inversion = INVERSION_OFF;
1640                                 break;
1641                         default:
1642                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1643                                 parm_inversion = INVERSION_AUTO;
1644                                 break;
1645                 }
1646                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1647                         switch (feparm.fec)
1648                         {
1649                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1650                                         parm_u_qpsk_fec_inner = FEC_NONE;
1651                                         break;
1652                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1653                                         parm_u_qpsk_fec_inner = FEC_1_2;
1654                                         break;
1655                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1656                                         parm_u_qpsk_fec_inner = FEC_2_3;
1657                                         break;
1658                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1659                                         parm_u_qpsk_fec_inner = FEC_3_4;
1660                                         break;
1661                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1662                                         parm_u_qpsk_fec_inner = FEC_5_6;
1663                                         break;
1664                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1665                                         parm_u_qpsk_fec_inner = FEC_7_8;
1666                                         break;
1667                                 default:
1668                                         eDebug("no valid fec for DVB-S set.. assume auto");
1669                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1670                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1671                                         break;
1672                         }
1673 #if HAVE_DVB_API_VERSION >= 3
1674                 else // DVB_S2
1675                 {
1676                         switch (feparm.fec)
1677                         {
1678                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1679                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1680                                         break;
1681                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1682                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1683                                         break;
1684                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1685                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1686                                         break;
1687                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1688                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1689                                         break;
1690                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1691                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1692                                         break;
1693                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1694                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1695                                         break;
1696                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1697                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1698                                         break;
1699                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1700                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1701                                         break;
1702                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1703                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1704                                         break;
1705                                 default:
1706                                         eDebug("no valid fec for DVB-S2 set.. abort !!");
1707                                         return -EINVAL;
1708                         }
1709                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1710                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1711                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1712                                 // 8PSK fec driver values are decimal 9 bigger
1713                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1714                         }
1715                 }
1716 #endif
1717                 // FIXME !!! get frequency range from tuner
1718                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1719                 {
1720                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1721                         return -EINVAL;
1722                 }
1723                 eDebug("tuning to %d mhz", parm_frequency/1000);
1724         }
1725         return res;
1726 }
1727
1728 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1729 {
1730 #if HAVE_DVB_API_VERSION < 3
1731         parm_frequency = feparm.frequency;
1732 #else
1733         parm_frequency = feparm.frequency * 1000;
1734 #endif
1735         parm_u_qam_symbol_rate = feparm.symbol_rate;
1736         switch (feparm.modulation)
1737         {
1738         case eDVBFrontendParametersCable::Modulation::QAM16:
1739                 parm_u_qam_modulation = QAM_16;
1740                 break;
1741         case eDVBFrontendParametersCable::Modulation::QAM32:
1742                 parm_u_qam_modulation = QAM_32;
1743                 break;
1744         case eDVBFrontendParametersCable::Modulation::QAM64:
1745                 parm_u_qam_modulation = QAM_64;
1746                 break;
1747         case eDVBFrontendParametersCable::Modulation::QAM128:
1748                 parm_u_qam_modulation = QAM_128;
1749                 break;
1750         case eDVBFrontendParametersCable::Modulation::QAM256:
1751                 parm_u_qam_modulation = QAM_256;
1752                 break;
1753         default:
1754         case eDVBFrontendParametersCable::Modulation::Auto:
1755                 parm_u_qam_modulation = QAM_AUTO;
1756                 break;
1757         }
1758         switch (feparm.inversion)
1759         {
1760         case eDVBFrontendParametersCable::Inversion::On:
1761                 parm_inversion = INVERSION_ON;
1762                 break;
1763         case eDVBFrontendParametersCable::Inversion::Off:
1764                 parm_inversion = INVERSION_OFF;
1765                 break;
1766         default:
1767         case eDVBFrontendParametersCable::Inversion::Unknown:
1768                 parm_inversion = INVERSION_AUTO;
1769                 break;
1770         }
1771         switch (feparm.fec_inner)
1772         {
1773         case eDVBFrontendParametersCable::FEC::fNone:
1774                 parm_u_qam_fec_inner = FEC_NONE;
1775                 break;
1776         case eDVBFrontendParametersCable::FEC::f1_2:
1777                 parm_u_qam_fec_inner = FEC_1_2;
1778                 break;
1779         case eDVBFrontendParametersCable::FEC::f2_3:
1780                 parm_u_qam_fec_inner = FEC_2_3;
1781                 break;
1782         case eDVBFrontendParametersCable::FEC::f3_4:
1783                 parm_u_qam_fec_inner = FEC_3_4;
1784                 break;
1785         case eDVBFrontendParametersCable::FEC::f5_6:
1786                 parm_u_qam_fec_inner = FEC_5_6;
1787                 break;
1788         case eDVBFrontendParametersCable::FEC::f7_8:
1789                 parm_u_qam_fec_inner = FEC_7_8;
1790                 break;
1791 #if HAVE_DVB_API_VERSION >= 3
1792         case eDVBFrontendParametersCable::FEC::f8_9:
1793                 parm_u_qam_fec_inner = FEC_8_9;
1794                 break;
1795 #endif
1796         default:
1797         case eDVBFrontendParametersCable::FEC::fAuto:
1798                 parm_u_qam_fec_inner = FEC_AUTO;
1799                 break;
1800         }
1801         eDebug("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1802                 parm_frequency/1000,
1803                 parm_u_qam_symbol_rate,
1804                 parm_u_qam_fec_inner,
1805                 parm_u_qam_modulation,
1806                 parm_inversion);
1807         return 0;
1808 }
1809
1810 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1811 {
1812         parm_frequency = feparm.frequency;
1813
1814         switch (feparm.bandwidth)
1815         {
1816         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1817                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1818                 break;
1819         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1820                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1821                 break;
1822         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1823                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1824                 break;
1825         default:
1826         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1827                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1828                 break;
1829         }
1830         switch (feparm.code_rate_LP)
1831         {
1832         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1833                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1834                 break;
1835         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1836                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1837                 break;
1838         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1839                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1840                 break;
1841         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1842                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1843                 break;
1844         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1845                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1846                 break;
1847         default:
1848         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1849                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1850                 break;
1851         }
1852         switch (feparm.code_rate_HP)
1853         {
1854         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1855                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1856                 break;
1857         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1858                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1859                 break;
1860         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1861                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1862                 break;
1863         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1864                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1865                 break;
1866         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1867                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1868                 break;
1869         default:
1870         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1871                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1872                 break;
1873         }
1874         switch (feparm.modulation)
1875         {
1876         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1877                 parm_u_ofdm_constellation = QPSK;
1878                 break;
1879         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1880                 parm_u_ofdm_constellation = QAM_16;
1881                 break;
1882         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
1883                 parm_u_ofdm_constellation = QAM_64;
1884                 break;
1885         default:
1886         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1887                 parm_u_ofdm_constellation = QAM_AUTO;
1888                 break;
1889         }
1890         switch (feparm.transmission_mode)
1891         {
1892         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1893                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1894                 break;
1895         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1896                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1897                 break;
1898         default:
1899         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1900                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1901                 break;
1902         }
1903         switch (feparm.guard_interval)
1904         {
1905                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
1906                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
1907                         break;
1908                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
1909                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
1910                         break;
1911                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
1912                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
1913                         break;
1914                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
1915                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
1916                         break;
1917                 default:
1918                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
1919                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
1920                         break;
1921         }
1922         switch (feparm.hierarchy)
1923         {
1924                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
1925                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
1926                         break;
1927                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
1928                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
1929                         break;
1930                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
1931                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
1932                         break;
1933                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
1934                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
1935                         break;
1936                 default:
1937                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
1938                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
1939                         break;
1940         }
1941         switch (feparm.inversion)
1942         {
1943         case eDVBFrontendParametersTerrestrial::Inversion::On:
1944                 parm_inversion = INVERSION_ON;
1945                 break;
1946         case eDVBFrontendParametersTerrestrial::Inversion::Off:
1947                 parm_inversion = INVERSION_OFF;
1948                 break;
1949         default:
1950         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
1951                 parm_inversion = INVERSION_AUTO;
1952                 break;
1953         }
1954         return 0;
1955 }
1956
1957 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
1958 {
1959         unsigned int timeout = 5000;
1960         eDebug("(%d)tune", m_dvbid);
1961
1962         m_timeout->stop();
1963
1964         int res=0;
1965
1966         if (!m_sn)
1967         {
1968                 eDebug("no frontend device opened... do not try to tune !!!");
1969                 res = -ENODEV;
1970                 goto tune_error;
1971         }
1972
1973         if (m_type == -1)
1974         {
1975                 res = -ENODEV;
1976                 goto tune_error;
1977         }
1978
1979         m_sn->stop();
1980         m_sec_sequence.clear();
1981
1982         where.calcLockTimeout(timeout);
1983
1984         switch (m_type)
1985         {
1986         case feSatellite:
1987         {
1988                 eDVBFrontendParametersSatellite feparm;
1989                 if (where.getDVBS(feparm))
1990                 {
1991                         eDebug("no dvbs data!");
1992                         res = -EINVAL;
1993                         goto tune_error;
1994                 }
1995                 m_sec->setRotorMoving(false);
1996                 res=prepare_sat(feparm, timeout);
1997                 if (res)
1998                         goto tune_error;
1999
2000                 break;
2001         }
2002         case feCable:
2003         {
2004                 eDVBFrontendParametersCable feparm;
2005                 if (where.getDVBC(feparm))
2006                 {
2007                         res = -EINVAL;
2008                         goto tune_error;
2009                 }
2010                 res=prepare_cable(feparm);
2011                 if (res)
2012                         goto tune_error;
2013
2014                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2015                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2016                 break;
2017         }
2018         case feTerrestrial:
2019         {
2020                 eDVBFrontendParametersTerrestrial feparm;
2021                 if (where.getDVBT(feparm))
2022                 {
2023                         eDebug("no -T data");
2024                         res = -EINVAL;
2025                         goto tune_error;
2026                 }
2027                 res=prepare_terrestrial(feparm);
2028                 if (res)
2029                         goto tune_error;
2030
2031                 std::string enable_5V;
2032                 char configStr[255];
2033                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2034                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2035                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2036                 if (enable_5V == "True")
2037                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2038                 else
2039                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2040                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2041
2042                 break;
2043         }
2044         }
2045
2046         m_tuneTimer->start(0,true);
2047         m_sec_sequence.current() = m_sec_sequence.begin();
2048
2049         if (m_state != stateTuning)
2050         {
2051                 m_tuning = 1;
2052                 m_state = stateTuning;
2053                 m_stateChanged(this);
2054         }
2055
2056         return res;
2057
2058 tune_error:
2059         m_tuneTimer->stop();
2060         return res;
2061 }
2062
2063 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2064 {
2065         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2066         return 0;
2067 }
2068
2069 RESULT eDVBFrontend::setVoltage(int voltage)
2070 {
2071         if (m_type == feCable)
2072                 return -1;
2073 #if HAVE_DVB_API_VERSION < 3
2074         secVoltage vlt;
2075 #else
2076         bool increased=false;
2077         fe_sec_voltage_t vlt;
2078 #endif
2079         m_data[CUR_VOLTAGE]=voltage;
2080         switch (voltage)
2081         {
2082         case voltageOff:
2083                 for (int i=0; i < 3; ++i)  // reset diseqc
2084                         m_data[i]=-1;
2085                 vlt = SEC_VOLTAGE_OFF;
2086                 break;
2087         case voltage13_5:
2088 #if HAVE_DVB_API_VERSION < 3
2089                 vlt = SEC_VOLTAGE_13_5;
2090                 break;
2091 #else
2092                 increased = true;
2093 #endif
2094         case voltage13:
2095                 vlt = SEC_VOLTAGE_13;
2096                 break;
2097         case voltage18_5:
2098 #if HAVE_DVB_API_VERSION < 3
2099                 vlt = SEC_VOLTAGE_18_5;
2100                 break;
2101 #else
2102                 increased = true;
2103 #endif
2104         case voltage18:
2105                 vlt = SEC_VOLTAGE_18;
2106                 break;
2107         default:
2108                 return -ENODEV;
2109         }
2110 #if HAVE_DVB_API_VERSION < 3
2111         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2112 #else
2113         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2114                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2115         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2116 #endif
2117 }
2118
2119 RESULT eDVBFrontend::getState(int &state)
2120 {
2121         state = m_state;
2122         return 0;
2123 }
2124
2125 RESULT eDVBFrontend::setTone(int t)
2126 {
2127         if (m_type != feSatellite)
2128                 return -1;
2129 #if HAVE_DVB_API_VERSION < 3
2130         secToneMode_t tone;
2131 #else
2132         fe_sec_tone_mode_t tone;
2133 #endif
2134         m_data[CUR_TONE]=t;
2135         switch (t)
2136         {
2137         case toneOn:
2138                 tone = SEC_TONE_ON;
2139                 break;
2140         case toneOff:
2141                 tone = SEC_TONE_OFF;
2142                 break;
2143         default:
2144                 return -ENODEV;
2145         }
2146 #if HAVE_DVB_API_VERSION < 3    
2147         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2148 #else   
2149         return ::ioctl(m_fd, FE_SET_TONE, tone);
2150 #endif
2151 }
2152
2153 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2154         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2155 #endif
2156
2157 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2158 {
2159 #if HAVE_DVB_API_VERSION < 3
2160         struct secCommand cmd;
2161         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2162         cmd.u.diseqc.cmdtype = diseqc.data[0];
2163         cmd.u.diseqc.addr = diseqc.data[1];
2164         cmd.u.diseqc.cmd = diseqc.data[2];
2165         cmd.u.diseqc.numParams = diseqc.len-3;
2166         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2167         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2168 #else
2169         struct dvb_diseqc_master_cmd cmd;
2170         memcpy(cmd.msg, diseqc.data, diseqc.len);
2171         cmd.msg_len = diseqc.len;
2172         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2173 #endif
2174                 return -EINVAL;
2175         return 0;
2176 }
2177
2178 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2179         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2180 #endif
2181 RESULT eDVBFrontend::sendToneburst(int burst)
2182 {
2183 #if HAVE_DVB_API_VERSION < 3
2184         secMiniCmd cmd = SEC_MINI_NONE;
2185 #else
2186         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2187 #endif
2188         if ( burst == eDVBSatelliteDiseqcParameters::A )
2189                 cmd = SEC_MINI_A;
2190         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2191                 cmd = SEC_MINI_B;
2192 #if HAVE_DVB_API_VERSION < 3
2193         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2194                 return -EINVAL;
2195 #else
2196         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2197                 return -EINVAL;
2198 #endif
2199         return 0;
2200 }
2201
2202 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2203 {
2204         m_sec = sec;
2205         return 0;
2206 }
2207
2208 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2209 {
2210         m_sec_sequence = list;
2211         return 0;
2212 }
2213
2214 RESULT eDVBFrontend::getData(int num, long &data)
2215 {
2216         if ( num < NUM_DATA_ENTRIES )
2217         {
2218                 data = m_data[num];
2219                 return 0;
2220         }
2221         return -EINVAL;
2222 }
2223
2224 RESULT eDVBFrontend::setData(int num, long val)
2225 {
2226         if ( num < NUM_DATA_ENTRIES )
2227         {
2228                 m_data[num] = val;
2229                 return 0;
2230         }
2231         return -EINVAL;
2232 }
2233
2234 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2235 {
2236         int type;
2237         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2238                 return 0;
2239
2240         if (m_type == eDVBFrontend::feSatellite)
2241         {
2242                 ASSERT(m_sec);
2243                 eDVBFrontendParametersSatellite sat_parm;
2244                 int ret = feparm->getDVBS(sat_parm);
2245                 ASSERT(!ret);
2246                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2247                         return 0;
2248                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2249                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2250                         ret -= 1;
2251         }
2252         else if (m_type == eDVBFrontend::feCable)
2253                 return 2;  // more prio for cable frontends
2254         return 1;
2255 }
2256
2257 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2258 {
2259         ePyObject Id, Descr, Enabled;
2260         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 3)
2261                 goto arg_error;
2262         Id = PyTuple_GET_ITEM(obj, 0);
2263         Descr = PyTuple_GET_ITEM(obj, 1);
2264         Enabled = PyTuple_GET_ITEM(obj, 2);
2265         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled))
2266                 goto arg_error;
2267         strcpy(m_description, PyString_AS_STRING(Descr));
2268         m_slotid = PyInt_AsLong(Id);
2269         m_enabled = Enabled == Py_True;
2270         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2271         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2272                 !!strstr(m_description, "Alps BSBE2") ||
2273                 !!strstr(m_description, "Alps -S") ||
2274                 !!strstr(m_description, "BCM4501");
2275         m_can_handle_dvbs2 = !!strstr(m_description, "Alps BSBE2") || !!strstr(m_description, "BCM4501");
2276         eDebug("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2277                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2278         return true;
2279 arg_error:
2280         PyErr_SetString(PyExc_StandardError,
2281                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2282         return false;
2283 }