02297243160044ce6d29855f0b422b4ab8bf18ce
[vuplus_dvbapp] / 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=stateIdle;
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, false);
528         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
529
530         return 0;
531 }
532
533 int eDVBFrontend::closeFrontend(bool force)
534 {
535         if (!force && m_data[CUR_VOLTAGE] != -1 && m_data[CUR_VOLTAGE] != iDVBFrontend::voltageOff)
536         {
537                 long tmp = m_data[LINKED_NEXT_PTR];
538                 while (tmp != -1)
539                 {
540                         eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
541                         if (linked_fe->m_inuse)
542                         {
543                                 eDebug("dont close frontend %d until the linked frontend %d in slot %d is still in use",
544                                         m_dvbid, linked_fe->m_frontend->getDVBID(), linked_fe->m_frontend->getSlotID());
545                                 return -1;
546                         }
547                         linked_fe->m_frontend->getData(LINKED_NEXT_PTR, tmp);
548                 }
549         }
550         if (m_fd >= 0)
551         {
552                 eDebug("close frontend %d", m_dvbid);
553                 m_tuneTimer->stop();
554                 setTone(iDVBFrontend::toneOff);
555                 setVoltage(iDVBFrontend::voltageOff);
556                 if (m_sec)
557                         m_sec->setRotorMoving(false);
558                 if (!::close(m_fd))
559                         m_fd=-1;
560                 else
561                         eWarning("couldnt close frontend %d", m_dvbid);
562                 m_data[CSW] = m_data[UCSW] = m_data[TONEBURST] = -1;
563         }
564 #if HAVE_DVB_API_VERSION < 3
565         if (m_secfd >= 0)
566         {
567                 if (!::close(m_secfd))
568                         m_secfd=-1;
569                 else
570                         eWarning("couldnt close sec %d", m_dvbid);
571         }
572 #endif
573         delete m_sn;
574         m_sn=0;
575         m_state = stateClosed;
576
577         return 0;
578 }
579
580 eDVBFrontend::~eDVBFrontend()
581 {
582         m_data[LINKED_PREV_PTR] = m_data[LINKED_NEXT_PTR] = -1;
583         closeFrontend();
584         delete m_timeout;
585         delete m_tuneTimer;
586 }
587
588 void eDVBFrontend::feEvent(int w)
589 {
590         while (1)
591         {
592 #if HAVE_DVB_API_VERSION < 3
593                 FrontendEvent event;
594 #else
595                 dvb_frontend_event event;
596 #endif
597                 int res;
598                 int state;
599                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
600
601                 if (res && (errno == EAGAIN))
602                         break;
603
604                 if (res)
605                 {
606                         eWarning("FE_GET_EVENT failed! %m");
607                         return;
608                 }
609
610                 if (w < 0)
611                         continue;
612
613 #if HAVE_DVB_API_VERSION < 3
614                 if (event.type == FE_COMPLETION_EV)
615 #else
616                 eDebug("(%d)fe event: status %x, inversion %s", m_dvbid, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
617                 if (event.status & FE_HAS_LOCK)
618 #endif
619                 {
620                         state = stateLock;
621                 } else
622                 {
623                         if (m_tuning)
624                                 state = stateTuning;
625                         else
626                         {
627                                 eDVBFrontend *sec_fe = this;
628                                 long tmp = m_data[LINKED_PREV_PTR];
629
630                                 eDebug("stateLostLock");
631                                 state = stateLostLock;
632
633                                 while (tmp != -1)
634                                 {
635                                         eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)tmp;
636                                         sec_fe = linked_fe->m_frontend;
637                                         sec_fe->getData(LINKED_NEXT_PTR, tmp);
638                                 }
639                                 sec_fe->m_data[CSW] = sec_fe->m_data[UCSW] = sec_fe->m_data[TONEBURST] = -1; // reset diseqc
640                         }
641                 }
642                 if (m_state != state)
643                 {
644                         m_state = state;
645                         m_stateChanged(this);
646                 }
647         }
648 }
649
650 void eDVBFrontend::timeout()
651 {
652         m_tuning = 0;
653         if (m_state == stateTuning)
654         {
655                 m_state = stateFailed;
656                 m_stateChanged(this);
657         }
658 }
659
660 int eDVBFrontend::readFrontendData(int type)
661 {
662         switch(type)
663         {
664                 case bitErrorRate:
665                 {
666                         uint32_t ber=0;
667                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
668                                 eDebug("FE_READ_BER failed (%m)");
669                         return ber;
670                 }
671                 case signalQuality:
672                 {
673                         uint16_t snr=0;
674                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
675                                 eDebug("FE_READ_SNR failed (%m)");
676                         return snr;
677                 }
678                 case signalQualitydB: /* this will move into the driver */
679                 {
680                         uint16_t snr=0;
681                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
682                                 eDebug("FE_READ_SNR failed (%m)");
683                         if (!strcmp(m_description, "BCM4501 (internal)"))
684                         {
685                                 unsigned int SDS_SNRE = snr << 16;
686
687                                 static float SNR_COEFF[6] = {
688                                         100.0 / 4194304.0,
689                                         -7136.0 / 4194304.0,
690                                         197418.0 / 4194304.0,
691                                         -2602183.0 / 4194304.0,
692                                         20377212.0 / 4194304.0,
693                                         -37791203.0 / 4194304.0,
694                                 };
695                         
696                                 float fval1, fval2, snr_in_db;
697                                 int i;
698                                 fval1 = 12.44714 - (2.0 * log10(SDS_SNRE / 256.0));
699                                 fval2 = pow(10.0, fval1)-1;
700                                 fval1 = 10.0 * log10(fval2);
701                         
702                                 if (fval1 < 10.0)
703                                 {
704                                         fval2 = SNR_COEFF[0];
705                                         for (i=0; i<6; ++i)
706                                         {
707                                                 fval2 *= fval1;
708                                                 fval2 += SNR_COEFF[i];
709                                         }
710                                         fval1 = fval2;
711                                 }
712                                 snr_in_db = fval1;
713                         
714                                 return (int)(snr_in_db * 100.0);
715                         }
716                         else if (!strcmp(m_description, "Alps BSBE1 702A") ||  // some frontends with STV0299
717                                 !strcmp(m_description, "Alps -S") ||
718                                 !strcmp(m_description, "Philips -S") ||
719                                 !strcmp(m_description, "LG -S") )
720                         {
721                                 float snr_in_db=(snr-39075)/1764.7;
722                                 return (int)(snr_in_db * 100.0);
723                         } else if (!strcmp(m_description, "Alps BSBE2"))
724                         {
725                                 return (int)((snr >> 7) * 10.0);
726                         } /* else
727                                 eDebug("no SNR dB calculation for frontendtype %s yet", m_description); */
728                         return 0x12345678;
729                 }
730                 case signalPower:
731                 {
732                         uint16_t strength=0;
733                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
734                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
735                         return strength;
736                 }
737                 case locked:
738                 {
739 #if HAVE_DVB_API_VERSION < 3
740                         FrontendStatus status=0;
741 #else
742                         fe_status_t status;
743 #endif
744                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
745                                 eDebug("FE_READ_STATUS failed (%m)");
746                         return !!(status&FE_HAS_LOCK);
747                 }
748                 case synced:
749                 {
750 #if HAVE_DVB_API_VERSION < 3
751                         FrontendStatus status=0;
752 #else
753                         fe_status_t status;
754 #endif
755                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
756                                 eDebug("FE_READ_STATUS failed (%m)");
757                         return !!(status&FE_HAS_SYNC);
758                 }
759                 case frontendNumber:
760                         return m_slotid;
761         }
762         return 0;
763 }
764
765 void PutToDict(ePyObject &dict, const char*key, long value)
766 {
767         ePyObject item = PyInt_FromLong(value);
768         if (item)
769         {
770                 if (PyDict_SetItemString(dict, key, item))
771                         eDebug("put %s to dict failed", key);
772                 Py_DECREF(item);
773         }
774         else
775                 eDebug("could not create PyObject for %s", key);
776 }
777
778 void PutToDict(ePyObject &dict, const char*key, ePyObject item)
779 {
780         if (item)
781         {
782                 if (PyDict_SetItemString(dict, key, item))
783                         eDebug("put %s to dict failed", key);
784                 Py_DECREF(item);
785         }
786         else
787                 eDebug("invalid PyObject for %s", key);
788 }
789
790 void PutToDict(ePyObject &dict, const char*key, const char *value)
791 {
792         ePyObject item = PyString_FromString(value);
793         if (item)
794         {
795                 if (PyDict_SetItemString(dict, key, item))
796                         eDebug("put %s to dict failed", key);
797                 Py_DECREF(item);
798         }
799         else
800                 eDebug("could not create PyObject for %s", key);
801 }
802
803 void fillDictWithSatelliteData(ePyObject dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
804 {
805         long freq_offset=0;
806         const char *tmp=0;
807         fe->getData(eDVBFrontend::FREQ_OFFSET, freq_offset);
808         int frequency = parm_frequency + freq_offset;
809         PutToDict(dict, "frequency", frequency);
810         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
811         switch(parm_u_qpsk_fec_inner)
812         {
813         case FEC_1_2:
814                 tmp = "FEC_1_2";
815                 break;
816         case FEC_2_3:
817                 tmp = "FEC_2_3";
818                 break;
819         case FEC_3_4:
820                 tmp = "FEC_3_4";
821                 break;
822         case FEC_5_6:
823                 tmp = "FEC_5_6";
824                 break;
825         case FEC_7_8:
826                 tmp = "FEC_7_8";
827                 break;
828         case FEC_NONE:
829                 tmp = "FEC_NONE";
830         default:
831         case FEC_AUTO:
832                 tmp = "FEC_AUTO";
833                 break;
834 #if HAVE_DVB_API_VERSION >=3
835         case FEC_S2_8PSK_1_2:
836         case FEC_S2_QPSK_1_2:
837                 tmp = "FEC_1_2";
838                 break;
839         case FEC_S2_8PSK_2_3:
840         case FEC_S2_QPSK_2_3:
841                 tmp = "FEC_2_3";
842                 break;
843         case FEC_S2_8PSK_3_4:
844         case FEC_S2_QPSK_3_4:
845                 tmp = "FEC_3_4";
846                 break;
847         case FEC_S2_8PSK_5_6:
848         case FEC_S2_QPSK_5_6:
849                 tmp = "FEC_5_6";
850                 break;
851         case FEC_S2_8PSK_7_8:
852         case FEC_S2_QPSK_7_8:
853                 tmp = "FEC_7_8";
854                 break;
855         case FEC_S2_8PSK_8_9:
856         case FEC_S2_QPSK_8_9:
857                 tmp = "FEC_8_9";
858                 break;
859         case FEC_S2_8PSK_3_5:
860         case FEC_S2_QPSK_3_5:
861                 tmp = "FEC_3_5";
862                 break;
863         case FEC_S2_8PSK_4_5:
864         case FEC_S2_QPSK_4_5:
865                 tmp = "FEC_4_5";
866                 break;
867         case FEC_S2_8PSK_9_10:
868         case FEC_S2_QPSK_9_10:
869                 tmp = "FEC_9_10";
870                 break;
871 #endif
872         }
873         PutToDict(dict, "fec_inner", tmp);
874 #if HAVE_DVB_API_VERSION >=3
875         PutToDict(dict, "modulation",
876                 parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10 ? "8PSK": "QPSK" );
877         if (parm_u_qpsk_fec_inner > FEC_AUTO)
878         {
879                 switch(parm_inversion & 0xc)
880                 {
881                 default: // unknown rolloff
882                 case 0: // 0.35
883                         tmp = "ROLLOFF_0_35";
884                         break;
885                 case 4: // 0.25
886                         tmp = "ROLLOFF_0_25";
887                         break;
888                 case 8: // 0.20
889                         tmp = "ROLLOFF_0_20";
890                         break;
891                 }
892                 PutToDict(dict, "rolloff", tmp);
893                 if (parm_u_qpsk_fec_inner > FEC_S2_QPSK_9_10)
894                 {
895                         switch(parm_inversion & 0x30)
896                         {
897                         case 0: // pilot off
898                                 tmp = "PILOT_OFF";
899                                 break;
900                         case 0x10: // pilot on
901                                 tmp = "PILOT_ON";
902                                 break;
903                         case 0x20: // pilot auto
904                                 tmp = "PILOT_AUTO";
905                                 break;
906                         }
907                         PutToDict(dict, "pilot", tmp);
908                 }
909                 tmp = "DVB-S2";
910         }
911         else
912                 tmp = "DVB-S";
913 #else
914         PutToDict(dict, "modulation", "QPSK" );
915         tmp = "DVB-S";
916 #endif
917         PutToDict(dict, "system", tmp);
918 }
919
920 void fillDictWithCableData(ePyObject dict, const FRONTENDPARAMETERS &parm)
921 {
922         const char *tmp=0;
923 #if HAVE_DVB_API_VERSION < 3
924         PutToDict(dict, "frequency", parm_frequency);
925 #else
926         PutToDict(dict, "frequency", parm_frequency/1000);
927 #endif
928         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
929         switch(parm_u_qam_fec_inner)
930         {
931         case FEC_NONE:
932                 tmp = "FEC_NONE";
933                 break;
934         case FEC_1_2:
935                 tmp = "FEC_1_2";
936                 break;
937         case FEC_2_3:
938                 tmp = "FEC_2_3";
939                 break;
940         case FEC_3_4:
941                 tmp = "FEC_3_4";
942                 break;
943         case FEC_5_6:
944                 tmp = "FEC_5_6";
945                 break;
946         case FEC_7_8:
947                 tmp = "FEC_7_8";
948                 break;
949 #if HAVE_DVB_API_VERSION >= 3
950         case FEC_8_9:
951                 tmp = "FEC_8_9";
952                 break;
953 #endif
954         default:
955         case FEC_AUTO:
956                 tmp = "FEC_AUTO";
957                 break;
958         }
959         PutToDict(dict, "fec_inner", tmp);
960         switch(parm_u_qam_modulation)
961         {
962         case QAM_16:
963                 tmp = "QAM_16";
964                 break;
965         case QAM_32:
966                 tmp = "QAM_32";
967                 break;
968         case QAM_64:
969                 tmp = "QAM_64";
970                 break;
971         case QAM_128:
972                 tmp = "QAM_128";
973                 break;
974         case QAM_256:
975                 tmp = "QAM_256";
976                 break;
977         default:
978         case QAM_AUTO:
979                 tmp = "QAM_AUTO";
980                 break;
981         }
982         PutToDict(dict, "modulation", tmp);
983 }
984
985 void fillDictWithTerrestrialData(ePyObject dict, const FRONTENDPARAMETERS &parm)
986 {
987         const char *tmp=0;
988         PutToDict(dict, "frequency", parm_frequency);
989         switch (parm_u_ofdm_bandwidth)
990         {
991         case BANDWIDTH_8_MHZ:
992                 tmp = "BANDWIDTH_8_MHZ";
993                 break;
994         case BANDWIDTH_7_MHZ:
995                 tmp = "BANDWIDTH_7_MHZ";
996                 break;
997         case BANDWIDTH_6_MHZ:
998                 tmp = "BANDWIDTH_6_MHZ";
999                 break;
1000         default:
1001         case BANDWIDTH_AUTO:
1002                 tmp = "BANDWIDTH_AUTO";
1003                 break;
1004         }
1005         PutToDict(dict, "bandwidth", tmp);
1006         switch (parm_u_ofdm_code_rate_LP)
1007         {
1008         case FEC_1_2:
1009                 tmp = "FEC_1_2";
1010                 break;
1011         case FEC_2_3:
1012                 tmp = "FEC_2_3";
1013                 break;
1014         case FEC_3_4:
1015                 tmp = "FEC_3_4";
1016                 break;
1017         case FEC_5_6:
1018                 tmp = "FEC_5_6";
1019                 break;
1020         case FEC_7_8:
1021                 tmp = "FEC_7_8";
1022                 break;
1023         default:
1024         case FEC_AUTO:
1025                 tmp = "FEC_AUTO";
1026                 break;
1027         }
1028         PutToDict(dict, "code_rate_lp", tmp);
1029         switch (parm_u_ofdm_code_rate_HP)
1030         {
1031         case FEC_1_2:
1032                 tmp = "FEC_1_2";
1033                 break;
1034         case FEC_2_3:
1035                 tmp = "FEC_2_3";
1036                 break;
1037         case FEC_3_4:
1038                 tmp = "FEC_3_4";
1039                 break;
1040         case FEC_5_6:
1041                 tmp = "FEC_5_6";
1042                 break;
1043         case FEC_7_8:
1044                 tmp = "FEC_7_8";
1045                 break;
1046         default:
1047         case FEC_AUTO:
1048                 tmp = "FEC_AUTO";
1049                 break;
1050         }
1051         PutToDict(dict, "code_rate_hp", tmp);
1052         switch (parm_u_ofdm_constellation)
1053         {
1054         case QPSK:
1055                 tmp = "QPSK";
1056                 break;
1057         case QAM_16:
1058                 tmp = "QAM_16";
1059                 break;
1060         case QAM_64:
1061                 tmp = "QAM_64";
1062                 break;
1063         default:
1064         case QAM_AUTO:
1065                 tmp = "QAM_AUTO";
1066                 break;
1067         }
1068         PutToDict(dict, "constellation", tmp);
1069         switch (parm_u_ofdm_transmission_mode)
1070         {
1071         case TRANSMISSION_MODE_2K:
1072                 tmp = "TRANSMISSION_MODE_2K";
1073                 break;
1074         case TRANSMISSION_MODE_8K:
1075                 tmp = "TRANSMISSION_MODE_8K";
1076                 break;
1077         default:
1078         case TRANSMISSION_MODE_AUTO:
1079                 tmp = "TRANSMISSION_MODE_AUTO";
1080                 break;
1081         }
1082         PutToDict(dict, "transmission_mode", tmp);
1083         switch (parm_u_ofdm_guard_interval)
1084         {
1085                 case GUARD_INTERVAL_1_32:
1086                         tmp = "GUARD_INTERVAL_1_32";
1087                         break;
1088                 case GUARD_INTERVAL_1_16:
1089                         tmp = "GUARD_INTERVAL_1_16";
1090                         break;
1091                 case GUARD_INTERVAL_1_8:
1092                         tmp = "GUARD_INTERVAL_1_8";
1093                         break;
1094                 case GUARD_INTERVAL_1_4:
1095                         tmp = "GUARD_INTERVAL_1_4";
1096                         break;
1097                 default:
1098                 case GUARD_INTERVAL_AUTO:
1099                         tmp = "GUARD_INTERVAL_AUTO";
1100                         break;
1101         }
1102         PutToDict(dict, "guard_interval", tmp);
1103         switch (parm_u_ofdm_hierarchy_information)
1104         {
1105                 case HIERARCHY_NONE:
1106                         tmp = "HIERARCHY_NONE";
1107                         break;
1108                 case HIERARCHY_1:
1109                         tmp = "HIERARCHY_1";
1110                         break;
1111                 case HIERARCHY_2:
1112                         tmp = "HIERARCHY_2";
1113                         break;
1114                 case HIERARCHY_4:
1115                         tmp = "HIERARCHY_4";
1116                         break;
1117                 default:
1118                 case HIERARCHY_AUTO:
1119                         tmp = "HIERARCHY_AUTO";
1120                         break;
1121         }
1122         PutToDict(dict, "hierarchy_information", tmp);
1123 }
1124
1125 void eDVBFrontend::getFrontendStatus(ePyObject dest)
1126 {
1127         if (dest && PyDict_Check(dest))
1128         {
1129                 const char *tmp = "UNKNOWN";
1130                 switch(m_state)
1131                 {
1132                         case stateIdle:
1133                                 tmp="IDLE";
1134                                 break;
1135                         case stateTuning:
1136                                 tmp="TUNING";
1137                                 break;
1138                         case stateFailed:
1139                                 tmp="FAILED";
1140                                 break;
1141                         case stateLock:
1142                                 tmp="LOCKED";
1143                                 break;
1144                         case stateLostLock:
1145                                 tmp="LOSTLOCK";
1146                                 break;
1147                         default:
1148                                 break;
1149                 }
1150                 PutToDict(dest, "tuner_state", tmp);
1151                 PutToDict(dest, "tuner_locked", readFrontendData(locked));
1152                 PutToDict(dest, "tuner_synced", readFrontendData(synced));
1153                 PutToDict(dest, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
1154                 PutToDict(dest, "tuner_signal_quality", readFrontendData(signalQuality));
1155                 int sigQualitydB = readFrontendData(signalQualitydB);
1156                 if (sigQualitydB == 0x12345678) // not support yet
1157                 {
1158                         ePyObject obj=Py_None;
1159                         Py_INCREF(obj);
1160                         PutToDict(dest, "tuner_signal_quality_db", obj);
1161                 }
1162                 else
1163                         PutToDict(dest, "tuner_signal_quality_db", sigQualitydB);
1164                 PutToDict(dest, "tuner_signal_power", readFrontendData(signalPower));
1165         }
1166 }
1167
1168 void eDVBFrontend::getTransponderData(ePyObject dest, bool original)
1169 {
1170         if (m_fd != -1 && dest && PyDict_Check(dest))
1171         {
1172                 switch(m_type)
1173                 {
1174                         case feSatellite:
1175                         case feCable:
1176                         case feTerrestrial:
1177                         {
1178                                 FRONTENDPARAMETERS front;
1179                                 if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
1180                                         eDebug("FE_GET_FRONTEND (%m)");
1181                                 else
1182                                 {
1183                                         const FRONTENDPARAMETERS &parm = original ? this->parm : front;
1184                                         const char *tmp = "INVERSION_AUTO";
1185                                         switch(parm_inversion)
1186                                         {
1187                                                 case INVERSION_ON:
1188                                                         tmp = "INVERSION_ON";
1189                                                         break;
1190                                                 case INVERSION_OFF:
1191                                                         tmp = "INVERSION_OFF";
1192                                                         break;
1193                                                 default:
1194                                                         break;
1195                                         }
1196                                         if (tmp)
1197                                                 PutToDict(dest, "inversion", tmp);
1198
1199                                         switch(m_type)
1200                                         {
1201                                                 case feSatellite:
1202                                                         fillDictWithSatelliteData(dest, original?parm:front, this);
1203                                                         break;
1204                                                 case feCable:
1205                                                         fillDictWithCableData(dest, original?parm:front);
1206                                                         break;
1207                                                 case feTerrestrial:
1208                                                         fillDictWithTerrestrialData(dest, original?parm:front);
1209                                                         break;
1210                                         }
1211                                 }
1212                         }
1213                         default:
1214                                 break;
1215                 }
1216         }
1217 }
1218
1219 void eDVBFrontend::getFrontendData(ePyObject dest)
1220 {
1221         if (dest && PyDict_Check(dest))
1222         {
1223                 const char *tmp=0;
1224                 PutToDict(dest, "tuner_number", m_slotid);
1225                 switch(m_type)
1226                 {
1227                         case feSatellite:
1228                                 tmp = "DVB-S";
1229                                 break;
1230                         case feCable:
1231                                 tmp = "DVB-C";
1232                                 break;
1233                         case feTerrestrial:
1234                                 tmp = "DVB-T";
1235                                 break;
1236                         default:
1237                                 tmp = "UNKNOWN";
1238                                 break;
1239                 }
1240                 PutToDict(dest, "tuner_type", tmp);
1241         }
1242 }
1243
1244 #ifndef FP_IOCTL_GET_ID
1245 #define FP_IOCTL_GET_ID 0
1246 #endif
1247 int eDVBFrontend::readInputpower()
1248 {
1249         int power=m_slotid;  // this is needed for read inputpower from the correct tuner !
1250         char proc_name[64];
1251         sprintf(proc_name, "/proc/stb/fp/lnb_sense%d", m_slotid);
1252         FILE *f=fopen(proc_name, "r");
1253         if (f)
1254         {
1255                 if (fscanf(f, "%d", &power) != 1)
1256                         eDebug("read %s failed!! (%m)", proc_name);
1257                 else
1258                         eDebug("%s is %d\n", proc_name, power);
1259                 fclose(f);
1260         }
1261         else
1262         {
1263                 // open front prozessor
1264                 int fp=::open("/dev/dbox/fp0", O_RDWR);
1265                 if (fp < 0)
1266                 {
1267                         eDebug("couldn't open fp");
1268                         return -1;
1269                 }
1270                 static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1271                 if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1272                 {
1273                         eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1274                         return -1;
1275                 }
1276                 ::close(fp);
1277         }
1278
1279         return power;
1280 }
1281
1282 bool eDVBFrontend::setSecSequencePos(int steps)
1283 {
1284         eDebug("set sequence pos %d", steps);
1285         if (!steps)
1286                 return false;
1287         while( steps > 0 )
1288         {
1289                 if (m_sec_sequence.current() != m_sec_sequence.end())
1290                         ++m_sec_sequence.current();
1291                 --steps;
1292         }
1293         while( steps < 0 )
1294         {
1295                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1296                         --m_sec_sequence.current();
1297                 ++steps;
1298         }
1299         return true;
1300 }
1301
1302 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1303 {
1304         int delay=0;
1305         eDVBFrontend *sec_fe = this;
1306         eDVBRegisteredFrontend *regFE = 0;
1307         long tmp = m_data[LINKED_PREV_PTR];
1308         while ( tmp != -1 )
1309         {
1310                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)tmp;
1311                 sec_fe = prev->m_frontend;
1312                 tmp = prev->m_frontend->m_data[LINKED_PREV_PTR];
1313                 if (tmp == -1 && sec_fe != this && !prev->m_inuse) {
1314                         int state = sec_fe->m_state;
1315                         if (state != eDVBFrontend::stateIdle && state != stateClosed)
1316                         {
1317                                 sec_fe->closeFrontend(true);
1318                                 state = sec_fe->m_state;
1319                         }
1320                         if (state == eDVBFrontend::stateClosed)
1321                         {
1322                                 regFE = prev;
1323                                 prev->inc_use();
1324                         }
1325                 }
1326         }
1327
1328         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1329         {
1330                 long *sec_fe_data = sec_fe->m_data;
1331 //              eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1332                 switch (m_sec_sequence.current()->cmd)
1333                 {
1334                         case eSecCommand::SLEEP:
1335                                 delay = m_sec_sequence.current()++->msec;
1336                                 eDebug("[SEC] sleep %dms", delay);
1337                                 break;
1338                         case eSecCommand::GOTO:
1339                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1340                                         ++m_sec_sequence.current();
1341                                 break;
1342                         case eSecCommand::SET_VOLTAGE:
1343                         {
1344                                 int voltage = m_sec_sequence.current()++->voltage;
1345                                 eDebug("[SEC] setVoltage %d", voltage);
1346                                 sec_fe->setVoltage(voltage);
1347                                 break;
1348                         }
1349                         case eSecCommand::IF_VOLTAGE_GOTO:
1350                         {
1351                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1352                                 if ( compare.voltage == sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1353                                         break;
1354                                 ++m_sec_sequence.current();
1355                                 break;
1356                         }
1357                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1358                         {
1359                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1360                                 if ( compare.voltage != sec_fe_data[CUR_VOLTAGE] && setSecSequencePos(compare.steps) )
1361                                         break;
1362                                 ++m_sec_sequence.current();
1363                                 break;
1364                         }
1365                         case eSecCommand::IF_TONE_GOTO:
1366                         {
1367                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1368                                 if ( compare.tone == sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1369                                         break;
1370                                 ++m_sec_sequence.current();
1371                                 break;
1372                         }
1373                         case eSecCommand::IF_NOT_TONE_GOTO:
1374                         {
1375                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1376                                 if ( compare.tone != sec_fe_data[CUR_TONE] && setSecSequencePos(compare.steps) )
1377                                         break;
1378                                 ++m_sec_sequence.current();
1379                                 break;
1380                         }
1381                         case eSecCommand::SET_TONE:
1382                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
1383                                 sec_fe->setTone(m_sec_sequence.current()++->tone);
1384                                 break;
1385                         case eSecCommand::SEND_DISEQC:
1386                                 sec_fe->sendDiseqc(m_sec_sequence.current()->diseqc);
1387                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
1388                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1389                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1390                                 eDebug("");
1391                                 ++m_sec_sequence.current();
1392                                 break;
1393                         case eSecCommand::SEND_TONEBURST:
1394                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1395                                 sec_fe->sendToneburst(m_sec_sequence.current()++->toneburst);
1396                                 break;
1397                         case eSecCommand::SET_FRONTEND:
1398                                 eDebug("[SEC] setFrontend");
1399                                 setFrontend();
1400                                 ++m_sec_sequence.current();
1401                                 break;
1402                         case eSecCommand::START_TUNE_TIMEOUT:
1403                         {
1404                                 m_timeout->start(m_sec_sequence.current()->timeout, 1);
1405                                 ++m_sec_sequence.current();
1406                                 break;
1407                         }
1408                         case eSecCommand::SET_TIMEOUT:
1409                                 m_timeoutCount = m_sec_sequence.current()++->val;
1410                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
1411                                 break;
1412                         case eSecCommand::IF_TIMEOUT_GOTO:
1413                                 if (!m_timeoutCount)
1414                                 {
1415                                         eDebug("[SEC] rotor timout");
1416                                         m_sec->setRotorMoving(false);
1417                                         setSecSequencePos(m_sec_sequence.current()->steps);
1418                                 }
1419                                 else
1420                                         ++m_sec_sequence.current();
1421                                 break;
1422                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1423                         {
1424                                 int idx = m_sec_sequence.current()++->val;
1425                                 if ( idx == 0 || idx == 1 )
1426                                 {
1427                                         m_idleInputpower[idx] = sec_fe->readInputpower();
1428                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1429                                 }
1430                                 else
1431                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1432                                 break;
1433                         }
1434                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1435                         {
1436                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1437                                 int idx = compare.val;
1438                                 if ( idx == 0 || idx == 1 )
1439                                 {
1440                                         int idle = sec_fe->readInputpower();
1441                                         int diff = abs(idle-m_idleInputpower[idx]);
1442                                         if ( diff > 0)
1443                                         {
1444                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1445                                                 setSecSequencePos(compare.steps);
1446                                                 break;
1447                                         }
1448                                 }
1449                                 ++m_sec_sequence.current();
1450                                 break;
1451                         }
1452                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1453                         {
1454                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1455                                 if (readFrontendData(locked))
1456                                 {
1457                                         eDebug("[SEC] locked step %d ok", cmd.okcount);
1458                                         ++cmd.okcount;
1459                                         if (cmd.okcount > 12)
1460                                         {
1461                                                 eDebug("ok > 12 .. goto %d\n",m_sec_sequence.current()->steps);
1462                                                 setSecSequencePos(cmd.steps);
1463                                                 break;
1464                                         }
1465                                 }
1466                                 else
1467                                 {
1468                                         eDebug("[SEC] rotor locked step %d failed", cmd.okcount);
1469                                         --m_timeoutCount;
1470                                         if (!m_timeoutCount && m_retryCount > 0)
1471                                                 --m_retryCount;
1472                                         cmd.okcount=0;
1473                                 }
1474                                 ++m_sec_sequence.current();
1475                                 break;
1476                         }
1477                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1478                                 m_runningInputpower = sec_fe->readInputpower();
1479                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
1480                                 ++m_sec_sequence.current();
1481                                 break;
1482                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1483                         {
1484                                 int idleInputpower = m_idleInputpower[ (sec_fe_data[CUR_VOLTAGE]&1) ? 0 : 1];
1485                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1486                                 const char *txt = cmd.direction ? "running" : "stopped";
1487                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1488                                         txt,
1489                                         m_runningInputpower,
1490                                         idleInputpower,
1491                                         cmd.deltaA);
1492                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1493                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1494                                 {
1495                                         ++cmd.okcount;
1496                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1497                                         if ( cmd.okcount > 6 )
1498                                         {
1499                                                 m_sec->setRotorMoving(cmd.direction);
1500                                                 eDebug("[SEC] rotor is %s", txt);
1501                                                 if (setSecSequencePos(cmd.steps))
1502                                                         break;
1503                                         }
1504                                 }
1505                                 else
1506                                 {
1507                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1508                                         --m_timeoutCount;
1509                                         if (!m_timeoutCount && m_retryCount > 0)
1510                                                 --m_retryCount;
1511                                         cmd.okcount=0;
1512                                 }
1513                                 ++m_sec_sequence.current();
1514                                 break;
1515                         }
1516                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1517                                 if (sec_fe_data[ROTOR_CMD] != -1 && sec_fe_data[ROTOR_POS] != -1)
1518                                         setSecSequencePos(m_sec_sequence.current()->steps);
1519                                 else
1520                                         ++m_sec_sequence.current();
1521                                 break;
1522                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1523                                 eDebug("[SEC] invalidate current rotorparams");
1524                                 sec_fe_data[ROTOR_CMD] = -1;
1525                                 sec_fe_data[ROTOR_POS] = -1;
1526                                 ++m_sec_sequence.current();
1527                                 break;
1528                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1529                                 sec_fe_data[ROTOR_CMD] = sec_fe_data[NEW_ROTOR_CMD];
1530                                 sec_fe_data[ROTOR_POS] = sec_fe_data[NEW_ROTOR_POS];
1531                                 eDebug("[SEC] update current rotorparams %d %04lx %ld", m_timeoutCount, sec_fe_data[ROTOR_CMD], sec_fe_data[ROTOR_POS]);
1532                                 ++m_sec_sequence.current();
1533                                 break;
1534                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1535                                 m_retryCount = m_sec_sequence.current()++->val;
1536                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
1537                                 break;
1538                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1539                                 if (!m_retryCount)
1540                                 {
1541                                         eDebug("[SEC] no more rotor retrys");
1542                                         setSecSequencePos(m_sec_sequence.current()->steps);
1543                                 }
1544                                 else
1545                                         ++m_sec_sequence.current();
1546                                 break;
1547                         case eSecCommand::SET_POWER_LIMITING_MODE:
1548                         {
1549                                 char proc_name[64];
1550                                 sprintf(proc_name, "/proc/stb/frontend/%d/static_current_limiting", sec_fe->m_dvbid);
1551                                 FILE *f=fopen(proc_name, "w");
1552                                 if (f) // new interface exist?
1553                                 {
1554                                         bool slimiting = m_sec_sequence.current()->mode == eSecCommand::modeStatic;
1555                                         if (fprintf(f, "%s", slimiting ? "on" : "off") <= 0)
1556                                                 eDebug("write %s failed!! (%m)", proc_name);
1557                                         else
1558                                                 eDebug("[SEC] set %s current limiting", slimiting ? "static" : "dynamic");
1559                                         fclose(f);
1560                                 }
1561                                 else if (sec_fe->m_need_rotor_workaround)
1562                                 {
1563                                         char dev[16];
1564                                         int slotid = sec_fe->m_slotid;
1565                                         // FIXMEEEEEE hardcoded i2c devices for dm7025 and dm8000
1566                                         if (slotid < 2)
1567                                                 sprintf(dev, "/dev/i2c/%d", slotid);
1568                                         else if (slotid == 2)
1569                                                 sprintf(dev, "/dev/i2c/2"); // first nim socket on DM8000 use /dev/i2c/2
1570                                         else if (slotid == 3)
1571                                                 sprintf(dev, "/dev/i2c/4"); // second nim socket on DM8000 use /dev/i2c/4
1572                                         int fd = ::open(dev, O_RDWR);
1573
1574                                         unsigned char data[2];
1575                                         ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1576                                         if(::read(fd, data, 1) != 1)
1577                                                 eDebug("[SEC] error read lnbp (%m)");
1578                                         if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1579                                         {
1580                                                 data[0] |= 0x80;  // enable static current limiting
1581                                                 eDebug("[SEC] set static current limiting");
1582                                         }
1583                                         else
1584                                         {
1585                                                 data[0] &= ~0x80;  // enable dynamic current limiting
1586                                                 eDebug("[SEC] set dynamic current limiting");
1587                                         }
1588                                         if(::write(fd, data, 1) != 1)
1589                                                 eDebug("[SEC] error write lnbp (%m)");
1590                                         ::close(fd);
1591                                 }
1592                                 ++m_sec_sequence.current();
1593                                 break;
1594                         }
1595                         default:
1596                                 eDebug("[SEC] unhandled sec command %d",
1597                                         ++m_sec_sequence.current()->cmd);
1598                                 ++m_sec_sequence.current();
1599                 }
1600                 m_tuneTimer->start(delay,true);
1601         }
1602         if (regFE)
1603                 regFE->dec_use();
1604 }
1605
1606 void eDVBFrontend::setFrontend()
1607 {
1608         eDebug("setting frontend %d", m_dvbid);
1609         m_sn->start();
1610         feEvent(-1);
1611         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1612         {
1613                 perror("FE_SET_FRONTEND failed");
1614                 return;
1615         }
1616 }
1617
1618 RESULT eDVBFrontend::getFrontendType(int &t)
1619 {
1620         if (m_type == -1)
1621                 return -ENODEV;
1622         t = m_type;
1623         return 0;
1624 }
1625
1626 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm, unsigned int tunetimeout)
1627 {
1628         int res;
1629         if (!m_sec)
1630         {
1631                 eWarning("no SEC module active!");
1632                 return -ENOENT;
1633         }
1634         res = m_sec->prepare(*this, parm, feparm, 1 << m_slotid, tunetimeout);
1635         if (!res)
1636         {
1637                 eDebug("prepare_sat System %d Freq %d Pol %d SR %d INV %d FEC %d orbpos %d",
1638                         feparm.system,
1639                         feparm.frequency,
1640                         feparm.polarisation,
1641                         feparm.symbol_rate,
1642                         feparm.inversion,
1643                         feparm.fec,
1644                         feparm.orbital_position);
1645                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1646                 switch (feparm.inversion)
1647                 {
1648                         case eDVBFrontendParametersSatellite::Inversion::On:
1649                                 parm_inversion = INVERSION_ON;
1650                                 break;
1651                         case eDVBFrontendParametersSatellite::Inversion::Off:
1652                                 parm_inversion = INVERSION_OFF;
1653                                 break;
1654                         default:
1655                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1656                                 parm_inversion = INVERSION_AUTO;
1657                                 break;
1658                 }
1659                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1660                         switch (feparm.fec)
1661                         {
1662                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1663                                         parm_u_qpsk_fec_inner = FEC_NONE;
1664                                         break;
1665                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1666                                         parm_u_qpsk_fec_inner = FEC_1_2;
1667                                         break;
1668                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1669                                         parm_u_qpsk_fec_inner = FEC_2_3;
1670                                         break;
1671                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1672                                         parm_u_qpsk_fec_inner = FEC_3_4;
1673                                         break;
1674                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1675                                         parm_u_qpsk_fec_inner = FEC_5_6;
1676                                         break;
1677                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1678                                         parm_u_qpsk_fec_inner = FEC_7_8;
1679                                         break;
1680                                 default:
1681                                         eDebug("no valid fec for DVB-S set.. assume auto");
1682                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1683                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1684                                         break;
1685                         }
1686 #if HAVE_DVB_API_VERSION >= 3
1687                 else // DVB_S2
1688                 {
1689                         switch (feparm.fec)
1690                         {
1691                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1692                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_1_2;
1693                                         break;
1694                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1695                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_2_3;
1696                                         break;
1697                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1698                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_4;
1699                                         break;
1700                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1701                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_3_5;
1702                                         break;
1703                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1704                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_4_5;
1705                                         break;
1706                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1707                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_5_6;
1708                                         break;
1709                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1710                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_7_8;
1711                                         break;
1712                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1713                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_8_9;
1714                                         break;
1715                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1716                                         parm_u_qpsk_fec_inner = FEC_S2_QPSK_9_10;
1717                                         break;
1718                                 default:
1719                                         eDebug("no valid fec for DVB-S2 set.. abort !!");
1720                                         return -EINVAL;
1721                         }
1722                         parm_inversion |= (feparm.rolloff << 2); // Hack.. we use bit 2..3 of inversion param for rolloff
1723                         if (feparm.modulation == eDVBFrontendParametersSatellite::Modulation::M8PSK) {
1724                                 parm_u_qpsk_fec_inner = (fe_code_rate_t)((int)parm_u_qpsk_fec_inner+9);
1725                                 // 8PSK fec driver values are decimal 9 bigger
1726                                 parm_inversion |= (feparm.pilot << 4); // Hack.. we use bit 4..5 of inversion param for pilot
1727                         }
1728                 }
1729 #endif
1730                 // FIXME !!! get frequency range from tuner
1731                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1732                 {
1733                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1734                         return -EINVAL;
1735                 }
1736                 eDebug("tuning to %d mhz", parm_frequency/1000);
1737         }
1738         return res;
1739 }
1740
1741 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1742 {
1743 #if HAVE_DVB_API_VERSION < 3
1744         parm_frequency = feparm.frequency;
1745 #else
1746         parm_frequency = feparm.frequency * 1000;
1747 #endif
1748         parm_u_qam_symbol_rate = feparm.symbol_rate;
1749         switch (feparm.modulation)
1750         {
1751         case eDVBFrontendParametersCable::Modulation::QAM16:
1752                 parm_u_qam_modulation = QAM_16;
1753                 break;
1754         case eDVBFrontendParametersCable::Modulation::QAM32:
1755                 parm_u_qam_modulation = QAM_32;
1756                 break;
1757         case eDVBFrontendParametersCable::Modulation::QAM64:
1758                 parm_u_qam_modulation = QAM_64;
1759                 break;
1760         case eDVBFrontendParametersCable::Modulation::QAM128:
1761                 parm_u_qam_modulation = QAM_128;
1762                 break;
1763         case eDVBFrontendParametersCable::Modulation::QAM256:
1764                 parm_u_qam_modulation = QAM_256;
1765                 break;
1766         default:
1767         case eDVBFrontendParametersCable::Modulation::Auto:
1768                 parm_u_qam_modulation = QAM_AUTO;
1769                 break;
1770         }
1771         switch (feparm.inversion)
1772         {
1773         case eDVBFrontendParametersCable::Inversion::On:
1774                 parm_inversion = INVERSION_ON;
1775                 break;
1776         case eDVBFrontendParametersCable::Inversion::Off:
1777                 parm_inversion = INVERSION_OFF;
1778                 break;
1779         default:
1780         case eDVBFrontendParametersCable::Inversion::Unknown:
1781                 parm_inversion = INVERSION_AUTO;
1782                 break;
1783         }
1784         switch (feparm.fec_inner)
1785         {
1786         case eDVBFrontendParametersCable::FEC::fNone:
1787                 parm_u_qam_fec_inner = FEC_NONE;
1788                 break;
1789         case eDVBFrontendParametersCable::FEC::f1_2:
1790                 parm_u_qam_fec_inner = FEC_1_2;
1791                 break;
1792         case eDVBFrontendParametersCable::FEC::f2_3:
1793                 parm_u_qam_fec_inner = FEC_2_3;
1794                 break;
1795         case eDVBFrontendParametersCable::FEC::f3_4:
1796                 parm_u_qam_fec_inner = FEC_3_4;
1797                 break;
1798         case eDVBFrontendParametersCable::FEC::f5_6:
1799                 parm_u_qam_fec_inner = FEC_5_6;
1800                 break;
1801         case eDVBFrontendParametersCable::FEC::f7_8:
1802                 parm_u_qam_fec_inner = FEC_7_8;
1803                 break;
1804 #if HAVE_DVB_API_VERSION >= 3
1805         case eDVBFrontendParametersCable::FEC::f8_9:
1806                 parm_u_qam_fec_inner = FEC_8_9;
1807                 break;
1808 #endif
1809         default:
1810         case eDVBFrontendParametersCable::FEC::fAuto:
1811                 parm_u_qam_fec_inner = FEC_AUTO;
1812                 break;
1813         }
1814         eDebug("tuning to %d khz, sr %d, fec %d, modulation %d, inversion %d",
1815                 parm_frequency/1000,
1816                 parm_u_qam_symbol_rate,
1817                 parm_u_qam_fec_inner,
1818                 parm_u_qam_modulation,
1819                 parm_inversion);
1820         return 0;
1821 }
1822
1823 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1824 {
1825         parm_frequency = feparm.frequency;
1826
1827         switch (feparm.bandwidth)
1828         {
1829         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1830                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1831                 break;
1832         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1833                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1834                 break;
1835         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1836                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1837                 break;
1838         default:
1839         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1840                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1841                 break;
1842         }
1843         switch (feparm.code_rate_LP)
1844         {
1845         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1846                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1847                 break;
1848         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1849                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1850                 break;
1851         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1852                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1853                 break;
1854         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1855                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1856                 break;
1857         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1858                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1859                 break;
1860         default:
1861         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1862                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1863                 break;
1864         }
1865         switch (feparm.code_rate_HP)
1866         {
1867         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1868                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1869                 break;
1870         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1871                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1872                 break;
1873         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1874                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1875                 break;
1876         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1877                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1878                 break;
1879         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1880                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1881                 break;
1882         default:
1883         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1884                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1885                 break;
1886         }
1887         switch (feparm.modulation)
1888         {
1889         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1890                 parm_u_ofdm_constellation = QPSK;
1891                 break;
1892         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1893                 parm_u_ofdm_constellation = QAM_16;
1894                 break;
1895         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
1896                 parm_u_ofdm_constellation = QAM_64;
1897                 break;
1898         default:
1899         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1900                 parm_u_ofdm_constellation = QAM_AUTO;
1901                 break;
1902         }
1903         switch (feparm.transmission_mode)
1904         {
1905         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1906                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1907                 break;
1908         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1909                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1910                 break;
1911         default:
1912         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1913                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1914                 break;
1915         }
1916         switch (feparm.guard_interval)
1917         {
1918                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
1919                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
1920                         break;
1921                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
1922                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
1923                         break;
1924                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
1925                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
1926                         break;
1927                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
1928                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
1929                         break;
1930                 default:
1931                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
1932                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
1933                         break;
1934         }
1935         switch (feparm.hierarchy)
1936         {
1937                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
1938                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
1939                         break;
1940                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
1941                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
1942                         break;
1943                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
1944                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
1945                         break;
1946                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
1947                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
1948                         break;
1949                 default:
1950                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
1951                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
1952                         break;
1953         }
1954         switch (feparm.inversion)
1955         {
1956         case eDVBFrontendParametersTerrestrial::Inversion::On:
1957                 parm_inversion = INVERSION_ON;
1958                 break;
1959         case eDVBFrontendParametersTerrestrial::Inversion::Off:
1960                 parm_inversion = INVERSION_OFF;
1961                 break;
1962         default:
1963         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
1964                 parm_inversion = INVERSION_AUTO;
1965                 break;
1966         }
1967         return 0;
1968 }
1969
1970 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
1971 {
1972         unsigned int timeout = 5000;
1973         eDebug("(%d)tune", m_dvbid);
1974
1975         m_timeout->stop();
1976
1977         int res=0;
1978
1979         if (!m_sn)
1980         {
1981                 eDebug("no frontend device opened... do not try to tune !!!");
1982                 res = -ENODEV;
1983                 goto tune_error;
1984         }
1985
1986         if (m_type == -1)
1987         {
1988                 res = -ENODEV;
1989                 goto tune_error;
1990         }
1991
1992         m_sn->stop();
1993         m_sec_sequence.clear();
1994
1995         where.calcLockTimeout(timeout);
1996
1997         switch (m_type)
1998         {
1999         case feSatellite:
2000         {
2001                 eDVBFrontendParametersSatellite feparm;
2002                 if (where.getDVBS(feparm))
2003                 {
2004                         eDebug("no dvbs data!");
2005                         res = -EINVAL;
2006                         goto tune_error;
2007                 }
2008                 m_sec->setRotorMoving(false);
2009                 res=prepare_sat(feparm, timeout);
2010                 if (res)
2011                         goto tune_error;
2012
2013                 break;
2014         }
2015         case feCable:
2016         {
2017                 eDVBFrontendParametersCable feparm;
2018                 if (where.getDVBC(feparm))
2019                 {
2020                         res = -EINVAL;
2021                         goto tune_error;
2022                 }
2023                 res=prepare_cable(feparm);
2024                 if (res)
2025                         goto tune_error;
2026
2027                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2028                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2029                 break;
2030         }
2031         case feTerrestrial:
2032         {
2033                 eDVBFrontendParametersTerrestrial feparm;
2034                 if (where.getDVBT(feparm))
2035                 {
2036                         eDebug("no -T data");
2037                         res = -EINVAL;
2038                         goto tune_error;
2039                 }
2040                 res=prepare_terrestrial(feparm);
2041                 if (res)
2042                         goto tune_error;
2043
2044                 std::string enable_5V;
2045                 char configStr[255];
2046                 snprintf(configStr, 255, "config.Nims.%d.terrestrial_5V", m_slotid);
2047                 m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT, timeout) );
2048                 ePythonConfigQuery::getConfigValue(configStr, enable_5V);
2049                 if (enable_5V == "True")
2050                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltage13) );
2051                 else
2052                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_VOLTAGE, iDVBFrontend::voltageOff) );
2053                 m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
2054
2055                 break;
2056         }
2057         }
2058
2059         m_tuneTimer->start(0,true);
2060         m_sec_sequence.current() = m_sec_sequence.begin();
2061
2062         if (m_state != stateTuning)
2063         {
2064                 m_tuning = 1;
2065                 m_state = stateTuning;
2066                 m_stateChanged(this);
2067         }
2068
2069         return res;
2070
2071 tune_error:
2072         m_tuneTimer->stop();
2073         return res;
2074 }
2075
2076 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
2077 {
2078         connection = new eConnection(this, m_stateChanged.connect(stateChange));
2079         return 0;
2080 }
2081
2082 RESULT eDVBFrontend::setVoltage(int voltage)
2083 {
2084         if (m_type == feCable)
2085                 return -1;
2086 #if HAVE_DVB_API_VERSION < 3
2087         secVoltage vlt;
2088 #else
2089         bool increased=false;
2090         fe_sec_voltage_t vlt;
2091 #endif
2092         m_data[CUR_VOLTAGE]=voltage;
2093         switch (voltage)
2094         {
2095         case voltageOff:
2096                 m_data[CSW]=m_data[UCSW]=m_data[TONEBURST]=-1; // reset diseqc
2097                 vlt = SEC_VOLTAGE_OFF;
2098                 break;
2099         case voltage13_5:
2100 #if HAVE_DVB_API_VERSION < 3
2101                 vlt = SEC_VOLTAGE_13_5;
2102                 break;
2103 #else
2104                 increased = true;
2105 #endif
2106         case voltage13:
2107                 vlt = SEC_VOLTAGE_13;
2108                 break;
2109         case voltage18_5:
2110 #if HAVE_DVB_API_VERSION < 3
2111                 vlt = SEC_VOLTAGE_18_5;
2112                 break;
2113 #else
2114                 increased = true;
2115 #endif
2116         case voltage18:
2117                 vlt = SEC_VOLTAGE_18;
2118                 break;
2119         default:
2120                 return -ENODEV;
2121         }
2122 #if HAVE_DVB_API_VERSION < 3
2123         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
2124 #else
2125         if (m_type == feSatellite && ::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
2126                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
2127         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
2128 #endif
2129 }
2130
2131 RESULT eDVBFrontend::getState(int &state)
2132 {
2133         state = m_state;
2134         return 0;
2135 }
2136
2137 RESULT eDVBFrontend::setTone(int t)
2138 {
2139         if (m_type != feSatellite)
2140                 return -1;
2141 #if HAVE_DVB_API_VERSION < 3
2142         secToneMode_t tone;
2143 #else
2144         fe_sec_tone_mode_t tone;
2145 #endif
2146         m_data[CUR_TONE]=t;
2147         switch (t)
2148         {
2149         case toneOn:
2150                 tone = SEC_TONE_ON;
2151                 break;
2152         case toneOff:
2153                 tone = SEC_TONE_OFF;
2154                 break;
2155         default:
2156                 return -ENODEV;
2157         }
2158 #if HAVE_DVB_API_VERSION < 3    
2159         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
2160 #else   
2161         return ::ioctl(m_fd, FE_SET_TONE, tone);
2162 #endif
2163 }
2164
2165 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
2166         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
2167 #endif
2168
2169 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
2170 {
2171 #if HAVE_DVB_API_VERSION < 3
2172         struct secCommand cmd;
2173         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
2174         cmd.u.diseqc.cmdtype = diseqc.data[0];
2175         cmd.u.diseqc.addr = diseqc.data[1];
2176         cmd.u.diseqc.cmd = diseqc.data[2];
2177         cmd.u.diseqc.numParams = diseqc.len-3;
2178         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
2179         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
2180 #else
2181         struct dvb_diseqc_master_cmd cmd;
2182         memcpy(cmd.msg, diseqc.data, diseqc.len);
2183         cmd.msg_len = diseqc.len;
2184         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
2185 #endif
2186                 return -EINVAL;
2187         return 0;
2188 }
2189
2190 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
2191         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
2192 #endif
2193 RESULT eDVBFrontend::sendToneburst(int burst)
2194 {
2195 #if HAVE_DVB_API_VERSION < 3
2196         secMiniCmd cmd = SEC_MINI_NONE;
2197 #else
2198         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
2199 #endif
2200         if ( burst == eDVBSatelliteDiseqcParameters::A )
2201                 cmd = SEC_MINI_A;
2202         else if ( burst == eDVBSatelliteDiseqcParameters::B )
2203                 cmd = SEC_MINI_B;
2204 #if HAVE_DVB_API_VERSION < 3
2205         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
2206                 return -EINVAL;
2207 #else
2208         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
2209                 return -EINVAL;
2210 #endif
2211         return 0;
2212 }
2213
2214 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
2215 {
2216         m_sec = sec;
2217         return 0;
2218 }
2219
2220 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
2221 {
2222         m_sec_sequence = list;
2223         return 0;
2224 }
2225
2226 RESULT eDVBFrontend::getData(int num, long &data)
2227 {
2228         if ( num < NUM_DATA_ENTRIES )
2229         {
2230                 data = m_data[num];
2231                 return 0;
2232         }
2233         return -EINVAL;
2234 }
2235
2236 RESULT eDVBFrontend::setData(int num, long val)
2237 {
2238         if ( num < NUM_DATA_ENTRIES )
2239         {
2240                 m_data[num] = val;
2241                 return 0;
2242         }
2243         return -EINVAL;
2244 }
2245
2246 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
2247 {
2248         int type;
2249         if (feparm->getSystem(type) || type != m_type || !m_enabled)
2250                 return 0;
2251         if (m_type == eDVBFrontend::feSatellite)
2252         {
2253                 ASSERT(m_sec);
2254                 eDVBFrontendParametersSatellite sat_parm;
2255                 int ret = feparm->getDVBS(sat_parm);
2256                 ASSERT(!ret);
2257                 if (sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S2 && !m_can_handle_dvbs2)
2258                         return 0;
2259                 ret = m_sec->canTune(sat_parm, this, 1 << m_slotid);
2260                 if (ret > 1 && sat_parm.system == eDVBFrontendParametersSatellite::System::DVB_S && m_can_handle_dvbs2)
2261                         ret -= 1;
2262                 return ret;
2263         }
2264         else if (m_type == eDVBFrontend::feCable)
2265                 return 2;  // more prio for cable frontends
2266         else if (m_type == eDVBFrontend::feTerrestrial)
2267                 return 1;
2268         return 0;
2269 }
2270
2271 bool eDVBFrontend::setSlotInfo(ePyObject obj)
2272 {
2273         ePyObject Id, Descr, Enabled;
2274         if (!PyTuple_Check(obj) || PyTuple_Size(obj) != 3)
2275                 goto arg_error;
2276         Id = PyTuple_GET_ITEM(obj, 0);
2277         Descr = PyTuple_GET_ITEM(obj, 1);
2278         Enabled = PyTuple_GET_ITEM(obj, 2);
2279         if (!PyInt_Check(Id) || !PyString_Check(Descr) || !PyBool_Check(Enabled))
2280                 goto arg_error;
2281         strcpy(m_description, PyString_AS_STRING(Descr));
2282         m_slotid = PyInt_AsLong(Id);
2283         m_enabled = Enabled == Py_True;
2284         // HACK.. the rotor workaround is neede for all NIMs with LNBP21 voltage regulator...
2285         m_need_rotor_workaround = !!strstr(m_description, "Alps BSBE1") ||
2286                 !!strstr(m_description, "Alps BSBE2") ||
2287                 !!strstr(m_description, "Alps -S") ||
2288                 !!strstr(m_description, "BCM4501");
2289         m_can_handle_dvbs2 = !!strstr(m_description, "Alps BSBE2") || !!strstr(m_description, "BCM4501");
2290         eDebug("setSlotInfo for dvb frontend %d to slotid %d, descr %s, need rotorworkaround %s, enabled %s, DVB-S2 %s",
2291                 m_dvbid, m_slotid, m_description, m_need_rotor_workaround ? "Yes" : "No", m_enabled ? "Yes" : "No", m_can_handle_dvbs2 ? "Yes" : "No" );
2292         return true;
2293 arg_error:
2294         PyErr_SetString(PyExc_StandardError,
2295                 "eDVBFrontend::setSlotInfo must get a tuple with first param slotid, second param slot description and third param enabled boolean");
2296         return false;
2297 }