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