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