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