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