make eDVBResourceManager accessible from python (needed for allocate a raw iDVBChannel)
[vuplus_dvbapp] / lib / dvb / frontend.cpp
1 #include <lib/dvb/dvb.h>
2 #include <lib/base/eerror.h>
3 #include <errno.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <sys/ioctl.h>
7
8 #ifndef I2C_SLAVE_FORCE
9 #define I2C_SLAVE_FORCE 0x0706
10 #endif
11
12 #if HAVE_DVB_API_VERSION < 3
13 #include <ost/frontend.h>
14 #include <ost/sec.h>
15 #define QAM_AUTO                                (Modulation)6
16 #define TRANSMISSION_MODE_AUTO  (TransmitMode)2
17 #define BANDWIDTH_AUTO                  (BandWidth)3
18 #define GUARD_INTERVAL_AUTO             (GuardInterval)4
19 #define HIERARCHY_AUTO                  (Hierarchy)4
20 #define parm_frequency parm.Frequency
21 #define parm_inversion parm.Inversion
22 #define parm_u_qpsk_symbol_rate parm.u.qpsk.SymbolRate
23 #define parm_u_qpsk_fec_inner parm.u.qpsk.FEC_inner
24 #define parm_u_qam_symbol_rate parm.u.qam.SymbolRate
25 #define parm_u_qam_fec_inner parm.u.qam.FEC_inner
26 #define parm_u_qam_modulation parm.u.qam.QAM
27 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandWidth
28 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.LP_CodeRate
29 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.HP_CodeRate
30 #define parm_u_ofdm_constellation parm.u.ofdm.Constellation
31 #define parm_u_ofdm_transmission_mode parm.u.ofdm.TransmissionMode
32 #define parm_u_ofdm_guard_interval parm.u.ofdm.guardInterval
33 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.HierarchyInformation
34 #else
35 #include <linux/dvb/frontend.h>
36 #define parm_frequency parm.frequency
37 #define parm_inversion parm.inversion
38 #define parm_u_qpsk_symbol_rate parm.u.qpsk.symbol_rate
39 #define parm_u_qpsk_fec_inner parm.u.qpsk.fec_inner
40 #define parm_u_qam_symbol_rate parm.u.qam.symbol_rate
41 #define parm_u_qam_fec_inner parm.u.qam.fec_inner
42 #define parm_u_qam_modulation parm.u.qam.modulation
43 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandwidth
44 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.code_rate_LP
45 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.code_rate_HP
46 #define parm_u_ofdm_constellation parm.u.ofdm.constellation
47 #define parm_u_ofdm_transmission_mode parm.u.ofdm.transmission_mode
48 #define parm_u_ofdm_guard_interval parm.u.ofdm.guard_interval
49 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.hierarchy_information
50 #endif
51
52 #include <dvbsi++/satellite_delivery_system_descriptor.h>
53 #include <dvbsi++/cable_delivery_system_descriptor.h>
54 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
55
56 void eDVBDiseqcCommand::setData(const char *str)
57 {
58         len = strlen(str);
59         if (len > MAX_DISEQC_LENGTH)
60                 len = MAX_DISEQC_LENGTH;
61         memcpy(data, str, len);
62 }
63
64 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
65 {
66         frequency    = descriptor.getFrequency() * 10;
67         symbol_rate  = descriptor.getSymbolRate() * 100;
68         polarisation = descriptor.getPolarization();
69         fec = descriptor.getFecInner();
70         if ( fec == 0xF )
71                 fec = FEC::fNone;
72         inversion = Inversion::Unknown;
73         orbital_position  = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
74         orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
75         orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
76         orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
77         if (orbital_position && (!descriptor.getWestEastFlag()))
78                 orbital_position = 3600 - orbital_position;
79         eDebug("SAT freq %d, %s, pos %d, sr %d, fec %d",
80                 frequency,
81                 polarisation ? "hor" : "vert",
82                 orbital_position,
83                 symbol_rate, fec);
84 }
85
86 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
87 {
88         frequency = descriptor.getFrequency() / 10;
89         symbol_rate = descriptor.getSymbolRate() * 100;
90         fec_inner = descriptor.getFecInner();
91         if ( fec_inner == 0xF )
92                 fec_inner = FEC::fNone;
93         modulation = descriptor.getModulation();
94         if ( modulation > 0x5 )
95                 modulation = Modulation::Auto;
96         inversion = Inversion::Unknown;
97         eDebug("Cable freq %d, mod %d, sr %d, fec %d",
98                 frequency,
99                 modulation, symbol_rate, fec_inner);
100 }
101
102 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &descriptor)
103 {
104         frequency = descriptor.getCentreFrequency() * 10;
105         bandwidth = descriptor.getBandwidth();
106         if ( bandwidth > 2 ) // 5Mhz forced to auto
107                 bandwidth = Bandwidth::BwAuto;
108         code_rate_HP = descriptor.getCodeRateHpStream();
109         if (code_rate_HP > 4)
110                 code_rate_HP = FEC::fAuto;
111         code_rate_LP = descriptor.getCodeRateLpStream();
112         if (code_rate_LP > 4)
113                 code_rate_LP = FEC::fAuto;
114         transmission_mode = descriptor.getTransmissionMode();
115         if (transmission_mode > 2)
116                 transmission_mode = TransmissionMode::TMAuto;
117         guard_interval = descriptor.getGuardInterval();
118         if (guard_interval > 3)
119                 guard_interval = GuardInterval::GI_Auto;
120         hierarchy = descriptor.getHierarchyInformation()&3;
121         modulation = descriptor.getConstellation();
122         if (modulation > 2)
123                 modulation = Modulation::Auto;
124         inversion = Inversion::Unknown;
125         eDebug("Terr freq %d, bw %d, cr_hp %d, cr_lp %d, tm_mode %d, guard %d, hierarchy %d, const %d",
126                 frequency, bandwidth, code_rate_HP, code_rate_LP, transmission_mode,
127                 guard_interval, hierarchy, modulation);
128 }
129
130 eDVBFrontendParameters::eDVBFrontendParameters(): m_type(-1)
131 {
132 }
133
134 DEFINE_REF(eDVBFrontendParameters);
135
136 RESULT eDVBFrontendParameters::getSystem(int &t) const
137 {
138         if (m_type == -1)
139                 return -1;
140         t = m_type;
141         return 0;
142 }
143
144 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
145 {
146         if (m_type != iDVBFrontend::feSatellite)
147                 return -1;
148         p = sat;
149         return 0;
150 }
151
152 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
153 {
154         if (m_type != iDVBFrontend::feCable)
155                 return -1;
156         p = cable;
157         return 0;
158 }
159
160 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
161 {
162         if (m_type != iDVBFrontend::feTerrestrial)
163                 return -1;
164         p = terrestrial;
165         return 0;
166 }
167
168 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p)
169 {
170         sat = p;
171         m_type = iDVBFrontend::feSatellite;
172         return 0;
173 }
174
175 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
176 {
177         cable = p;
178         m_type = iDVBFrontend::feCable;
179         return 0;
180 }
181
182 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
183 {
184         terrestrial = p;
185         m_type = iDVBFrontend::feTerrestrial;
186         return 0;
187 }
188
189 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff) const
190 {
191         if (!parm)
192                 return -1;
193         int type;
194         if (parm->getSystem(type))
195                 return -1;
196         if (type != m_type)
197         {
198                 diff = 1<<30; // big difference
199                 return 0;
200         }
201         
202         switch (type)
203         {
204         case iDVBFrontend::feSatellite:
205         {
206                 eDVBFrontendParametersSatellite osat;
207                 if (parm->getDVBS(osat))
208                         return -2;
209                 
210                 if (sat.orbital_position != osat.orbital_position)
211                         diff = 1<<29;
212                 else if (sat.polarisation != osat.polarisation)
213                         diff = 1<<28;
214                 else
215                 {
216                         diff = abs(sat.frequency - osat.frequency);
217                         diff += abs(sat.symbol_rate - osat.symbol_rate);
218                 }
219                 return 0;
220         }
221         case iDVBFrontend::feCable:
222                 eDVBFrontendParametersCable ocable;
223                 if (parm->getDVBC(ocable))
224                         return -2;
225                 
226                 if (cable.modulation != ocable.modulation && cable.modulation != eDVBFrontendParametersCable::Modulation::Auto && ocable.modulation != eDVBFrontendParametersCable::Modulation::Auto)
227                         diff = 1 << 29;
228                 else if (cable.inversion != ocable.inversion && cable.inversion != eDVBFrontendParametersCable::Inversion::Unknown && ocable.inversion != eDVBFrontendParametersCable::Inversion::Unknown)
229                         diff = 1 << 28;
230                 else
231                 {
232                         diff = abs(cable.frequency - ocable.frequency);
233                         diff += abs(cable.symbol_rate - ocable.symbol_rate);
234                 }
235                 
236                 return 0;
237         case iDVBFrontend::feTerrestrial:
238                 eDVBFrontendParametersTerrestrial oterrestrial;
239                 if (parm->getDVBT(oterrestrial))
240                         return -2;
241                 
242                 diff = abs(terrestrial.frequency - oterrestrial.frequency);
243
244                 return 0;
245         default:
246                 return -1;
247         }
248         return 0;
249 }
250
251 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const
252 {
253         switch (m_type)
254         {
255         case iDVBFrontend::feSatellite:
256         {
257                 hash = (sat.orbital_position << 16);
258                 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
259                 return 0;
260         }
261         case iDVBFrontend::feCable:
262         case iDVBFrontend::feTerrestrial:
263         default:
264                 return -1;
265         }
266 }
267
268 DEFINE_REF(eDVBFrontend);
269
270 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok)
271         :m_type(-1), m_fe(fe), m_fd(-1), m_timeout(0), m_tuneTimer(0)
272 #if HAVE_DVB_API_VERSION < 3
273         ,m_secfd(-1)
274 #endif
275 {
276 #if HAVE_DVB_API_VERSION < 3
277         sprintf(m_filename, "/dev/dvb/card%d/frontend%d", adap, fe);
278         sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
279 #else
280         sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
281 #endif
282         m_timeout = new eTimer(eApp);
283         CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
284
285         m_tuneTimer = new eTimer(eApp);
286         CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
287
288         int entries = sizeof(m_data) / sizeof(int);
289         for (int i=0; i<entries; ++i)
290                 m_data[i] = -1;
291
292         m_idleInputpower[0]=m_idleInputpower[1]=0;
293
294         ok = !openFrontend();
295         closeFrontend();
296 }
297
298 int eDVBFrontend::openFrontend()
299 {
300         if (m_fd >= 0)
301                 return -1;  // already opened
302
303         m_state=0;
304         m_tuning=0;
305
306 #if HAVE_DVB_API_VERSION < 3
307         m_secfd = ::open(m_sec_filename, O_RDWR);
308         if (m_secfd < 0)
309         {
310                 eWarning("failed! (%s) %m", m_sec_filename);
311                 return -1;
312         }
313         FrontendInfo fe_info;
314 #else
315         dvb_frontend_info fe_info;
316 #endif
317         eDebug("opening frontend %d", m_fe);
318         m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
319         if (m_fd < 0)
320         {
321                 eWarning("failed! (%s) %m", m_filename);
322 #if HAVE_DVB_API_VERSION < 3
323                 ::close(m_secfd);
324                 m_secfd=-1;
325 #endif
326                 return -1;
327         }
328
329         if (m_type == -1)
330         {
331                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
332                 {
333                         eWarning("ioctl FE_GET_INFO failed");
334                         ::close(m_fd);
335                         m_fd = -1;
336 #if HAVE_DVB_API_VERSION < 3
337                         ::close(m_secfd);
338                         m_secfd=-1;
339 #endif
340                         return -1;
341                 }
342
343                 switch (fe_info.type)
344                 {
345                 case FE_QPSK:
346                         m_type = iDVBFrontend::feSatellite;
347                         break;
348                 case FE_QAM:
349                         m_type = iDVBFrontend::feCable;
350                         break;
351                 case FE_OFDM:
352                         m_type = iDVBFrontend::feTerrestrial;
353                         break;
354                 default:
355                         eWarning("unknown frontend type.");
356                         ::close(m_fd);
357                         m_fd = -1;
358 #if HAVE_DVB_API_VERSION < 3
359                         ::close(m_secfd);
360                         m_secfd=-1;
361 #endif
362                         return -1;
363                 }
364                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
365         }
366
367         setTone(iDVBFrontend::toneOff);
368         setVoltage(iDVBFrontend::voltageOff);
369
370         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
371         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
372         m_sn->start();
373
374         return 0;
375 }
376
377 int eDVBFrontend::closeFrontend()
378 {
379         if (!m_fe && m_data[7] != -1)
380         {
381                 // try to close the first frontend.. but the second is linked to the first
382                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)m_data[7];
383                 if (linked_fe->m_inuse)
384                 {
385                         eDebug("dont close frontend %d until the linked frontend %d is still in use",
386                                 m_fe, linked_fe->m_frontend->getID());
387                         return -1;
388                 }
389         }
390         if (m_fd >= 0)
391         {
392                 eDebug("close frontend %d", m_fe);
393                 setTone(iDVBFrontend::toneOff);
394                 setVoltage(iDVBFrontend::voltageOff);
395                 ::close(m_fd);
396                 m_fd=-1;
397                 m_data[0] = m_data[1] = m_data[2] = -1;
398         }
399 #if HAVE_DVB_API_VERSION < 3
400         if (m_secfd >= 0)
401         {
402                 ::close(m_secfd);
403                 m_secfd=-1;
404         }
405 #endif
406         delete m_sn;
407         m_sn=0;
408
409         return 0;
410 }
411
412 eDVBFrontend::~eDVBFrontend()
413 {
414         closeFrontend();
415         delete m_timeout;
416         delete m_tuneTimer;
417 }
418
419 void eDVBFrontend::feEvent(int w)
420 {
421         while (1)
422         {
423 #if HAVE_DVB_API_VERSION < 3
424                 FrontendEvent event;
425 #else
426                 dvb_frontend_event event;
427 #endif
428                 int res;
429                 int state;
430                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
431                 
432                 if (res && (errno == EAGAIN))
433                         break;
434
435                 if (res)
436                 {
437                         eWarning("FE_GET_EVENT failed! %m");
438                         return;
439                 }
440                 
441                 if (w < 0)
442                         continue;
443
444 #if HAVE_DVB_API_VERSION < 3
445                 if (event.type == FE_COMPLETION_EV)
446 #else
447                 eDebug("(%d)fe event: status %x, inversion %s", m_fe, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
448                 if (event.status & FE_HAS_LOCK)
449 #endif
450                 {
451                         state = stateLock;
452                 } else
453                 {
454                         if (m_tuning)
455                                 state = stateTuning;
456                         else
457                         {
458                                 state = stateLostLock;
459                                 m_data[0] = m_data[1] = m_data[2] = -1; // reset diseqc
460                         }
461                 }
462                 if (m_state != state)
463                 {
464                         m_state = state;
465                         m_stateChanged(this);
466                 }
467         }
468 }
469
470 void eDVBFrontend::timeout()
471 {
472         m_tuning = 0;
473         if (m_state == stateTuning)
474         {
475                 m_state = stateFailed;
476                 m_stateChanged(this);
477         }
478 }
479
480 int eDVBFrontend::readFrontendData(int type)
481 {
482         switch(type)
483         {
484                 case bitErrorRate:
485                 {
486                         uint32_t ber=0;
487                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
488                                 eDebug("FE_READ_BER failed (%m)");
489                         return ber;
490                 }
491                 case signalPower:
492                 {
493                         uint16_t snr=0;
494                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
495                                 eDebug("FE_READ_SNR failed (%m)");
496                         return snr;
497                 }
498                 case signalQuality:
499                 {
500                         uint16_t strength=0;
501                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
502                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
503                         return strength;
504                 }
505                 case Locked:
506                 {
507 #if HAVE_DVB_API_VERSION < 3
508                         FrontendStatus status=0;
509 #else
510                         fe_status_t status;
511 #endif
512                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
513                                 eDebug("FE_READ_STATUS failed (%m)");
514                         return !!(status&FE_HAS_LOCK);
515                 }
516                 case Synced:
517                 {
518 #if HAVE_DVB_API_VERSION < 3
519                         FrontendStatus status=0;
520 #else
521                         fe_status_t status;
522 #endif
523                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
524                                 eDebug("FE_READ_STATUS failed (%m)");
525                         return !!(status&FE_HAS_SYNC);
526                 }
527         }
528         return 0;
529 }
530
531 void PutToDict(PyObject *dict, const char*key, long value)
532 {
533         PyObject *item = PyInt_FromLong(value);
534         if (item)
535         {
536                 if (PyDict_SetItemString(dict, key, item))
537                         eDebug("put %s to dict failed", key);
538                 Py_DECREF(item);
539         }
540         else
541                 eDebug("could not create PyObject for %s", key);
542 }
543
544 void PutToDict(PyObject *dict, const char*key, const char *value)
545 {
546         PyObject *item = PyString_FromString(value);
547         if (item)
548         {
549                 if (PyDict_SetItemString(dict, key, item))
550                         eDebug("put %s to dict failed", key);
551                 Py_DECREF(item);
552         }
553         else
554                 eDebug("could not create PyObject for %s", key);
555 }
556
557 void fillDictWithSatelliteData(PyObject *dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
558 {
559         int freq_offset=0;
560         int csw=0;
561         const char *fec=0;
562         fe->getData(0, csw);
563         fe->getData(9, freq_offset);
564         int frequency = parm_frequency + freq_offset;
565         PutToDict(dict, "frequency", frequency);
566         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
567
568         switch(parm_u_qpsk_fec_inner)
569         {
570         case FEC_1_2:
571                 fec = "FEC_1_2";
572                 break;
573         case FEC_2_3:
574                 fec = "FEC_2_3";
575                 break;
576         case FEC_3_4:
577                 fec = "FEC_3_4";
578                 break;
579         case FEC_5_6:
580                 fec = "FEC_5_6";
581                 break;
582         case FEC_7_8:
583                 fec = "FEC_7_8";
584                 break;
585         default:
586         case FEC_AUTO:
587                 fec = "FEC_AUTO";
588                 break;
589         }
590         PutToDict(dict, "fec_inner", fec);
591 }
592
593 void fillDictWithCableData(PyObject *dict, const FRONTENDPARAMETERS &parm)
594 {
595         const char *tmp=0;
596         PutToDict(dict, "frequency", parm_frequency/1000);
597         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
598         switch(parm_u_qam_fec_inner)
599         {
600         case FEC_NONE:
601                 tmp = "FEC_NONE";
602                 break;
603         case FEC_1_2:
604                 tmp = "FEC_1_2";
605                 break;
606         case FEC_2_3:
607                 tmp = "FEC_2_3";
608                 break;
609         case FEC_3_4:
610                 tmp = "FEC_3_4";
611                 break;
612         case FEC_5_6:
613                 tmp = "FEC_5_6";
614                 break;
615         case FEC_7_8:
616                 tmp = "FEC_7_8";
617                 break;
618 #if HAVE_DVB_API_VERSION >= 3
619         case FEC_8_9:
620                 tmp = "FEC_8_9";
621                 break;
622 #endif
623         default:
624         case FEC_AUTO:
625                 tmp = "FEC_AUTO";
626                 break;
627         }
628         PutToDict(dict, "fec_inner", tmp);
629         switch(parm_u_qam_modulation)
630         {
631         case QAM_16:
632                 tmp = "QAM_16";
633                 break;
634         case QAM_32:
635                 tmp = "QAM_32";
636                 break;
637         case QAM_64:
638                 tmp = "QAM_64";
639                 break;
640         case QAM_128:
641                 tmp = "QAM_128";
642                 break;
643         case QAM_256:
644                 tmp = "QAM_256";
645                 break;
646         default:
647         case QAM_AUTO:
648                 tmp = "QAM_AUTO";
649                 break;
650         }
651         PutToDict(dict, "modulation", tmp);
652 }
653
654 void fillDictWithTerrestrialData(PyObject *dict, const FRONTENDPARAMETERS &parm)
655 {
656         const char *tmp=0;
657         PutToDict(dict, "frequency", parm_frequency);
658         switch (parm_u_ofdm_bandwidth)
659         {
660         case BANDWIDTH_8_MHZ:
661                 tmp = "BANDWIDTH_8_MHZ";
662                 break;
663         case BANDWIDTH_7_MHZ:
664                 tmp = "BANDWIDTH_7_MHZ";
665                 break;
666         case BANDWIDTH_6_MHZ:
667                 tmp = "BANDWIDTH_6_MHZ";
668                 break;
669         default:
670         case BANDWIDTH_AUTO:
671                 tmp = "BANDWIDTH_AUTO";
672                 break;
673         }
674         PutToDict(dict, "bandwidth", tmp);
675         switch (parm_u_ofdm_code_rate_LP)
676         {
677         case FEC_1_2:
678                 tmp = "FEC_1_2";
679                 break;
680         case FEC_2_3:
681                 tmp = "FEC_2_3";
682                 break;
683         case FEC_3_4:
684                 tmp = "FEC_3_4";
685                 break;
686         case FEC_5_6:
687                 tmp = "FEC_5_6";
688                 break;
689         case FEC_7_8:
690                 tmp = "FEC_7_8";
691                 break;
692         default:
693         case FEC_AUTO:
694                 tmp = "FEC_AUTO";
695                 break;
696         }
697         PutToDict(dict, "code_rate_lp", tmp);
698         switch (parm_u_ofdm_code_rate_HP)
699         {
700         case FEC_1_2:
701                 tmp = "FEC_1_2";
702                 break;
703         case FEC_2_3:
704                 tmp = "FEC_2_3";
705                 break;
706         case FEC_3_4:
707                 tmp = "FEC_3_4";
708                 break;
709         case FEC_5_6:
710                 tmp = "FEC_5_6";
711                 break;
712         case FEC_7_8:
713                 tmp = "FEC_7_8";
714                 break;
715         default:
716         case FEC_AUTO:
717                 tmp = "FEC_AUTO";
718                 break;
719         }
720         PutToDict(dict, "code_rate_hp", tmp);
721         switch (parm_u_ofdm_constellation)
722         {
723         case QPSK:
724                 tmp = "QPSK";
725                 break;
726         case QAM_16:
727                 tmp = "QAM_16";
728                 break;
729         default:
730         case QAM_AUTO:
731                 tmp = "QAM_AUTO";
732                 break;
733         }
734         PutToDict(dict, "constellation", tmp);
735         switch (parm_u_ofdm_transmission_mode)
736         {
737         case TRANSMISSION_MODE_2K:
738                 tmp = "TRANSMISSION_MODE_2K";
739                 break;
740         case TRANSMISSION_MODE_8K:
741                 tmp = "TRANSMISSION_MODE_8K";
742                 break;
743         default:
744         case TRANSMISSION_MODE_AUTO:
745                 tmp = "TRANSMISSION_MODE_AUTO";
746                 break;
747         }
748         PutToDict(dict, "transmission_mode", tmp);
749         switch (parm_u_ofdm_guard_interval)
750         {
751                 case GUARD_INTERVAL_1_32:
752                         tmp = "GUARD_INTERVAL_1_32";
753                         break;
754                 case GUARD_INTERVAL_1_16:
755                         tmp = "GUARD_INTERVAL_1_16";
756                         break;
757                 case GUARD_INTERVAL_1_8:
758                         tmp = "GUARD_INTERVAL_1_8";
759                         break;
760                 case GUARD_INTERVAL_1_4:
761                         tmp = "GUARD_INTERVAL_1_4";
762                         break;
763                 default:
764                 case GUARD_INTERVAL_AUTO:
765                         tmp = "GUARD_INTERVAL_AUTO";
766                         break;
767         }
768         PutToDict(dict, "guard_interval", tmp);
769         switch (parm_u_ofdm_hierarchy_information)
770         {
771                 case HIERARCHY_1:
772                         tmp = "HIERARCHY_1";
773                         break;
774                 case HIERARCHY_2:
775                         tmp = "HIERARCHY_2";
776                         break;
777                 case HIERARCHY_4:
778                         tmp = "HIERARCHY_4";
779                         break;
780                 default:
781                 case HIERARCHY_AUTO:
782                         tmp = "HIERARCHY_AUTO";
783                         break;
784         }
785         PutToDict(dict, "hierarchy_information", tmp);
786 }
787
788 PyObject *eDVBFrontend::readTransponderData(bool original)
789 {
790         PyObject *ret=PyDict_New();
791
792         if (ret)
793         {
794                 bool read=m_fd != -1;
795                 const char *tmp=0;
796
797                 PutToDict(ret, "tuner_number", m_fe);
798
799                 switch(m_type)
800                 {
801                         case feSatellite:
802                                 tmp = "DVB-S";
803                                 break;
804                         case feCable:
805                                 tmp = "DVB-C";
806                                 break;
807                         case feTerrestrial:
808                                 tmp = "DVB-T";
809                                 break;
810                         default:
811                                 tmp = "UNKNOWN";
812                                 read=false;
813                                 break;
814                 }
815                 PutToDict(ret, "tuner_type", tmp);
816
817                 if (read)
818                 {
819                         FRONTENDPARAMETERS front;
820
821                         tmp = "UNKNOWN";
822                         switch(m_state)
823                         {
824                                 case stateIdle:
825                                         tmp="IDLE";
826                                         break;
827                                 case stateTuning:
828                                         tmp="TUNING";
829                                         break;
830                                 case stateFailed:
831                                         tmp="FAILED";
832                                         break;
833                                 case stateLock:
834                                         tmp="LOCKED";
835                                         break;
836                                 case stateLostLock:
837                                         tmp="LOSTLOCK";
838                                         break;
839                                 default:
840                                         break;
841                         }
842                         PutToDict(ret, "tuner_state", tmp);
843
844                         PutToDict(ret, "tuner_locked", readFrontendData(Locked));
845                         PutToDict(ret, "tuner_synced", readFrontendData(Synced));
846                         PutToDict(ret, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
847                         PutToDict(ret, "tuner_signal_power", readFrontendData(signalPower));
848                         PutToDict(ret, "tuner_signal_quality", readFrontendData(signalQuality));
849
850                         if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
851                                 eDebug("FE_GET_FRONTEND (%m)");
852                         else
853                         {
854                                 tmp = "INVERSION_AUTO";
855                                 switch(parm_inversion)
856                                 {
857                                         case INVERSION_ON:
858                                                 tmp = "INVERSION_ON";
859                                                 break;
860                                         case INVERSION_OFF:
861                                                 tmp = "INVERSION_OFF";
862                                                 break;
863                                         default:
864                                                 break;
865                                 }
866                                 if (tmp)
867                                         PutToDict(ret, "inversion", tmp);
868
869                                 switch(m_type)
870                                 {
871                                         case feSatellite:
872                                                 fillDictWithSatelliteData(ret, original?parm:front, this);
873                                                 break;
874                                         case feCable:
875                                                 fillDictWithCableData(ret, original?parm:front);
876                                                 break;
877                                         case feTerrestrial:
878                                                 fillDictWithTerrestrialData(ret, original?parm:front);
879                                                 break;
880                                 }
881                         }
882                 }
883         }
884         else
885         {
886                 Py_INCREF(Py_None);
887                 ret = Py_None;
888         }
889         return ret;
890 }
891
892 #ifndef FP_IOCTL_GET_ID
893 #define FP_IOCTL_GET_ID 0
894 #endif
895 int eDVBFrontend::readInputpower()
896 {
897         int power=m_fe;  // this is needed for read inputpower from the correct tuner !
898
899         // open front prozessor
900         int fp=::open("/dev/dbox/fp0", O_RDWR);
901         if (fp < 0)
902         {
903                 eDebug("couldn't open fp");
904                 return -1;
905         }
906         static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
907         if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
908         {
909                 eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
910                 return -1;
911         }
912         ::close(fp);
913
914         return power;
915 }
916
917 bool eDVBFrontend::setSecSequencePos(int steps)
918 {
919         eDebug("set sequence pos %d", steps);
920         if (!steps)
921                 return false;
922         while( steps > 0 )
923         {
924                 if (m_sec_sequence.current() != m_sec_sequence.end())
925                         ++m_sec_sequence.current();
926                 --steps;
927         }
928         while( steps < 0 )
929         {
930                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
931                         --m_sec_sequence.current();
932                 ++steps;
933         }
934         return true;
935 }
936
937 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
938 {
939         int delay=0;
940         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
941         {
942 //              eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
943                 switch (m_sec_sequence.current()->cmd)
944                 {
945                         case eSecCommand::SLEEP:
946                                 delay = m_sec_sequence.current()++->msec;
947                                 eDebug("[SEC] sleep %dms", delay);
948                                 break;
949                         case eSecCommand::GOTO:
950                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
951                                         ++m_sec_sequence.current();
952                                 break;
953                         case eSecCommand::SET_VOLTAGE:
954                         {
955                                 int voltage = m_sec_sequence.current()++->voltage;
956                                 eDebug("[SEC] setVoltage %d", voltage);
957                                 setVoltage(voltage);
958                                 break;
959                         }
960                         case eSecCommand::IF_VOLTAGE_GOTO:
961                         {
962                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
963                                 if ( compare.voltage == m_curVoltage && setSecSequencePos(compare.steps) )
964                                         break;
965                                 ++m_sec_sequence.current();
966                                 break;
967                         }
968                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
969                         {
970                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
971                                 if ( compare.voltage != m_curVoltage && setSecSequencePos(compare.steps) )
972                                         break;
973                                 ++m_sec_sequence.current();
974                                 break;
975                         }
976                         case eSecCommand::SET_TONE:
977                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
978                                 setTone(m_sec_sequence.current()++->tone);
979                                 break;
980                         case eSecCommand::SEND_DISEQC:
981                                 sendDiseqc(m_sec_sequence.current()->diseqc);
982                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
983                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
984                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
985                                 eDebug("");
986                                 ++m_sec_sequence.current();
987                                 break;
988                         case eSecCommand::SEND_TONEBURST:
989                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
990                                 sendToneburst(m_sec_sequence.current()++->toneburst);
991                                 break;
992                         case eSecCommand::SET_FRONTEND:
993                                 eDebug("[SEC] setFrontend");
994                                 setFrontend();
995                                 ++m_sec_sequence.current();
996                                 break;
997                         case eSecCommand::START_TUNE_TIMEOUT:
998                                 m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
999                                 ++m_sec_sequence.current();
1000                                 break;
1001                         case eSecCommand::SET_TIMEOUT:
1002                                 m_timeoutCount = m_sec_sequence.current()++->val;
1003                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
1004                                 break;
1005                         case eSecCommand::IF_TIMEOUT_GOTO:
1006                                 if (!m_timeoutCount)
1007                                 {
1008                                         eDebug("[SEC] rotor timout");
1009                                         m_sec->setRotorMoving(false);
1010                                         setSecSequencePos(m_sec_sequence.current()->steps);
1011                                 }
1012                                 else
1013                                         ++m_sec_sequence.current();
1014                                 break;
1015                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1016                         {
1017                                 int idx = m_sec_sequence.current()++->val;
1018                                 if ( idx == 0 || idx == 1 )
1019                                 {
1020                                         m_idleInputpower[idx] = readInputpower();
1021                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1022                                 }
1023                                 else
1024                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1025                                 break;
1026                         }
1027                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1028                         {
1029                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1030                                 int idx = compare.voltage;
1031                                 if ( idx == 0 || idx == 1 )
1032                                 {
1033                                         int idle = readInputpower();
1034                                         int diff = abs(idle-m_idleInputpower[idx]);
1035                                         if ( diff > 0)
1036                                         {
1037                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1038                                                 setSecSequencePos(compare.steps);
1039                                                 break;
1040                                         }
1041                                 }
1042                                 ++m_sec_sequence.current();
1043                                 break;
1044                         }
1045                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1046                         {
1047                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1048                                 if (readFrontendData(Locked))
1049                                 {
1050                                         eDebug("[SEC] locked step %d ok", cmd.okcount);
1051                                         ++cmd.okcount;
1052                                         if (cmd.okcount > 12)
1053                                         {
1054                                                 eDebug("ok > 12 .. goto %d\n",m_sec_sequence.current()->steps);
1055                                                 setSecSequencePos(cmd.steps);
1056                                                 break;
1057                                         }
1058                                 }
1059                                 else
1060                                 {
1061                                         eDebug("[SEC] rotor locked step %d failed", cmd.okcount);
1062                                         --m_timeoutCount;
1063                                         if (!m_timeoutCount && m_retryCount > 0)
1064                                                 --m_retryCount;
1065                                         cmd.okcount=0;
1066                                 }
1067                                 ++m_sec_sequence.current();
1068                                 break;
1069                         }
1070                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1071                                 m_runningInputpower = readInputpower();
1072                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
1073                                 ++m_sec_sequence.current();
1074                                 break;
1075                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1076                         {
1077                                 int idleInputpower = m_idleInputpower[ (m_curVoltage&1) ? 0 : 1];
1078                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1079                                 const char *txt = cmd.direction ? "running" : "stopped";
1080                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1081                                         txt,
1082                                         m_runningInputpower,
1083                                         idleInputpower,
1084                                         cmd.deltaA);
1085                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1086                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1087                                 {
1088                                         ++cmd.okcount;
1089                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1090                                         if ( cmd.okcount > 6 )
1091                                         {
1092                                                 m_sec->setRotorMoving(cmd.direction);
1093                                                 eDebug("[SEC] rotor is %s", txt);
1094                                                 if (setSecSequencePos(cmd.steps))
1095                                                         break;
1096                                         }
1097                                 }
1098                                 else
1099                                 {
1100                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1101                                         --m_timeoutCount;
1102                                         if (!m_timeoutCount && m_retryCount > 0)
1103                                                 --m_retryCount;
1104                                         cmd.okcount=0;
1105                                 }
1106                                 ++m_sec_sequence.current();
1107                                 break;
1108                         }
1109                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1110                                 if (m_data[5] != -1 && m_data[6] != -1)
1111                                         setSecSequencePos(m_sec_sequence.current()->steps);
1112                                 else
1113                                         ++m_sec_sequence.current();
1114                                 break;
1115                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1116                                 m_data[5] = m_data[6] = -1;
1117                                 eDebug("[SEC] invalidate current rotorparams");
1118                                 ++m_sec_sequence.current();
1119                                 break;
1120                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1121                                 m_data[5] = m_data[3];
1122                                 m_data[6] = m_data[4];
1123                                 eDebug("[SEC] update current rotorparams %d %04x %d", m_timeoutCount, m_data[5], m_data[6]);
1124                                 ++m_sec_sequence.current();
1125                                 break;
1126                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1127                                 m_retryCount = m_sec_sequence.current()++->val;
1128                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
1129                                 break;
1130                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1131                                 if (!m_retryCount)
1132                                 {
1133                                         eDebug("[SEC] no more rotor retrys");
1134                                         setSecSequencePos(m_sec_sequence.current()->steps);
1135                                 }
1136                                 else
1137                                         ++m_sec_sequence.current();
1138                                 break;
1139                         case eSecCommand::SET_POWER_LIMITING_MODE:
1140                         {
1141                                 int fd = m_fe ?
1142                                         ::open("/dev/i2c/1", O_RDWR) :
1143                                         ::open("/dev/i2c/0", O_RDWR);
1144
1145                                 unsigned char data[2];
1146                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1147                                 if(::read(fd, data, 1) != 1)
1148                                         eDebug("[SEC] error read lnbp (%m)");
1149                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1150                                 {
1151                                         data[0] |= 0x80;  // enable static current limiting
1152                                         eDebug("[SEC] set static current limiting");
1153                                 }
1154                                 else
1155                                 {
1156                                         data[0] &= ~0x80;  // enable dynamic current limiting
1157                                         eDebug("[SEC] set dynamic current limiting");
1158                                 }
1159                                 if(::write(fd, data, 1) != 1)
1160                                         eDebug("[SEC] error write lnbp (%m)");
1161                                 ::close(fd);
1162                                 ++m_sec_sequence.current();
1163                                 break;
1164                         }
1165                         default:
1166                                 ++m_sec_sequence.current();
1167                                 eDebug("[SEC] unhandled sec command");
1168                 }
1169                 m_tuneTimer->start(delay,true);
1170         }
1171 }
1172
1173 void eDVBFrontend::setFrontend()
1174 {
1175         eDebug("setting frontend %d", m_fe);
1176         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1177         {
1178                 perror("FE_SET_FRONTEND failed");
1179                 return;
1180         }
1181 }
1182
1183 RESULT eDVBFrontend::getFrontendType(int &t)
1184 {
1185         if (m_type == -1)
1186                 return -ENODEV;
1187         t = m_type;
1188         return 0;
1189 }
1190
1191 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm)
1192 {
1193         int res;
1194         if (!m_sec)
1195         {
1196                 eWarning("no SEC module active!");
1197                 return -ENOENT;
1198         }
1199         res = m_sec->prepare(*this, parm, feparm, 1 << m_fe);
1200         if (!res)
1201         {
1202                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1203                 switch (feparm.inversion)
1204                 {
1205                         case eDVBFrontendParametersSatellite::Inversion::On:
1206                                 parm_inversion = INVERSION_ON;
1207                                 break;
1208                         case eDVBFrontendParametersSatellite::Inversion::Off:
1209                                 parm_inversion = INVERSION_OFF;
1210                                 break;
1211                         default:
1212                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1213                                 parm_inversion = INVERSION_AUTO;
1214                                 break;
1215                 }
1216                 switch (feparm.fec)
1217                 {
1218                         default:
1219                         case eDVBFrontendParametersSatellite::FEC::fNone:
1220                                 eDebug("no fec set.. assume auto");
1221                         case eDVBFrontendParametersSatellite::FEC::fAuto:
1222                                 parm_u_qpsk_fec_inner = FEC_AUTO;
1223                                 break;
1224                         case eDVBFrontendParametersSatellite::FEC::f1_2:
1225                                 parm_u_qpsk_fec_inner = FEC_1_2;
1226                                 break;
1227                         case eDVBFrontendParametersSatellite::FEC::f2_3:
1228                                 parm_u_qpsk_fec_inner = FEC_2_3;
1229                                 break;
1230                         case eDVBFrontendParametersSatellite::FEC::f3_4:
1231                                 parm_u_qpsk_fec_inner = FEC_3_4;
1232                                 break;
1233                         case eDVBFrontendParametersSatellite::FEC::f5_6:
1234                                 parm_u_qpsk_fec_inner = FEC_5_6;
1235                                 break;
1236                         case eDVBFrontendParametersSatellite::FEC::f7_8:
1237                                 parm_u_qpsk_fec_inner = FEC_7_8;
1238                                 break;
1239                 }
1240                 // FIXME !!! get frequency range from tuner
1241                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1242                 {
1243                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1244                         return -EINVAL;
1245                 }
1246                 eDebug("tuning to %d mhz", parm_frequency/1000);
1247         }
1248         return res;
1249 }
1250
1251 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1252 {
1253         parm_frequency = feparm.frequency * 1000;
1254         parm_u_qam_symbol_rate = feparm.symbol_rate;
1255         switch (feparm.modulation)
1256         {
1257         case eDVBFrontendParametersCable::Modulation::QAM16:
1258                 parm_u_qam_modulation = QAM_16;
1259                 break;
1260         case eDVBFrontendParametersCable::Modulation::QAM32:
1261                 parm_u_qam_modulation = QAM_32;
1262                 break;
1263         case eDVBFrontendParametersCable::Modulation::QAM64:
1264                 parm_u_qam_modulation = QAM_64;
1265                 break;
1266         case eDVBFrontendParametersCable::Modulation::QAM128:
1267                 parm_u_qam_modulation = QAM_128;
1268                 break;
1269         case eDVBFrontendParametersCable::Modulation::QAM256:
1270                 parm_u_qam_modulation = QAM_256;
1271                 break;
1272         default:
1273         case eDVBFrontendParametersCable::Modulation::Auto:
1274                 parm_u_qam_modulation = QAM_AUTO;
1275                 break;
1276         }
1277         switch (feparm.inversion)
1278         {
1279         case eDVBFrontendParametersCable::Inversion::On:
1280                 parm_inversion = INVERSION_ON;
1281                 break;
1282         case eDVBFrontendParametersCable::Inversion::Off:
1283                 parm_inversion = INVERSION_OFF;
1284                 break;
1285         default:
1286         case eDVBFrontendParametersCable::Inversion::Unknown:
1287                 parm_inversion = INVERSION_AUTO;
1288                 break;
1289         }
1290         switch (feparm.fec_inner)
1291         {
1292         case eDVBFrontendParametersCable::FEC::fNone:
1293                 parm_u_qam_fec_inner = FEC_NONE;
1294                 break;
1295         case eDVBFrontendParametersCable::FEC::f1_2:
1296                 parm_u_qam_fec_inner = FEC_1_2;
1297                 break;
1298         case eDVBFrontendParametersCable::FEC::f2_3:
1299                 parm_u_qam_fec_inner = FEC_2_3;
1300                 break;
1301         case eDVBFrontendParametersCable::FEC::f3_4:
1302                 parm_u_qam_fec_inner = FEC_3_4;
1303                 break;
1304         case eDVBFrontendParametersCable::FEC::f5_6:
1305                 parm_u_qam_fec_inner = FEC_5_6;
1306                 break;
1307         case eDVBFrontendParametersCable::FEC::f7_8:
1308                 parm_u_qam_fec_inner = FEC_7_8;
1309                 break;
1310 #if HAVE_DVB_API_VERSION >= 3
1311         case eDVBFrontendParametersCable::FEC::f8_9:
1312                 parm_u_qam_fec_inner = FEC_8_9;
1313                 break;
1314 #endif
1315         default:
1316         case eDVBFrontendParametersCable::FEC::fAuto:
1317                 parm_u_qam_fec_inner = FEC_AUTO;
1318                 break;
1319         }
1320         return 0;
1321 }
1322
1323 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1324 {
1325         parm_frequency = feparm.frequency;
1326
1327         switch (feparm.bandwidth)
1328         {
1329         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1330                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1331                 break;
1332         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1333                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1334                 break;
1335         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1336                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1337                 break;
1338         default:
1339         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1340                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1341                 break;
1342         }
1343         switch (feparm.code_rate_LP)
1344         {
1345         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1346                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1347                 break;
1348         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1349                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1350                 break;
1351         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1352                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1353                 break;
1354         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1355                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1356                 break;
1357         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1358                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1359                 break;
1360         default:
1361         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1362                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1363                 break;
1364         }
1365         switch (feparm.code_rate_HP)
1366         {
1367         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1368                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1369                 break;
1370         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1371                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1372                 break;
1373         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1374                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1375                 break;
1376         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1377                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1378                 break;
1379         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1380                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1381                 break;
1382         default:
1383         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1384                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1385                 break;
1386         }
1387         switch (feparm.modulation)
1388         {
1389         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1390                 parm_u_ofdm_constellation = QPSK;
1391                 break;
1392         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1393                 parm_u_ofdm_constellation = QAM_16;
1394                 break;
1395         default:
1396         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1397                 parm_u_ofdm_constellation = QAM_AUTO;
1398                 break;
1399         }
1400         switch (feparm.transmission_mode)
1401         {
1402         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1403                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1404                 break;
1405         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1406                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1407                 break;
1408         default:
1409         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1410                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1411                 break;
1412         }
1413         switch (feparm.guard_interval)
1414         {
1415                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
1416                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
1417                         break;
1418                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
1419                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
1420                         break;
1421                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
1422                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
1423                         break;
1424                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
1425                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
1426                         break;
1427                 default:
1428                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
1429                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
1430                         break;
1431         }
1432         switch (feparm.hierarchy)
1433         {
1434                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
1435                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
1436                         break;
1437                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
1438                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
1439                         break;
1440                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
1441                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
1442                         break;
1443                 default:
1444                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
1445                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
1446                         break;
1447         }
1448         return 0;
1449 }
1450
1451 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
1452 {
1453         eDebug("(%d)tune", m_fe);
1454
1455         int res=0;
1456
1457         if (m_type == -1)
1458                 return -ENODEV;
1459
1460         feEvent(-1);
1461
1462         m_sec_sequence.clear();
1463
1464         switch (m_type)
1465         {
1466         case feSatellite:
1467         {
1468                 eDVBFrontendParametersSatellite feparm;
1469                 if (where.getDVBS(feparm))
1470                 {
1471                         eDebug("no dvbs data!");
1472                         return -EINVAL;
1473                 }
1474                 res=prepare_sat(feparm);
1475                 break;
1476         }
1477         case feCable:
1478         {
1479                 eDVBFrontendParametersCable feparm;
1480                 if (where.getDVBC(feparm))
1481                         return -EINVAL;
1482                 res=prepare_cable(feparm);
1483                 if (!res)
1484                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
1485                 break;
1486         }
1487         case feTerrestrial:
1488         {
1489                 eDVBFrontendParametersTerrestrial feparm;
1490                 if (where.getDVBT(feparm))
1491                 {
1492                         eDebug("no -T data");
1493                         return -EINVAL;
1494                 }
1495                 res=prepare_terrestrial(feparm);
1496                 if (!res)
1497                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
1498                 break;
1499         }
1500         }
1501
1502         if (!res)  // prepare ok
1503         {
1504                 m_tuneTimer->start(0,true);
1505                 m_timeout->stop();
1506                 m_sec_sequence.current() = m_sec_sequence.begin();
1507
1508                 if (m_state != stateTuning)
1509                 {
1510                         m_tuning = 1;
1511                         m_state = stateTuning;
1512                         m_stateChanged(this);
1513                 }
1514         }
1515
1516         return res;
1517 }
1518
1519 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
1520 {
1521         connection = new eConnection(this, m_stateChanged.connect(stateChange));
1522         return 0;
1523 }
1524
1525 RESULT eDVBFrontend::setVoltage(int voltage)
1526 {
1527         if (m_type != feSatellite)
1528                 return -1;
1529 #if HAVE_DVB_API_VERSION < 3
1530         secVoltage vlt;
1531 #else
1532         bool increased=false;
1533         fe_sec_voltage_t vlt;
1534 #endif
1535         m_curVoltage=voltage;
1536         switch (voltage)
1537         {
1538         case voltageOff:
1539                 for (int i=0; i < 3; ++i)  // reset diseqc
1540                         m_data[i]=-1;
1541                 vlt = SEC_VOLTAGE_OFF;
1542                 break;
1543         case voltage13_5:
1544 #if HAVE_DVB_API_VERSION < 3
1545                 vlt = SEC_VOLTAGE_13_5;
1546                 break;
1547 #else
1548                 increased = true;
1549 #endif
1550         case voltage13:
1551                 vlt = SEC_VOLTAGE_13;
1552                 break;
1553         case voltage18_5:
1554 #if HAVE_DVB_API_VERSION < 3
1555                 vlt = SEC_VOLTAGE_18_5;
1556                 break;
1557 #else
1558                 increased = true;
1559 #endif
1560         case voltage18:
1561                 vlt = SEC_VOLTAGE_18;
1562                 break;
1563         default:
1564                 return -ENODEV;
1565         }
1566 #if HAVE_DVB_API_VERSION < 3
1567         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
1568 #else
1569         if (::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
1570                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1571         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
1572 #endif
1573 }
1574
1575 RESULT eDVBFrontend::getState(int &state)
1576 {
1577         state = m_state;
1578         return 0;
1579 }
1580
1581 RESULT eDVBFrontend::setTone(int t)
1582 {
1583         if (m_type != feSatellite)
1584                 return -1;
1585 #if HAVE_DVB_API_VERSION < 3
1586         secToneMode_t tone;
1587 #else
1588         fe_sec_tone_mode_t tone;
1589 #endif
1590
1591         switch (t)
1592         {
1593         case toneOn:
1594                 tone = SEC_TONE_ON;
1595                 break;
1596         case toneOff:
1597                 tone = SEC_TONE_OFF;
1598                 break;
1599         default:
1600                 return -ENODEV;
1601         }
1602 #if HAVE_DVB_API_VERSION < 3    
1603         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
1604 #else   
1605         return ::ioctl(m_fd, FE_SET_TONE, tone);
1606 #endif
1607 }
1608
1609 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
1610         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
1611 #endif
1612
1613 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
1614 {
1615 #if HAVE_DVB_API_VERSION < 3
1616         struct secCommand cmd;
1617         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
1618         cmd.u.diseqc.cmdtype = diseqc.data[0];
1619         cmd.u.diseqc.addr = diseqc.data[1];
1620         cmd.u.diseqc.cmd = diseqc.data[2];
1621         cmd.u.diseqc.numParams = diseqc.len-3;
1622         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
1623         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
1624 #else
1625         struct dvb_diseqc_master_cmd cmd;
1626         memcpy(cmd.msg, diseqc.data, diseqc.len);
1627         cmd.msg_len = diseqc.len;
1628         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
1629 #endif
1630                 return -EINVAL;
1631         return 0;
1632 }
1633
1634 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
1635         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
1636 #endif
1637 RESULT eDVBFrontend::sendToneburst(int burst)
1638 {
1639 #if HAVE_DVB_API_VERSION < 3
1640         secMiniCmd cmd = SEC_MINI_NONE;
1641 #else
1642         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
1643 #endif
1644         if ( burst == eDVBSatelliteDiseqcParameters::A )
1645                 cmd = SEC_MINI_A;
1646         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1647                 cmd = SEC_MINI_B;
1648 #if HAVE_DVB_API_VERSION < 3
1649         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
1650                 return -EINVAL;
1651 #else
1652         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
1653                 return -EINVAL;
1654 #endif
1655         return 0;
1656 }
1657
1658 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
1659 {
1660         m_sec = sec;
1661         return 0;
1662 }
1663
1664 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
1665 {
1666         m_sec_sequence = list;
1667         return 0;
1668 }
1669
1670 RESULT eDVBFrontend::getData(int num, int &data)
1671 {
1672         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1673         {
1674                 data = m_data[num];
1675                 return 0;
1676         }
1677         return -EINVAL;
1678 }
1679
1680 RESULT eDVBFrontend::setData(int num, int val)
1681 {
1682         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1683         {
1684                 m_data[num] = val;
1685                 return 0;
1686         }
1687         return -EINVAL;
1688 }
1689
1690 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
1691 {
1692         int type;
1693         if (feparm->getSystem(type) || type != m_type)
1694                 return 0;
1695
1696         if (m_type == eDVBFrontend::feSatellite)
1697         {
1698                 ASSERT(m_sec);
1699                 eDVBFrontendParametersSatellite sat_parm;
1700                 ASSERT(!feparm->getDVBS(sat_parm));
1701                 return m_sec->canTune(sat_parm, this, 1 << m_fe);
1702         }
1703         return 1;
1704 }