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