fix wrap around with enabled movemode
[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_tuning=0;
248
249 #if HAVE_DVB_API_VERSION < 3
250         m_secfd = ::open(m_sec_filename, O_RDWR);
251         if (m_secfd < 0)
252         {
253                 eWarning("failed! (%s) %m", m_sec_filename);
254                 return -1;
255         }
256         FrontendInfo fe_info;
257 #else
258         dvb_frontend_info fe_info;
259 #endif
260         eDebug("opening frontend %d", m_fe);
261         m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
262         if (m_fd < 0)
263         {
264                 eWarning("failed! (%s) %m", m_filename);
265 #if HAVE_DVB_API_VERSION < 3
266                 ::close(m_secfd);
267                 m_secfd=-1;
268 #endif
269                 return -1;
270         }
271
272         if (m_type == -1)
273         {
274                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
275                 {
276                         eWarning("ioctl FE_GET_INFO failed");
277                         ::close(m_fd);
278                         m_fd = -1;
279 #if HAVE_DVB_API_VERSION < 3
280                         ::close(m_secfd);
281                         m_secfd=-1;
282 #endif
283                         return -1;
284                 }
285
286                 switch (fe_info.type)
287                 {
288                 case FE_QPSK:
289                         m_type = iDVBFrontend::feSatellite;
290                         break;
291                 case FE_QAM:
292                         m_type = iDVBFrontend::feCable;
293                         break;
294                 case FE_OFDM:
295                         m_type = iDVBFrontend::feTerrestrial;
296                         break;
297                 default:
298                         eWarning("unknown frontend type.");
299                         ::close(m_fd);
300                         m_fd = -1;
301 #if HAVE_DVB_API_VERSION < 3
302                         ::close(m_secfd);
303                         m_secfd=-1;
304 #endif
305                         return -1;
306                 }
307                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
308         }
309
310         setTone(iDVBFrontend::toneOff);
311         setVoltage(iDVBFrontend::voltageOff);
312
313         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
314         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
315         m_sn->start();
316
317         return 0;
318 }
319
320 int eDVBFrontend::closeFrontend()
321 {
322         if (!m_fe && m_data[7] != -1)
323         {
324                 // try to close the first frontend.. but the second is linked to the first
325                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)m_data[7];
326                 if (linked_fe->m_inuse)
327                 {
328                         eDebug("dont close frontend %d until the linked frontend %d is still in use",
329                                 m_fe, linked_fe->m_frontend->getID());
330                         return -1;
331                 }
332         }
333         if (m_fd >= 0)
334         {
335                 eDebug("close frontend %d", m_fe);
336                 setTone(iDVBFrontend::toneOff);
337                 setVoltage(iDVBFrontend::voltageOff);
338                 ::close(m_fd);
339                 m_fd=-1;
340                 m_data[0] = m_data[1] = m_data[2] = -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::IF_VOLTAGE_GOTO:
520                         {
521                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
522                                 if ( compare.voltage == m_curVoltage && setSecSequencePos(compare.steps) )
523                                         break;
524                                 ++m_sec_sequence.current();
525                                 break;
526                         }
527                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
528                         {
529                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
530                                 if ( compare.voltage != m_curVoltage && setSecSequencePos(compare.steps) )
531                                         break;
532                                 ++m_sec_sequence.current();
533                                 break;
534                         }
535                         case eSecCommand::SET_TONE:
536                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
537                                 setTone(m_sec_sequence.current()++->tone);
538                                 break;
539                         case eSecCommand::SEND_DISEQC:
540                                 sendDiseqc(m_sec_sequence.current()->diseqc);
541                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
542                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
543                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
544                                 eDebug("");
545                                 ++m_sec_sequence.current();
546                                 break;
547                         case eSecCommand::SEND_TONEBURST:
548                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
549                                 sendToneburst(m_sec_sequence.current()++->toneburst);
550                                 break;
551                         case eSecCommand::SET_FRONTEND:
552                                 eDebug("[SEC] setFrontend");
553                                 setFrontend();
554                                 ++m_sec_sequence.current();
555                                 break;
556                         case eSecCommand::SET_TIMEOUT:
557                                 m_timeoutCount = m_sec_sequence.current()++->val;
558                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
559                                 break;
560                         case eSecCommand::IF_TIMEOUT_GOTO:
561                                 if (!m_timeoutCount)
562                                 {
563                                         eDebug("[SEC] rotor timout");
564                                         m_sec->setRotorMoving(false);
565                                         setSecSequencePos(m_sec_sequence.current()->steps);
566                                 }
567                                 else
568                                         ++m_sec_sequence.current();
569                                 break;
570                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
571                         {
572                                 int idx = m_sec_sequence.current()++->val;
573                                 if ( idx == 0 || idx == 1 )
574                                 {
575                                         m_idleInputpower[idx] = readInputpower();
576                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
577                                 }
578                                 else
579                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
580                                 break;
581                         }
582                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
583                         {
584                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
585                                 int idx = compare.voltage;
586                                 if ( idx == 0 || idx == 1 )
587                                 {
588                                         int idle = readInputpower();
589                                         int diff = abs(idle-m_idleInputpower[idx]);
590                                         if ( diff > 0)
591                                         {
592                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
593                                                 setSecSequencePos(compare.steps);
594                                                 break;
595                                         }
596                                 }
597                                 ++m_sec_sequence.current();
598                                 break;
599                         }
600                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
601                                 m_runningInputpower = readInputpower();
602                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
603                                 ++m_sec_sequence.current();
604                                 break;
605                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
606                         {
607                                 int idleInputpower = m_idleInputpower[ (m_curVoltage&1) ? 0 : 1];
608                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
609                                 const char *txt = cmd.direction ? "running" : "stopped";
610                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
611                                         txt,
612                                         m_runningInputpower,
613                                         idleInputpower,
614                                         cmd.deltaA);
615                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
616                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
617                                 {
618                                         ++cmd.okcount;
619                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
620                                         if ( cmd.okcount > 6 )
621                                         {
622                                                 m_sec->setRotorMoving(cmd.direction);
623                                                 eDebug("[SEC] rotor is %s", txt);
624                                                 if (setSecSequencePos(cmd.steps))
625                                                         break;
626                                         }
627                                 }
628                                 else
629                                 {
630                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
631                                         --m_timeoutCount;
632                                         if (!m_timeoutCount && m_retryCount > 0)
633                                                 --m_retryCount;
634                                         cmd.okcount=0;
635                                 }
636                                 ++m_sec_sequence.current();
637                                 break;
638                         }
639                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
640                                 if (m_data[5] != -1 && m_data[6] != -1)
641                                         setSecSequencePos(m_sec_sequence.current()->steps);
642                                 else
643                                         ++m_sec_sequence.current();
644                                 break;
645                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
646                                 m_data[5] = m_data[6] = -1;
647                                 eDebug("[SEC] invalidate current rotorparams");
648                                 ++m_sec_sequence.current();
649                                 break;
650                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
651                                 m_data[5] = m_data[3];
652                                 m_data[6] = m_data[4];
653                                 eDebug("[SEC] update current rotorparams %d %04x %d", m_timeoutCount, m_data[5], m_data[6]);
654                                 ++m_sec_sequence.current();
655                                 break;
656                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
657                                 m_retryCount = m_sec_sequence.current()++->val;
658                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
659                                 break;
660                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
661                                 if (!m_retryCount)
662                                 {
663                                         eDebug("[SEC] no more rotor retrys");
664                                         setSecSequencePos(m_sec_sequence.current()->steps);
665                                 }
666                                 else
667                                         ++m_sec_sequence.current();
668                                 break;
669                         case eSecCommand::SET_POWER_LIMITING_MODE:
670                         {
671                                 int fd = m_fe ?
672                                         ::open("/dev/i2c/1", O_RDWR) :
673                                         ::open("/dev/i2c/0", O_RDWR);
674
675                                 unsigned char data[2];
676                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
677                                 if(::read(fd, data, 1) != 1)
678                                         eDebug("[SEC] error read lnbp (%m)");
679                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
680                                 {
681                                         data[0] |= 0x80;  // enable static current limiting
682                                         eDebug("[SEC] set static current limiting");
683                                 }
684                                 else
685                                 {
686                                         data[0] &= ~0x80;  // enable dynamic current limiting
687                                         eDebug("[SEC] set dynamic current limiting");
688                                 }
689                                 if(::write(fd, data, 1) != 1)
690                                         eDebug("[SEC] error write lnbp (%m)");
691                                 ::close(fd);
692                                 ++m_sec_sequence.current();
693                                 break;
694                         }
695                         default:
696                                 ++m_sec_sequence.current();
697                                 eDebug("[SEC] unhandled sec command");
698                 }
699                 m_tuneTimer->start(delay,true);
700         }
701 }
702
703 void eDVBFrontend::setFrontend()
704 {
705         eDebug("setting frontend %d", m_fe);
706         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
707         {
708                 perror("FE_SET_FRONTEND failed");
709                 return;
710         }
711         m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
712 }
713
714 RESULT eDVBFrontend::getFrontendType(int &t)
715 {
716         if (m_type == -1)
717                 return -ENODEV;
718         t = m_type;
719         return 0;
720 }
721
722 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
723 {
724         eDebug("(%d)tune", m_fe);
725
726         if (m_type == -1)
727                 return -ENODEV;
728
729         feEvent(-1);
730
731         m_sec_sequence.clear();
732
733         switch (m_type)
734         {
735         case feSatellite:
736         {
737                 int res;
738                 eDVBFrontendParametersSatellite feparm;
739                 if (where.getDVBS(feparm))
740                 {
741                         eDebug("no dvbs data!");
742                         return -EINVAL;
743                 }
744                 if (!m_sec)
745                 {
746                         eWarning("no SEC module active!");
747                         return -ENOENT;
748                 }
749                 
750                 res = m_sec->prepare(*this, parm, feparm, 1 << m_fe);
751                 if (res)
752                         return res;
753 #if HAVE_DVB_API_VERSION < 3
754                 eDebug("tuning to %d mhz", parm.Frequency/1000);
755 #else
756                 eDebug("tuning to %d mhz", parm.frequency/1000);
757 #endif
758                 break;
759         }
760         case feCable:
761         {
762 #if HAVE_DVB_API_VERSION >= 3
763                 eDVBFrontendParametersCable feparm;
764                 if (where.getDVBC(feparm))
765                         return -EINVAL;
766 #if HAVE_DVB_API_VERSION < 3
767                 parm.Frequency = feparm.frequency * 1000;
768                 parm.u.qam.SymbolRate = feparm.symbol_rate;
769 #else
770                 parm.frequency = feparm.frequency * 1000;
771                 parm.u.qam.symbol_rate = feparm.symbol_rate;
772 #endif
773                 fe_modulation_t mod=QAM_AUTO;
774                 switch (feparm.modulation)
775                 {
776                 case eDVBFrontendParametersCable::Modulation::QAM16:
777                         mod = QAM_16;
778                         break;
779                 case eDVBFrontendParametersCable::Modulation::QAM32:
780                         mod = QAM_32;
781                         break;
782                 case eDVBFrontendParametersCable::Modulation::QAM64:
783                         mod = QAM_64;
784                         break;
785                 case eDVBFrontendParametersCable::Modulation::QAM128:
786                         mod = QAM_128;
787                         break;
788                 case eDVBFrontendParametersCable::Modulation::QAM256:
789                         mod = QAM_256;
790                         break;                  
791                 case eDVBFrontendParametersCable::Modulation::Auto:
792                         mod = QAM_AUTO;
793                         break;                  
794                 }
795 #if HAVE_DVB_API_VERSION < 3
796                 parm.u.qam.QAM = mod;
797 #else
798                 parm.u.qam.modulation = mod;
799 #endif
800                 switch (feparm.inversion)
801                 {               
802                 case eDVBFrontendParametersCable::Inversion::On:
803                         #if HAVE_DVB_API_VERSION < 3
804                         parm.Inversion =
805                         #else
806                         parm.inversion =
807                         #endif
808                                 INVERSION_ON;
809                         break;
810                 case eDVBFrontendParametersCable::Inversion::Off:
811                         #if HAVE_DVB_API_VERSION < 3
812                         parm.Inversion =
813                         #else
814                         parm.inversion =
815                         #endif
816                                 INVERSION_OFF;
817                         break;
818                 case eDVBFrontendParametersCable::Inversion::Unknown:
819                         #if HAVE_DVB_API_VERSION < 3
820                         parm.Inversion =
821                         #else
822                         parm.inversion =
823                         #endif
824                                 INVERSION_AUTO;
825                         break;
826                 }
827                 
828                 fe_code_rate_t fec_inner=FEC_AUTO;
829                 switch (feparm.fec_inner)
830                 {               
831                 case eDVBFrontendParametersCable::FEC::fNone:
832                         fec_inner = FEC_NONE;
833                         break;
834                 case eDVBFrontendParametersCable::FEC::f1_2:
835                         fec_inner = FEC_1_2;
836                         break;
837                 case eDVBFrontendParametersCable::FEC::f2_3:
838                         fec_inner = FEC_2_3;
839                         break;
840                 case eDVBFrontendParametersCable::FEC::f3_4:
841                         fec_inner = FEC_3_4;
842                         break;
843                 case eDVBFrontendParametersCable::FEC::f4_5:
844                         fec_inner = FEC_4_5;
845                         break;
846                 case eDVBFrontendParametersCable::FEC::f5_6:
847                         fec_inner = FEC_5_6;
848                         break;
849                 case eDVBFrontendParametersCable::FEC::f6_7:
850                         fec_inner = FEC_6_7;
851                         break;
852                 case eDVBFrontendParametersCable::FEC::f7_8:
853                         fec_inner = FEC_7_8;
854                         break;
855                 case eDVBFrontendParametersCable::FEC::f8_9:
856                         fec_inner = FEC_8_9;
857                         break;
858                 case eDVBFrontendParametersCable::FEC::fAuto:
859                         fec_inner = FEC_AUTO;
860                         break;
861                 }
862 #if HAVE_DVB_API_VERSION < 3
863                 parm.u.qam.FEC_inner = fec_inner;
864 #else
865                 parm.u.qam.fec_inner = fec_inner;
866 #endif
867 #else
868                 eFatal("Old API not fully supported");
869 #endif // old api
870                 break;
871         }
872         case feTerrestrial:
873         {
874                 eDVBFrontendParametersTerrestrial feparm;
875                 if (where.getDVBT(feparm))
876                 {
877                         eDebug("no -T data");
878                         return -EINVAL;
879                 }
880 #if HAVE_DVB_API_VERSION < 3
881                 parm.Frequency = feparm.frequency;
882 #else
883                 parm.frequency = feparm.frequency;
884 #endif
885
886                 switch (feparm.bandwidth)
887                 {
888                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
889 #if HAVE_DVB_API_VERSION < 3
890                         parm.u.ofdm.bandWidth =
891 #else
892                         parm.u.ofdm.bandwidth =
893 #endif
894                                 BANDWIDTH_8_MHZ;
895                         break;
896                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
897 #if HAVE_DVB_API_VERSION < 3
898                         parm.u.ofdm.bandWidth =
899 #else
900                         parm.u.ofdm.bandwidth =
901 #endif
902                                 BANDWIDTH_7_MHZ;
903                         break;
904                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
905 #if HAVE_DVB_API_VERSION < 3
906                         parm.u.ofdm.bandWidth =
907 #else
908                         parm.u.ofdm.bandwidth =
909 #endif
910                                 BANDWIDTH_6_MHZ;
911                         break;
912                 case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
913 #if HAVE_DVB_API_VERSION < 3
914                         parm.u.ofdm.bandWidth =
915 #else
916                         parm.u.ofdm.bandwidth =
917 #endif
918                                 BANDWIDTH_AUTO;
919                         break;
920                 default:
921                         eWarning("invalid OFDM bandwith");
922                         return -EINVAL;
923                 }
924                 
925                 parm.u.ofdm.code_rate_HP = FEC_AUTO;
926                 parm.u.ofdm.code_rate_LP = FEC_AUTO;
927                 
928                 switch (feparm.modulation)
929                 {
930                 case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
931                         parm.u.ofdm.constellation = QPSK;
932                         break;
933                 case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
934                         parm.u.ofdm.constellation = QAM_16;
935                         break;
936                 case eDVBFrontendParametersTerrestrial::Modulation::Auto:
937                         parm.u.ofdm.constellation = QAM_AUTO;
938                         break;
939                 }
940                 
941                 switch (feparm.transmission_mode)
942                 {
943                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
944 #if HAVE_DVB_API_VERSION < 3
945                         parm.u.ofdm.TransmissionMode =
946 #else
947                         parm.u.ofdm.transmission_mode =
948 #endif
949                                 TRANSMISSION_MODE_2K;
950                         break;
951                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
952 #if HAVE_DVB_API_VERSION < 3
953                         parm.u.ofdm.TransmissionMode =
954 #else
955                         parm.u.ofdm.transmission_mode =
956 #endif
957                                 TRANSMISSION_MODE_8K;
958                         break;
959                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
960 #if HAVE_DVB_API_VERSION < 3
961                         parm.u.ofdm.TransmissionMode =
962 #else
963                         parm.u.ofdm.transmission_mode =
964 #endif
965                                 TRANSMISSION_MODE_AUTO;
966                         break;
967                 }
968                 
969                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
970                 parm.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
971 #if HAVE_DVB_API_VERSION < 3
972                 parm.Inversion =
973 #else
974                 parm.inversion =
975 #endif
976                         INVERSION_AUTO;
977                 break;
978         }
979         }
980
981         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
982         m_tuneTimer->start(0,true);
983         m_timeout->stop();
984         m_sec_sequence.current() = m_sec_sequence.begin();
985
986         if (m_state != stateTuning)
987         {
988                 m_tuning = 1;
989                 m_state = stateTuning;
990                 m_stateChanged(this);
991         }
992
993         return 0;
994 }
995
996 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
997 {
998         connection = new eConnection(this, m_stateChanged.connect(stateChange));
999         return 0;
1000 }
1001
1002 RESULT eDVBFrontend::setVoltage(int voltage)
1003 {
1004         if (m_type != feSatellite)
1005                 return -1;
1006 #if HAVE_DVB_API_VERSION < 3
1007         secVoltage vlt;
1008 #else
1009         bool increased=false;
1010         fe_sec_voltage_t vlt;
1011 #endif
1012         m_curVoltage=voltage;
1013         switch (voltage)
1014         {
1015         case voltageOff:
1016                 for (int i=0; i < 3; ++i)  // reset diseqc
1017                         m_data[i]=-1;
1018                 vlt = SEC_VOLTAGE_OFF;
1019                 break;
1020         case voltage13_5:
1021 #if HAVE_DVB_API_VERSION < 3
1022                 vlt = SEC_VOLTAGE_13_5;
1023                 break;
1024 #else
1025                 increased = true;
1026 #endif
1027         case voltage13:
1028                 vlt = SEC_VOLTAGE_13;
1029                 break;
1030         case voltage18_5:
1031 #if HAVE_DVB_API_VERSION < 3
1032                 vlt = SEC_VOLTAGE_18_5;
1033                 break;
1034 #else
1035                 increased = true;
1036 #endif
1037         case voltage18:
1038                 vlt = SEC_VOLTAGE_18;
1039                 break;
1040         default:
1041                 return -ENODEV;
1042         }
1043 #if HAVE_DVB_API_VERSION < 3
1044         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
1045 #else
1046         if (::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
1047                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1048         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
1049 #endif
1050 }
1051
1052 RESULT eDVBFrontend::getState(int &state)
1053 {
1054         state = m_state;
1055         return 0;
1056 }
1057
1058 RESULT eDVBFrontend::setTone(int t)
1059 {
1060         if (m_type != feSatellite)
1061                 return -1;
1062 #if HAVE_DVB_API_VERSION < 3
1063         secToneMode_t tone;
1064 #else
1065         fe_sec_tone_mode_t tone;
1066 #endif
1067
1068         switch (t)
1069         {
1070         case toneOn:
1071                 tone = SEC_TONE_ON;
1072                 break;
1073         case toneOff:
1074                 tone = SEC_TONE_OFF;
1075                 break;
1076         default:
1077                 return -ENODEV;
1078         }
1079 #if HAVE_DVB_API_VERSION < 3    
1080         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
1081 #else   
1082         return ::ioctl(m_fd, FE_SET_TONE, tone);
1083 #endif
1084 }
1085
1086 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
1087         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
1088 #endif
1089
1090 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
1091 {
1092 #if HAVE_DVB_API_VERSION < 3
1093         struct secCommand cmd;
1094         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
1095         cmd.u.diseqc.cmdtype = diseqc.data[0];
1096         cmd.u.diseqc.addr = diseqc.data[1];
1097         cmd.u.diseqc.cmd = diseqc.data[2];
1098         cmd.u.diseqc.numParams = diseqc.len-3;
1099         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
1100         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
1101 #else
1102         struct dvb_diseqc_master_cmd cmd;
1103         memcpy(cmd.msg, diseqc.data, diseqc.len);
1104         cmd.msg_len = diseqc.len;
1105         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
1106 #endif
1107                 return -EINVAL;
1108         return 0;
1109 }
1110
1111 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
1112         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
1113 #endif
1114 RESULT eDVBFrontend::sendToneburst(int burst)
1115 {
1116 #if HAVE_DVB_API_VERSION < 3
1117         secMiniCmd cmd = SEC_MINI_NONE;
1118         if ( burst == eDVBSatelliteDiseqcParameters::A )
1119                 cmd = SEC_MINI_A;
1120         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1121                 cmd = SEC_MINI_B;
1122         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
1123                 return -EINVAL;
1124 #else
1125         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
1126         if ( burst == eDVBSatelliteDiseqcParameters::A )
1127                 cmd = SEC_MINI_A;
1128         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1129                 cmd = SEC_MINI_B;
1130         else
1131         {
1132                 eDebug("unknown toneburst!");
1133                 return -EINVAL;
1134         }
1135         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
1136                 return -EINVAL;
1137 #endif
1138         return 0;
1139 }
1140
1141 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
1142 {
1143         m_sec = sec;
1144         return 0;
1145 }
1146
1147 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
1148 {
1149         m_sec_sequence = list;
1150         return 0;
1151 }
1152
1153 RESULT eDVBFrontend::getData(int num, int &data)
1154 {
1155         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1156         {
1157                 data = m_data[num];
1158                 return 0;
1159         }
1160         return -EINVAL;
1161 }
1162
1163 RESULT eDVBFrontend::setData(int num, int val)
1164 {
1165         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1166         {
1167                 m_data[num] = val;
1168                 return 0;
1169         }
1170         return -EINVAL;
1171 }
1172
1173 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
1174 {
1175         int type;
1176         if (feparm->getSystem(type) || type != m_type)
1177                 return 0;
1178
1179         if (m_type == eDVBFrontend::feSatellite)
1180         {
1181                 ASSERT(m_sec);
1182                 eDVBFrontendParametersSatellite sat_parm;
1183                 ASSERT(!feparm->getDVBS(sat_parm));
1184                 return m_sec->canTune(sat_parm, this, 1 << m_fe);
1185         }
1186         return 1;
1187 }