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