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