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