use fec from satellites.xml,
[enigma2.git] / lib / dvb / frontend.cpp
1 #include <config.h>
2 #include <lib/dvb/dvb.h>
3 #include <lib/base/eerror.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8
9 #ifndef I2C_SLAVE_FORCE
10 #define I2C_SLAVE_FORCE 0x0706
11 #endif
12
13 #if HAVE_DVB_API_VERSION < 3
14 #include <ost/frontend.h>
15 #include <ost/sec.h>
16 #define QAM_AUTO                                (Modulation)6
17 #define TRANSMISSION_MODE_AUTO  (TransmitMode)2
18 #define BANDWIDTH_AUTO                  (BandWidth)3
19 #define GUARD_INTERVAL_AUTO             (GuardInterval)4
20 #define HIERARCHY_AUTO                  (Hierarchy)4
21 #define constellation Constellation
22 #define guard_interval guardInterval
23 #define hierarchy_information HierarchyInformation
24 #define code_rate_HP HP_CodeRate
25 #define code_rate_LP LP_CodeRate
26 #else
27 #include <linux/dvb/frontend.h>
28 #endif
29
30 #include <dvbsi++/satellite_delivery_system_descriptor.h>
31 #include <dvbsi++/cable_delivery_system_descriptor.h>
32 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
33
34 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
35 {
36         frequency    = descriptor.getFrequency() * 10;
37         symbol_rate  = descriptor.getSymbolRate() * 100;
38         switch (descriptor.getPolarization())
39         {
40         case 0:
41                 polarisation = Polarisation::Horizontal;
42                 break;
43         case 1:
44                 polarisation = Polarisation::Vertical;
45                 break;
46         case 2:
47                 polarisation = Polarisation::CircularLeft;
48                 break;
49         case 3:
50                 polarisation = Polarisation::CircularRight;
51                 break;
52         }
53         switch (descriptor.getFecInner())
54         {
55         case 1:
56                 fec = FEC::f1_2;
57                 break;
58         case 2:
59                 fec = FEC::f2_3;
60                 break;
61         case 3:
62                 fec = FEC::f3_4;
63                 break;
64         case 4:
65                 fec = FEC::f5_6;
66                 break;
67         case 5:
68                 fec = FEC::f7_8;
69                 break;
70         case 0xF:
71                 fec = FEC::fNone;
72                 break;
73         default:
74                 fec = FEC::fAuto;
75                 break;
76         }
77         inversion = Inversion::Unknown;
78         orbital_position  = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
79         orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
80         orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
81         orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
82         if (orbital_position && (!descriptor.getWestEastFlag()))
83                 orbital_position = 3600 - orbital_position;
84 }
85
86 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
87 {
88         eFatal("nyi");
89 }
90
91 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor  &)
92 {
93         eFatal("nyi");
94 }
95
96 eDVBFrontendParameters::eDVBFrontendParameters(): m_type(-1)
97 {
98 }
99
100 DEFINE_REF(eDVBFrontendParameters);
101
102 RESULT eDVBFrontendParameters::getSystem(int &t) const
103 {
104         if (m_type == -1)
105                 return -1;
106         t = m_type;
107         return 0;
108 }
109
110 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
111 {
112         if (m_type != iDVBFrontend::feSatellite)
113                 return -1;
114         p = sat;
115         return 0;
116 }
117
118 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
119 {
120         if (m_type != iDVBFrontend::feCable)
121                 return -1;
122         p = cable;
123         return 0;
124 }
125
126 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
127 {
128         if (m_type != iDVBFrontend::feTerrestrial)
129                 return -1;
130         p = terrestrial;
131         return 0;
132 }
133
134 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p)
135 {
136         sat = p;
137         m_type = iDVBFrontend::feSatellite;
138         return 0;
139 }
140
141 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
142 {
143         cable = p;
144         m_type = iDVBFrontend::feCable;
145         return 0;
146 }
147
148 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
149 {
150         terrestrial = p;
151         m_type = iDVBFrontend::feTerrestrial;
152         return 0;
153 }
154
155 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff) const
156 {
157         if (!parm)
158                 return -1;
159         int type;
160         if (parm->getSystem(type))
161                 return -1;
162         if (type != m_type)
163         {
164                 diff = 1<<30; // big difference
165                 return 0;
166         }
167         
168         switch (type)
169         {
170         case iDVBFrontend::feSatellite:
171         {
172                 eDVBFrontendParametersSatellite osat;
173                 if (parm->getDVBS(osat))
174                         return -2;
175                 
176                 if (sat.orbital_position != osat.orbital_position)
177                         diff = 1<<29;
178                 else if (sat.polarisation != osat.polarisation)
179                         diff = 1<<28;
180                 else
181                 {
182                         diff = abs(sat.frequency - osat.frequency);
183                         diff += abs(sat.symbol_rate - osat.symbol_rate);
184                 }
185                 return 0;
186         }
187         case iDVBFrontend::feCable:
188         case iDVBFrontend::feTerrestrial:
189         default:
190                 return -1;
191         }
192         return 0;
193 }
194
195 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const 
196 {
197         switch (m_type)
198         {
199         case iDVBFrontend::feSatellite:
200         {
201                 hash = (sat.orbital_position << 16);
202                 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
203                 return 0;
204         }
205         case iDVBFrontend::feCable:
206         case iDVBFrontend::feTerrestrial:
207         default:
208                 return -1;
209         }
210 }
211
212 DEFINE_REF(eDVBFrontend);
213
214 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok)
215         :m_type(-1), m_fe(fe), m_timeout(0), m_tuneTimer(0), m_fd(-1)
216 #if HAVE_DVB_API_VERSION < 3
217         ,m_secfd(-1)
218 #endif
219 {
220 #if HAVE_DVB_API_VERSION < 3
221         sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
222 #endif
223         sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
224
225         m_timeout = new eTimer(eApp);
226         CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
227
228         m_tuneTimer = new eTimer(eApp);
229         CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
230
231         int entries = sizeof(m_data) / sizeof(int);
232         for (int i=0; i<entries; ++i)
233                 m_data[i] = -1;
234
235         m_idleInputpower[0]=m_idleInputpower[1]=0;
236
237         ok = !openFrontend();
238         closeFrontend();
239 }
240
241 int eDVBFrontend::openFrontend()
242 {
243         if (m_fd >= 0)
244                 return -1;  // already opened
245
246         m_state=0;
247         m_curVoltage=voltageOff;
248         m_tuning=0;
249
250 #if HAVE_DVB_API_VERSION < 3
251         m_secfd = ::open(m_sec_filename, O_RDWR);
252         if (m_secfd < 0)
253         {
254                 eWarning("failed! (%s) %m", m_sec_filename);
255                 return -1;
256         }
257         FrontendInfo fe_info;
258 #else
259         dvb_frontend_info fe_info;
260 #endif
261         eDebug("opening frontend %d", m_fe);
262         m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
263         if (m_fd < 0)
264         {
265                 eWarning("failed! (%s) %m", m_filename);
266 #if HAVE_DVB_API_VERSION < 3
267                 ::close(m_secfd);
268                 m_secfd=-1;
269 #endif
270                 return -1;
271         }
272
273         if (m_type == -1)
274         {
275                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
276                 {
277                         eWarning("ioctl FE_GET_INFO failed");
278                         ::close(m_fd);
279                         m_fd = -1;
280 #if HAVE_DVB_API_VERSION < 3
281                         ::close(m_secfd);
282                         m_secfd=-1;
283 #endif
284                         return -1;
285                 }
286
287                 switch (fe_info.type)
288                 {
289                 case FE_QPSK:
290                         m_type = iDVBFrontend::feSatellite;
291                         break;
292                 case FE_QAM:
293                         m_type = iDVBFrontend::feCable;
294                         break;
295                 case FE_OFDM:
296                         m_type = iDVBFrontend::feTerrestrial;
297                         break;
298                 default:
299                         eWarning("unknown frontend type.");
300                         ::close(m_fd);
301                         m_fd = -1;
302 #if HAVE_DVB_API_VERSION < 3
303                         ::close(m_secfd);
304                         m_secfd=-1;
305 #endif
306                         return -1;
307                 }
308                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
309         }
310
311         setTone(iDVBFrontend::toneOff);
312         setVoltage(iDVBFrontend::voltageOff);
313
314         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
315         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
316         m_sn->start();
317
318         return 0;
319 }
320
321 int eDVBFrontend::closeFrontend()
322 {
323         if (!m_fe && m_data[7] != -1)
324         {
325                 // try to close the first frontend.. but the second is linked to the first
326                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)m_data[7];
327                 if (linked_fe->m_inuse)
328                 {
329                         eDebug("dont close frontend %d until the linked frontend %d is still in use",
330                                 m_fe, linked_fe->m_frontend->getID());
331                         return -1;
332                 }
333         }
334         eDebug("close frontend %d", m_fe);
335         if (m_fd >= 0)
336         {
337                 ::close(m_fd);
338                 m_fd=-1;
339         }
340 #if HAVE_DVB_API_VERSION < 3
341         if (m_secfd >= 0)
342         {
343                 ::close(m_secfd);
344                 m_secfd=-1;
345         }
346 #endif
347         delete m_sn;
348         m_sn=0;
349
350         setTone(iDVBFrontend::toneOff);
351         setVoltage(iDVBFrontend::voltageOff);
352         return 0;
353 }
354
355 eDVBFrontend::~eDVBFrontend()
356 {
357         closeFrontend();
358         delete m_timeout;
359         delete m_tuneTimer;
360 }
361
362 void eDVBFrontend::feEvent(int w)
363 {
364         while (1)
365         {
366 #if HAVE_DVB_API_VERSION < 3
367                 FrontendEvent event;
368 #else
369                 dvb_frontend_event event;
370 #endif
371                 int res;
372                 int state;
373                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
374                 
375                 if (res && (errno == EAGAIN))
376                         break;
377
378                 if (res)
379                 {
380                         eWarning("FE_GET_EVENT failed! %m");
381                         return;
382                 }
383                 
384                 if (w < 0)
385                         continue;
386
387 #if HAVE_DVB_API_VERSION < 3
388                 if (event.type == FE_COMPLETION_EV)
389 #else
390                 eDebug("(%d)fe event: status %x, inversion %s", m_fe, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
391                 if (event.status & FE_HAS_LOCK)
392 #endif
393                 {
394                         state = stateLock;
395                 } else
396                 {
397                         if (m_tuning)
398                                 state = stateTuning;
399                         else
400                         {
401                                 state = stateLostLock;
402
403                                 if (m_state != stateLostLock)
404                                         eDebug("FIXME: we lost lock, so we might have to retune.");
405                         }
406                 }
407                 if (m_state != state)
408                 {
409                         m_state = state;
410                         m_stateChanged(this);
411                 }
412         }
413 }
414
415 void eDVBFrontend::timeout()
416 {
417         int state;
418         if (m_state == stateTuning)
419         {
420                 state = stateFailed;
421                 eDebug("DVBFrontend: timeout");
422                 if (m_state != state)
423                 {
424                         m_state = state;
425                         m_stateChanged(this);
426                 }
427                 m_tuning = 0;
428         } else
429                 m_tuning = 0;
430 }
431
432 int eDVBFrontend::readFrontendData(int type)
433 {
434         switch(type)
435         {
436                 case bitErrorRate:
437                 {
438                         uint32_t ber=0;
439                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
440                                 eDebug("FE_READ_BER failed (%m)");
441                         return ber;
442                 }
443                 case signalPower:
444                 {
445                         uint16_t snr=0;
446                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
447                                 eDebug("FE_READ_SNR failed (%m)");
448                         return snr;
449                 }
450                 case signalQuality:
451                 {
452                         uint16_t strength=0;
453                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
454                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
455                         return strength;
456                 }
457         }
458         return 0;
459 }
460
461 #ifndef FP_IOCTL_GET_ID
462 #define FP_IOCTL_GET_ID 0
463 #endif
464 int eDVBFrontend::readInputpower()
465 {
466         int power=m_fe;  // this is needed for read inputpower from the correct tuner !
467
468         // open front prozessor
469         int fp=::open("/dev/dbox/fp0", O_RDWR);
470         if (fp < 0)
471         {
472                 eDebug("couldn't open fp");
473                 return -1;
474         }
475         static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
476         if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
477         {
478                 eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
479                 return -1;
480         }
481         ::close(fp);
482
483         return power;
484 }
485
486 bool eDVBFrontend::setSecSequencePos(int steps)
487 {
488         eDebug("set sequence pos %d", steps);
489         if (!steps)
490                 return false;
491         while( steps > 0 )
492         {
493                 if (m_sec_sequence.current() != m_sec_sequence.end())
494                         ++m_sec_sequence.current();
495                 --steps;
496         }
497         while( steps < 0 )
498         {
499                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
500                         --m_sec_sequence.current();
501                 ++steps;
502         }
503         return true;
504 }
505
506 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
507 {
508         int delay=0;
509         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
510         {
511                 switch (m_sec_sequence.current()->cmd)
512                 {
513                         case eSecCommand::SLEEP:
514                                 delay = m_sec_sequence.current()++->msec;
515                                 eDebug("[SEC] sleep %dms", delay);
516                                 break;
517                         case eSecCommand::GOTO:
518                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
519                                         ++m_sec_sequence.current();
520                                 break;
521                         case eSecCommand::SET_VOLTAGE:
522                                 int voltage = m_sec_sequence.current()++->voltage;
523                                 eDebug("[SEC] setVoltage %d", voltage);
524                                 setVoltage(voltage);
525                                 break;
526                         case eSecCommand::SET_TONE:
527                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
528                                 setTone(m_sec_sequence.current()++->tone);
529                                 break;
530                         case eSecCommand::SEND_DISEQC:
531                                 sendDiseqc(m_sec_sequence.current()->diseqc);
532                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
533                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
534                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
535                                 eDebug("");
536                                 ++m_sec_sequence.current();
537                                 break;
538                         case eSecCommand::SEND_TONEBURST:
539                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
540                                 sendToneburst(m_sec_sequence.current()++->toneburst);
541                                 break;
542                         case eSecCommand::SET_FRONTEND:
543                                 eDebug("[SEC] setFrontend");
544                                 setFrontend();
545                                 ++m_sec_sequence.current();
546                                 break;
547                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
548                         {
549                                 int idx = m_sec_sequence.current()++->val;
550                                 if ( idx == 0 || idx == 1 )
551                                 {
552                                         m_idleInputpower[idx] = readInputpower();
553                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
554                                 }
555                                 else
556                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
557                                 break;
558                         }
559                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
560                                 m_runningInputpower = readInputpower();
561                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
562                                 ++m_sec_sequence.current();
563                                 break;
564                         case eSecCommand::SET_TIMEOUT:
565                                 m_timeoutCount = m_sec_sequence.current()++->val;
566                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
567                                 break;
568                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
569                                 m_data[5] = m_data[3];
570                                 m_data[6] = m_data[4];
571                                 eDebug("[SEC] update current rotorparams %d %04x %d", m_timeoutCount, m_data[5], m_data[6]);
572                                 ++m_sec_sequence.current();
573                                 break;
574                         case eSecCommand::IF_TIMEOUT_GOTO:
575                                 if (!m_timeoutCount)
576                                 {
577                                         eDebug("[SEC] rotor timout");
578                                         m_sec->setRotorMoving(false);
579                                         setSecSequencePos(m_sec_sequence.current()->steps);
580                                 }
581                                 else
582                                         ++m_sec_sequence.current();
583                                 break;
584                         case eSecCommand::SET_POWER_LIMITING_MODE:
585                         {
586                                 int fd = m_fe ?
587                                         ::open("/dev/i2c/1", O_RDWR) :
588                                         ::open("/dev/i2c/0", O_RDWR);
589
590                                 unsigned char data[2];
591                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
592                                 if(::read(fd, data, 1) != 1)
593                                         eDebug("[SEC] error read lnbp (%m)");
594                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
595                                 {
596                                         data[0] |= 0x90;  // enable static current limiting
597                                         eDebug("[SEC] set static current limiting");
598                                 }
599                                 else
600                                 {
601                                         data[0] &= ~0x90;  // enable dynamic current limiting
602                                         eDebug("[SEC] set dynamic current limiting");
603                                 }
604                                 if(::write(fd, data, 1) != 1)
605                                         eDebug("[SEC] error write lnbp (%m)");
606                                 ::close(fd);
607                                 ++m_sec_sequence.current();
608                                 break;
609                         }
610                         case eSecCommand::IF_IDLE_INPUTPOWER_AVAIL_GOTO:
611                                 if (m_idleInputpower[0] && m_idleInputpower[1] && setSecSequencePos(m_sec_sequence.current()->steps))
612                                         break;
613                                 ++m_sec_sequence.current();
614                                 break;
615                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
616                         {
617                                 int idleInputpower = m_idleInputpower[m_curVoltage == iDVBFrontend::voltage13 ? 0 : 1];
618                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
619                                 const char *txt = cmd.direction ? "running" : "stopped";
620                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
621                                         txt,
622                                         m_runningInputpower,
623                                         idleInputpower,
624                                         cmd.deltaA);
625                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
626                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
627                                 {
628                                         ++cmd.okcount;
629                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
630                                         if ( cmd.okcount > 6 )
631                                         {
632                                                 m_sec->setRotorMoving(cmd.direction);
633                                                 eDebug("[SEC] rotor is %s", txt);
634                                                 if (setSecSequencePos(cmd.steps))
635                                                         break;
636                                         }
637                                 }
638                                 else
639                                 {
640                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
641                                         --m_timeoutCount;
642                                         cmd.okcount=0;
643                                 }
644                                 ++m_sec_sequence.current();
645                                 break;
646                         }
647                         case eSecCommand::IF_VOLTAGE_GOTO:
648                         {
649                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
650                                 if ( compare.voltage == m_curVoltage && setSecSequencePos(compare.steps) )
651                                         break;
652                                 ++m_sec_sequence.current();
653                                 break;
654                         }
655                         default:
656                                 ++m_sec_sequence.current();
657                                 eDebug("[SEC] unhandled sec command");
658                 }
659                 m_tuneTimer->start(delay,true);
660         }
661 }
662
663 void eDVBFrontend::setFrontend()
664 {
665         eDebug("setting frontend %d", m_fe);
666         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
667         {
668                 perror("FE_SET_FRONTEND failed");
669                 return;
670         }
671
672         if (m_state != stateTuning)
673         {
674                 m_tuning = 1;
675                 m_state = stateTuning;
676                 m_stateChanged(this);
677         }
678         m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
679 }
680
681 RESULT eDVBFrontend::getFrontendType(int &t)
682 {
683         if (m_type == -1)
684                 return -ENODEV;
685         t = m_type;
686         return 0;
687 }
688
689 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
690 {
691         eDebug("(%d)tune", m_fe);
692
693         if (m_type == -1)
694                 return -ENODEV;
695
696         feEvent(-1);
697
698         m_sec_sequence.clear();
699
700         switch (m_type)
701         {
702         case feSatellite:
703         {
704                 int res;
705                 eDVBFrontendParametersSatellite feparm;
706                 if (where.getDVBS(feparm))
707                 {
708                         eDebug("no dvbs data!");
709                         return -EINVAL;
710                 }
711                 if (!m_sec)
712                 {
713                         eWarning("no SEC module active!");
714                         return -ENOENT;
715                 }
716                 
717                 res = m_sec->prepare(*this, parm, feparm, 1 << m_fe);
718                 if (res)
719                         return res;
720 #if HAVE_DVB_API_VERSION < 3
721                 eDebug("tuning to %d mhz", parm.Frequency/1000);
722 #else
723                 eDebug("tuning to %d mhz", parm.frequency/1000);
724 #endif
725                 break;
726         }
727         case feCable:
728         {
729 #if HAVE_DVB_API_VERSION >= 3
730                 eDVBFrontendParametersCable feparm;
731                 if (where.getDVBC(feparm))
732                         return -EINVAL;
733 #if HAVE_DVB_API_VERSION < 3
734                 parm.Frequency = feparm.frequency * 1000;
735                 parm.u.qam.SymbolRate = feparm.symbol_rate;
736 #else
737                 parm.frequency = feparm.frequency * 1000;
738                 parm.u.qam.symbol_rate = feparm.symbol_rate;
739 #endif
740                 fe_modulation_t mod=QAM_AUTO;
741                 switch (feparm.modulation)
742                 {
743                 case eDVBFrontendParametersCable::Modulation::QAM16:
744                         mod = QAM_16;
745                         break;
746                 case eDVBFrontendParametersCable::Modulation::QAM32:
747                         mod = QAM_32;
748                         break;
749                 case eDVBFrontendParametersCable::Modulation::QAM64:
750                         mod = QAM_64;
751                         break;
752                 case eDVBFrontendParametersCable::Modulation::QAM128:
753                         mod = QAM_128;
754                         break;
755                 case eDVBFrontendParametersCable::Modulation::QAM256:
756                         mod = QAM_256;
757                         break;                  
758                 case eDVBFrontendParametersCable::Modulation::Auto:
759                         mod = QAM_AUTO;
760                         break;                  
761                 }
762 #if HAVE_DVB_API_VERSION < 3
763                 parm.u.qam.QAM = mod;
764 #else
765                 parm.u.qam.modulation = mod;
766 #endif
767                 switch (feparm.inversion)
768                 {               
769                 case eDVBFrontendParametersCable::Inversion::On:
770                         #if HAVE_DVB_API_VERSION < 3
771                         parm.Inversion =
772                         #else
773                         parm.inversion =
774                         #endif
775                                 INVERSION_ON;
776                         break;
777                 case eDVBFrontendParametersCable::Inversion::Off:
778                         #if HAVE_DVB_API_VERSION < 3
779                         parm.Inversion =
780                         #else
781                         parm.inversion =
782                         #endif
783                                 INVERSION_OFF;
784                         break;
785                 case eDVBFrontendParametersCable::Inversion::Unknown:
786                         #if HAVE_DVB_API_VERSION < 3
787                         parm.Inversion =
788                         #else
789                         parm.inversion =
790                         #endif
791                                 INVERSION_AUTO;
792                         break;
793                 }
794                 
795                 fe_code_rate_t fec_inner=FEC_AUTO;
796                 switch (feparm.fec_inner)
797                 {               
798                 case eDVBFrontendParametersCable::FEC::fNone:
799                         fec_inner = FEC_NONE;
800                         break;
801                 case eDVBFrontendParametersCable::FEC::f1_2:
802                         fec_inner = FEC_1_2;
803                         break;
804                 case eDVBFrontendParametersCable::FEC::f2_3:
805                         fec_inner = FEC_2_3;
806                         break;
807                 case eDVBFrontendParametersCable::FEC::f3_4:
808                         fec_inner = FEC_3_4;
809                         break;
810                 case eDVBFrontendParametersCable::FEC::f4_5:
811                         fec_inner = FEC_4_5;
812                         break;
813                 case eDVBFrontendParametersCable::FEC::f5_6:
814                         fec_inner = FEC_5_6;
815                         break;
816                 case eDVBFrontendParametersCable::FEC::f6_7:
817                         fec_inner = FEC_6_7;
818                         break;
819                 case eDVBFrontendParametersCable::FEC::f7_8:
820                         fec_inner = FEC_7_8;
821                         break;
822                 case eDVBFrontendParametersCable::FEC::f8_9:
823                         fec_inner = FEC_8_9;
824                         break;
825                 case eDVBFrontendParametersCable::FEC::fAuto:
826                         fec_inner = FEC_AUTO;
827                         break;
828                 }
829 #if HAVE_DVB_API_VERSION < 3
830                 parm.u.qam.FEC_inner = fec_inner;
831 #else
832                 parm.u.qam.fec_inner = fec_inner;
833 #endif
834 #else
835                 eFatal("Old API not fully supported");
836 #endif // old api
837                 break;
838         }
839         case feTerrestrial:
840         {
841                 eDVBFrontendParametersTerrestrial feparm;
842                 if (where.getDVBT(feparm))
843                 {
844                         eDebug("no -T data");
845                         return -EINVAL;
846                 }
847 #if HAVE_DVB_API_VERSION < 3
848                 parm.Frequency = feparm.frequency;
849 #else
850                 parm.frequency = feparm.frequency;
851 #endif
852
853                 switch (feparm.bandwidth)
854                 {
855                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
856 #if HAVE_DVB_API_VERSION < 3
857                         parm.u.ofdm.bandWidth =
858 #else
859                         parm.u.ofdm.bandwidth =
860 #endif
861                                 BANDWIDTH_8_MHZ;
862                         break;
863                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
864 #if HAVE_DVB_API_VERSION < 3
865                         parm.u.ofdm.bandWidth =
866 #else
867                         parm.u.ofdm.bandwidth =
868 #endif
869                                 BANDWIDTH_7_MHZ;
870                         break;
871                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
872 #if HAVE_DVB_API_VERSION < 3
873                         parm.u.ofdm.bandWidth =
874 #else
875                         parm.u.ofdm.bandwidth =
876 #endif
877                                 BANDWIDTH_6_MHZ;
878                         break;
879                 case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
880 #if HAVE_DVB_API_VERSION < 3
881                         parm.u.ofdm.bandWidth =
882 #else
883                         parm.u.ofdm.bandwidth =
884 #endif
885                                 BANDWIDTH_AUTO;
886                         break;
887                 default:
888                         eWarning("invalid OFDM bandwith");
889                         return -EINVAL;
890                 }
891                 
892                 parm.u.ofdm.code_rate_HP = FEC_AUTO;
893                 parm.u.ofdm.code_rate_LP = FEC_AUTO;
894                 
895                 switch (feparm.modulation)
896                 {
897                 case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
898                         parm.u.ofdm.constellation = QPSK;
899                         break;
900                 case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
901                         parm.u.ofdm.constellation = QAM_16;
902                         break;
903                 case eDVBFrontendParametersTerrestrial::Modulation::Auto:
904                         parm.u.ofdm.constellation = QAM_AUTO;
905                         break;
906                 }
907                 
908                 switch (feparm.transmission_mode)
909                 {
910                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
911 #if HAVE_DVB_API_VERSION < 3
912                         parm.u.ofdm.TransmissionMode =
913 #else
914                         parm.u.ofdm.transmission_mode =
915 #endif
916                                 TRANSMISSION_MODE_2K;
917                         break;
918                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
919 #if HAVE_DVB_API_VERSION < 3
920                         parm.u.ofdm.TransmissionMode =
921 #else
922                         parm.u.ofdm.transmission_mode =
923 #endif
924                                 TRANSMISSION_MODE_8K;
925                         break;
926                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
927 #if HAVE_DVB_API_VERSION < 3
928                         parm.u.ofdm.TransmissionMode =
929 #else
930                         parm.u.ofdm.transmission_mode =
931 #endif
932                                 TRANSMISSION_MODE_AUTO;
933                         break;
934                 }
935                 
936                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
937                 parm.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
938 #if HAVE_DVB_API_VERSION < 3
939                 parm.Inversion =
940 #else
941                 parm.inversion =
942 #endif
943                         INVERSION_AUTO;
944                 break;
945         }
946         }
947
948         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
949         m_tuneTimer->start(0,true);
950         m_sec_sequence.current() = m_sec_sequence.begin();
951
952         return 0;
953 }
954
955 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
956 {
957         connection = new eConnection(this, m_stateChanged.connect(stateChange));
958         return 0;
959 }
960
961 RESULT eDVBFrontend::setVoltage(int voltage)
962 {
963         if (m_type != feSatellite)
964                 return -1;
965 #if HAVE_DVB_API_VERSION < 3
966         secVoltage vlt;
967 #else
968         fe_sec_voltage_t vlt;
969 #endif
970
971         m_curVoltage=voltage;
972         switch (voltage)
973         {
974         case voltageOff:
975                 for (int i=0; i < 3; ++i)  // reset diseqc
976                         m_data[i]=-1;
977                 vlt = SEC_VOLTAGE_OFF;
978                 break;
979         case voltage13:
980                 vlt = SEC_VOLTAGE_13;
981                 break;
982         case voltage18:
983                 vlt = SEC_VOLTAGE_18;
984                 break;
985         default:
986                 return -ENODEV;
987         }
988 #if HAVE_DVB_API_VERSION < 3
989         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
990 #else
991         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
992 #endif
993 }
994
995 RESULT eDVBFrontend::getState(int &state)
996 {
997         state = m_state;
998         return 0;
999 }
1000
1001 RESULT eDVBFrontend::setTone(int t)
1002 {
1003         if (m_type != feSatellite)
1004                 return -1;
1005 #if HAVE_DVB_API_VERSION < 3
1006         secToneMode_t tone;
1007 #else
1008         fe_sec_tone_mode_t tone;
1009 #endif
1010
1011         switch (t)
1012         {
1013         case toneOn:
1014                 tone = SEC_TONE_ON;
1015                 break;
1016         case toneOff:
1017                 tone = SEC_TONE_OFF;
1018                 break;
1019         default:
1020                 return -ENODEV;
1021         }
1022 #if HAVE_DVB_API_VERSION < 3    
1023         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
1024 #else   
1025         return ::ioctl(m_fd, FE_SET_TONE, tone);
1026 #endif
1027 }
1028
1029 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
1030         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
1031 #endif
1032
1033 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
1034 {
1035 #if HAVE_DVB_API_VERSION < 3
1036         struct secCommand cmd;
1037         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
1038         cmd.u.diseqc.cmdtype = diseqc.data[0];
1039         cmd.u.diseqc.addr = diseqc.data[1];
1040         cmd.u.diseqc.cmd = diseqc.data[2];
1041         cmd.u.diseqc.numParams = diseqc.len-3;
1042         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
1043         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
1044 #else
1045         struct dvb_diseqc_master_cmd cmd;
1046         memcpy(cmd.msg, diseqc.data, diseqc.len);
1047         cmd.msg_len = diseqc.len;
1048         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
1049 #endif
1050                 return -EINVAL;
1051         return 0;
1052 }
1053
1054 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
1055         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
1056 #endif
1057 RESULT eDVBFrontend::sendToneburst(int burst)
1058 {
1059 #if HAVE_DVB_API_VERSION < 3
1060         secMiniCmd cmd = SEC_MINI_NONE;
1061         if ( burst == eDVBSatelliteDiseqcParameters::A )
1062                 cmd = SEC_MINI_A;
1063         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1064                 cmd = SEC_MINI_B;
1065         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
1066                 return -EINVAL;
1067 #else
1068         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
1069         if ( burst == eDVBSatelliteDiseqcParameters::A )
1070                 cmd = SEC_MINI_A;
1071         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1072                 cmd = SEC_MINI_B;
1073         else
1074         {
1075                 eDebug("unknown toneburst!");
1076                 return -EINVAL;
1077         }
1078         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
1079                 return -EINVAL;
1080 #endif
1081         return 0;
1082 }
1083
1084 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
1085 {
1086         m_sec = sec;
1087         return 0;
1088 }
1089
1090 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
1091 {
1092         m_sec_sequence = list;
1093         return 0;
1094 }
1095
1096 RESULT eDVBFrontend::getData(int num, int &data)
1097 {
1098         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1099         {
1100                 data = m_data[num];
1101                 return 0;
1102         }
1103         return -EINVAL;
1104 }
1105
1106 RESULT eDVBFrontend::setData(int num, int val)
1107 {
1108         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1109         {
1110                 m_data[num] = val;
1111                 return 0;
1112         }
1113         return -EINVAL;
1114 }
1115
1116 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
1117 {
1118         int type;
1119         if (feparm->getSystem(type) || type != m_type)
1120                 return 0;
1121
1122         if (m_type == eDVBFrontend::feSatellite)
1123         {
1124                 ASSERT(m_sec);
1125                 eDVBFrontendParametersSatellite sat_parm;
1126                 ASSERT(!feparm->getDVBS(sat_parm));
1127                 return m_sec->canTune(sat_parm, this, 1 << m_fe);
1128         }
1129         return 1;
1130 }