fix pixmaps
[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 parm.frequency parm.Frequency
21 #define parm.u.qam.symbol_rate parm.u.qam.SymbolRate
22 #define parm.u.qam.fec_inner parm.u.qam.FEC_inner
23 #define parm.u.qam.modulation parm.u.qam.QAM
24 #define parm.u.ofdm.bandwidth parm.u.ofdm.bandWidth
25 #define parm.u.ofdm.code_rate_LP parm.u.ofdm.LP_CodeRate
26 #define parm.u.ofdm.code_rate_HP parm.u.ofdm.HP_CodeRate
27 #define parm.u.ofdm.constellation parm.u.ofdm.Constellation
28 #define parm.u.ofdm.transmission_mode parm.u.ofdm.TransmissionMode
29 #define parm.u.ofdm.guard_interval parm.u.ofdm.guardInterval
30 #define parm.u.ofdm.hierarchy_information parm.u.ofdm.HierarchyInformation
31 #define parm.inversion parm.Inversion
32 #else
33 #include <linux/dvb/frontend.h>
34 #endif
35
36 #include <dvbsi++/satellite_delivery_system_descriptor.h>
37 #include <dvbsi++/cable_delivery_system_descriptor.h>
38 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
39
40 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
41 {
42         frequency    = descriptor.getFrequency() * 10;
43         symbol_rate  = descriptor.getSymbolRate() * 100;
44         polarisation = descriptor.getPolarization();
45         fec = descriptor.getFecInner();
46         if ( fec == 0xF )
47                 fec = FEC::fNone;
48         inversion = Inversion::Unknown;
49         orbital_position  = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
50         orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
51         orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
52         orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
53         if (orbital_position && (!descriptor.getWestEastFlag()))
54                 orbital_position = 3600 - orbital_position;
55         eDebug("SAT freq %d, %s, pos %d, sr %d, fec %d",
56                 frequency,
57                 polarisation ? "hor" : "vert",
58                 orbital_position,
59                 symbol_rate, fec);
60 }
61
62 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
63 {
64         frequency = descriptor.getFrequency() / 10;
65         symbol_rate = descriptor.getSymbolRate() * 100;
66         fec_inner = descriptor.getFecInner();
67         if ( fec_inner == 0xF )
68                 fec_inner = FEC::fNone;
69         modulation = descriptor.getModulation();
70         if ( modulation > 0x5 )
71                 modulation = Modulation::Auto;
72         inversion = Inversion::Unknown;
73         eDebug("Cable freq %d, mod %d, sr %d, fec %d",
74                 frequency,
75                 modulation, symbol_rate, fec_inner);
76 }
77
78 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &descriptor)
79 {
80         frequency = descriptor.getCentreFrequency() * 10;
81         bandwidth = descriptor.getBandwidth();
82         if ( bandwidth > 2 ) // 5Mhz forced to auto
83                 bandwidth = Bandwidth::BwAuto;
84         code_rate_HP = descriptor.getCodeRateHpStream();
85         if (code_rate_HP > 4)
86                 code_rate_HP = FEC::fAuto;
87         code_rate_LP = descriptor.getCodeRateLpStream();
88         if (code_rate_LP > 4)
89                 code_rate_LP = FEC::fAuto;
90         transmission_mode = descriptor.getTransmissionMode();
91         if (transmission_mode > 2)
92                 transmission_mode = TransmissionMode::TMAuto;
93         guard_interval = descriptor.getGuardInterval();
94         if (guard_interval > 3)
95                 guard_interval = GuardInterval::GI_Auto;
96         hierarchy = descriptor.getHierarchyInformation()&3;
97         modulation = descriptor.getConstellation();
98         if (modulation > 2)
99                 modulation = Modulation::Auto;
100         inversion = Inversion::Unknown;
101         eDebug("Terr freq %d, bw %d, cr_hp %d, cr_lp %d, tm_mode %d, guard %d, hierarchy %d, const %d",
102                 frequency, bandwidth, code_rate_HP, code_rate_LP, transmission_mode,
103                 guard_interval, hierarchy, modulation);
104 }
105
106 eDVBFrontendParameters::eDVBFrontendParameters(): m_type(-1)
107 {
108 }
109
110 DEFINE_REF(eDVBFrontendParameters);
111
112 RESULT eDVBFrontendParameters::getSystem(int &t) const
113 {
114         if (m_type == -1)
115                 return -1;
116         t = m_type;
117         return 0;
118 }
119
120 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
121 {
122         if (m_type != iDVBFrontend::feSatellite)
123                 return -1;
124         p = sat;
125         return 0;
126 }
127
128 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
129 {
130         if (m_type != iDVBFrontend::feCable)
131                 return -1;
132         p = cable;
133         return 0;
134 }
135
136 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
137 {
138         if (m_type != iDVBFrontend::feTerrestrial)
139                 return -1;
140         p = terrestrial;
141         return 0;
142 }
143
144 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p)
145 {
146         sat = p;
147         m_type = iDVBFrontend::feSatellite;
148         return 0;
149 }
150
151 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
152 {
153         cable = p;
154         m_type = iDVBFrontend::feCable;
155         return 0;
156 }
157
158 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
159 {
160         terrestrial = p;
161         m_type = iDVBFrontend::feTerrestrial;
162         return 0;
163 }
164
165 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff) const
166 {
167         if (!parm)
168                 return -1;
169         int type;
170         if (parm->getSystem(type))
171                 return -1;
172         if (type != m_type)
173         {
174                 diff = 1<<30; // big difference
175                 return 0;
176         }
177         
178         switch (type)
179         {
180         case iDVBFrontend::feSatellite:
181         {
182                 eDVBFrontendParametersSatellite osat;
183                 if (parm->getDVBS(osat))
184                         return -2;
185                 
186                 if (sat.orbital_position != osat.orbital_position)
187                         diff = 1<<29;
188                 else if (sat.polarisation != osat.polarisation)
189                         diff = 1<<28;
190                 else
191                 {
192                         diff = abs(sat.frequency - osat.frequency);
193                         diff += abs(sat.symbol_rate - osat.symbol_rate);
194                 }
195                 return 0;
196         }
197         case iDVBFrontend::feCable:
198         case iDVBFrontend::feTerrestrial:
199         default:
200                 return -1;
201         }
202         return 0;
203 }
204
205 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const 
206 {
207         switch (m_type)
208         {
209         case iDVBFrontend::feSatellite:
210         {
211                 hash = (sat.orbital_position << 16);
212                 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
213                 return 0;
214         }
215         case iDVBFrontend::feCable:
216         case iDVBFrontend::feTerrestrial:
217         default:
218                 return -1;
219         }
220 }
221
222 DEFINE_REF(eDVBFrontend);
223
224 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok)
225         :m_type(-1), m_fe(fe), m_fd(-1), m_timeout(0), m_tuneTimer(0)
226 #if HAVE_DVB_API_VERSION < 3
227         ,m_secfd(-1)
228 #endif
229 {
230 #if HAVE_DVB_API_VERSION < 3
231         sprintf(m_filename, "/dev/dvb/card%d/frontend%d", adap, fe);
232         sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
233 #else
234         sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
235 #endif
236         m_timeout = new eTimer(eApp);
237         CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
238
239         m_tuneTimer = new eTimer(eApp);
240         CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
241
242         int entries = sizeof(m_data) / sizeof(int);
243         for (int i=0; i<entries; ++i)
244                 m_data[i] = -1;
245
246         m_idleInputpower[0]=m_idleInputpower[1]=0;
247
248         ok = !openFrontend();
249         closeFrontend();
250 }
251
252 int eDVBFrontend::openFrontend()
253 {
254         if (m_fd >= 0)
255                 return -1;  // already opened
256
257         m_state=0;
258         m_tuning=0;
259
260 #if HAVE_DVB_API_VERSION < 3
261         m_secfd = ::open(m_sec_filename, O_RDWR);
262         if (m_secfd < 0)
263         {
264                 eWarning("failed! (%s) %m", m_sec_filename);
265                 return -1;
266         }
267         FrontendInfo fe_info;
268 #else
269         dvb_frontend_info fe_info;
270 #endif
271         eDebug("opening frontend %d", m_fe);
272         m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
273         if (m_fd < 0)
274         {
275                 eWarning("failed! (%s) %m", m_filename);
276 #if HAVE_DVB_API_VERSION < 3
277                 ::close(m_secfd);
278                 m_secfd=-1;
279 #endif
280                 return -1;
281         }
282
283         if (m_type == -1)
284         {
285                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
286                 {
287                         eWarning("ioctl FE_GET_INFO failed");
288                         ::close(m_fd);
289                         m_fd = -1;
290 #if HAVE_DVB_API_VERSION < 3
291                         ::close(m_secfd);
292                         m_secfd=-1;
293 #endif
294                         return -1;
295                 }
296
297                 switch (fe_info.type)
298                 {
299                 case FE_QPSK:
300                         m_type = iDVBFrontend::feSatellite;
301                         break;
302                 case FE_QAM:
303                         m_type = iDVBFrontend::feCable;
304                         break;
305                 case FE_OFDM:
306                         m_type = iDVBFrontend::feTerrestrial;
307                         break;
308                 default:
309                         eWarning("unknown frontend type.");
310                         ::close(m_fd);
311                         m_fd = -1;
312 #if HAVE_DVB_API_VERSION < 3
313                         ::close(m_secfd);
314                         m_secfd=-1;
315 #endif
316                         return -1;
317                 }
318                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
319         }
320
321         setTone(iDVBFrontend::toneOff);
322         setVoltage(iDVBFrontend::voltageOff);
323
324         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
325         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
326         m_sn->start();
327
328         return 0;
329 }
330
331 int eDVBFrontend::closeFrontend()
332 {
333         if (!m_fe && m_data[7] != -1)
334         {
335                 // try to close the first frontend.. but the second is linked to the first
336                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)m_data[7];
337                 if (linked_fe->m_inuse)
338                 {
339                         eDebug("dont close frontend %d until the linked frontend %d is still in use",
340                                 m_fe, linked_fe->m_frontend->getID());
341                         return -1;
342                 }
343         }
344         if (m_fd >= 0)
345         {
346                 eDebug("close frontend %d", m_fe);
347                 setTone(iDVBFrontend::toneOff);
348                 setVoltage(iDVBFrontend::voltageOff);
349                 ::close(m_fd);
350                 m_fd=-1;
351                 m_data[0] = m_data[1] = m_data[2] = -1;
352         }
353 #if HAVE_DVB_API_VERSION < 3
354         if (m_secfd >= 0)
355         {
356                 ::close(m_secfd);
357                 m_secfd=-1;
358         }
359 #endif
360         delete m_sn;
361         m_sn=0;
362
363         return 0;
364 }
365
366 eDVBFrontend::~eDVBFrontend()
367 {
368         closeFrontend();
369         delete m_timeout;
370         delete m_tuneTimer;
371 }
372
373 void eDVBFrontend::feEvent(int w)
374 {
375         while (1)
376         {
377 #if HAVE_DVB_API_VERSION < 3
378                 FrontendEvent event;
379 #else
380                 dvb_frontend_event event;
381 #endif
382                 int res;
383                 int state;
384                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
385                 
386                 if (res && (errno == EAGAIN))
387                         break;
388
389                 if (res)
390                 {
391                         eWarning("FE_GET_EVENT failed! %m");
392                         return;
393                 }
394                 
395                 if (w < 0)
396                         continue;
397
398 #if HAVE_DVB_API_VERSION < 3
399                 if (event.type == FE_COMPLETION_EV)
400 #else
401                 eDebug("(%d)fe event: status %x, inversion %s", m_fe, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
402                 if (event.status & FE_HAS_LOCK)
403 #endif
404                 {
405                         state = stateLock;
406                 } else
407                 {
408                         if (m_tuning)
409                                 state = stateTuning;
410                         else
411                         {
412                                 state = stateLostLock;
413                                 m_data[0] = m_data[1] = m_data[2] = -1; // reset diseqc
414                         }
415                 }
416                 if (m_state != state)
417                 {
418                         m_state = state;
419                         m_stateChanged(this);
420                 }
421         }
422 }
423
424 void eDVBFrontend::timeout()
425 {
426         m_tuning = 0;
427         if (m_state == stateTuning)
428         {
429                 m_state = stateFailed;
430                 m_stateChanged(this);
431         }
432 }
433
434 int eDVBFrontend::readFrontendData(int type)
435 {
436         switch(type)
437         {
438                 case bitErrorRate:
439                 {
440                         uint32_t ber=0;
441                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
442                                 eDebug("FE_READ_BER failed (%m)");
443                         return ber;
444                 }
445                 case signalPower:
446                 {
447                         uint16_t snr=0;
448                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
449                                 eDebug("FE_READ_SNR failed (%m)");
450                         return snr;
451                 }
452                 case signalQuality:
453                 {
454                         uint16_t strength=0;
455                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
456                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
457                         return strength;
458                 }
459         }
460         return 0;
461 }
462
463 #ifndef FP_IOCTL_GET_ID
464 #define FP_IOCTL_GET_ID 0
465 #endif
466 int eDVBFrontend::readInputpower()
467 {
468         int power=m_fe;  // this is needed for read inputpower from the correct tuner !
469
470         // open front prozessor
471         int fp=::open("/dev/dbox/fp0", O_RDWR);
472         if (fp < 0)
473         {
474                 eDebug("couldn't open fp");
475                 return -1;
476         }
477         static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
478         if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
479         {
480                 eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
481                 return -1;
482         }
483         ::close(fp);
484
485         return power;
486 }
487
488 bool eDVBFrontend::setSecSequencePos(int steps)
489 {
490         eDebug("set sequence pos %d", steps);
491         if (!steps)
492                 return false;
493         while( steps > 0 )
494         {
495                 if (m_sec_sequence.current() != m_sec_sequence.end())
496                         ++m_sec_sequence.current();
497                 --steps;
498         }
499         while( steps < 0 )
500         {
501                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
502                         --m_sec_sequence.current();
503                 ++steps;
504         }
505         return true;
506 }
507
508 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
509 {
510         int delay=0;
511         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
512         {
513                 switch (m_sec_sequence.current()->cmd)
514                 {
515                         case eSecCommand::SLEEP:
516                                 delay = m_sec_sequence.current()++->msec;
517                                 eDebug("[SEC] sleep %dms", delay);
518                                 break;
519                         case eSecCommand::GOTO:
520                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
521                                         ++m_sec_sequence.current();
522                                 break;
523                         case eSecCommand::SET_VOLTAGE:
524                         {
525                                 int voltage = m_sec_sequence.current()++->voltage;
526                                 eDebug("[SEC] setVoltage %d", voltage);
527                                 setVoltage(voltage);
528                                 break;
529                         }
530                         case eSecCommand::IF_VOLTAGE_GOTO:
531                         {
532                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
533                                 if ( compare.voltage == m_curVoltage && setSecSequencePos(compare.steps) )
534                                         break;
535                                 ++m_sec_sequence.current();
536                                 break;
537                         }
538                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
539                         {
540                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
541                                 if ( compare.voltage != m_curVoltage && setSecSequencePos(compare.steps) )
542                                         break;
543                                 ++m_sec_sequence.current();
544                                 break;
545                         }
546                         case eSecCommand::SET_TONE:
547                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
548                                 setTone(m_sec_sequence.current()++->tone);
549                                 break;
550                         case eSecCommand::SEND_DISEQC:
551                                 sendDiseqc(m_sec_sequence.current()->diseqc);
552                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
553                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
554                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
555                                 eDebug("");
556                                 ++m_sec_sequence.current();
557                                 break;
558                         case eSecCommand::SEND_TONEBURST:
559                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
560                                 sendToneburst(m_sec_sequence.current()++->toneburst);
561                                 break;
562                         case eSecCommand::SET_FRONTEND:
563                                 eDebug("[SEC] setFrontend");
564                                 setFrontend();
565                                 ++m_sec_sequence.current();
566                                 break;
567                         case eSecCommand::SET_TIMEOUT:
568                                 m_timeoutCount = m_sec_sequence.current()++->val;
569                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
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::MEASURE_IDLE_INPUTPOWER:
582                         {
583                                 int idx = m_sec_sequence.current()++->val;
584                                 if ( idx == 0 || idx == 1 )
585                                 {
586                                         m_idleInputpower[idx] = readInputpower();
587                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
588                                 }
589                                 else
590                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
591                                 break;
592                         }
593                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
594                         {
595                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
596                                 int idx = compare.voltage;
597                                 if ( idx == 0 || idx == 1 )
598                                 {
599                                         int idle = readInputpower();
600                                         int diff = abs(idle-m_idleInputpower[idx]);
601                                         if ( diff > 0)
602                                         {
603                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
604                                                 setSecSequencePos(compare.steps);
605                                                 break;
606                                         }
607                                 }
608                                 ++m_sec_sequence.current();
609                                 break;
610                         }
611                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
612                                 m_runningInputpower = readInputpower();
613                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
614                                 ++m_sec_sequence.current();
615                                 break;
616                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
617                         {
618                                 int idleInputpower = m_idleInputpower[ (m_curVoltage&1) ? 0 : 1];
619                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
620                                 const char *txt = cmd.direction ? "running" : "stopped";
621                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
622                                         txt,
623                                         m_runningInputpower,
624                                         idleInputpower,
625                                         cmd.deltaA);
626                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
627                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
628                                 {
629                                         ++cmd.okcount;
630                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
631                                         if ( cmd.okcount > 6 )
632                                         {
633                                                 m_sec->setRotorMoving(cmd.direction);
634                                                 eDebug("[SEC] rotor is %s", txt);
635                                                 if (setSecSequencePos(cmd.steps))
636                                                         break;
637                                         }
638                                 }
639                                 else
640                                 {
641                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
642                                         --m_timeoutCount;
643                                         if (!m_timeoutCount && m_retryCount > 0)
644                                                 --m_retryCount;
645                                         cmd.okcount=0;
646                                 }
647                                 ++m_sec_sequence.current();
648                                 break;
649                         }
650                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
651                                 if (m_data[5] != -1 && m_data[6] != -1)
652                                         setSecSequencePos(m_sec_sequence.current()->steps);
653                                 else
654                                         ++m_sec_sequence.current();
655                                 break;
656                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
657                                 m_data[5] = m_data[6] = -1;
658                                 eDebug("[SEC] invalidate current rotorparams");
659                                 ++m_sec_sequence.current();
660                                 break;
661                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
662                                 m_data[5] = m_data[3];
663                                 m_data[6] = m_data[4];
664                                 eDebug("[SEC] update current rotorparams %d %04x %d", m_timeoutCount, m_data[5], m_data[6]);
665                                 ++m_sec_sequence.current();
666                                 break;
667                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
668                                 m_retryCount = m_sec_sequence.current()++->val;
669                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
670                                 break;
671                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
672                                 if (!m_retryCount)
673                                 {
674                                         eDebug("[SEC] no more rotor retrys");
675                                         setSecSequencePos(m_sec_sequence.current()->steps);
676                                 }
677                                 else
678                                         ++m_sec_sequence.current();
679                                 break;
680                         case eSecCommand::SET_POWER_LIMITING_MODE:
681                         {
682                                 int fd = m_fe ?
683                                         ::open("/dev/i2c/1", O_RDWR) :
684                                         ::open("/dev/i2c/0", O_RDWR);
685
686                                 unsigned char data[2];
687                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
688                                 if(::read(fd, data, 1) != 1)
689                                         eDebug("[SEC] error read lnbp (%m)");
690                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
691                                 {
692                                         data[0] |= 0x80;  // enable static current limiting
693                                         eDebug("[SEC] set static current limiting");
694                                 }
695                                 else
696                                 {
697                                         data[0] &= ~0x80;  // enable dynamic current limiting
698                                         eDebug("[SEC] set dynamic current limiting");
699                                 }
700                                 if(::write(fd, data, 1) != 1)
701                                         eDebug("[SEC] error write lnbp (%m)");
702                                 ::close(fd);
703                                 ++m_sec_sequence.current();
704                                 break;
705                         }
706                         default:
707                                 ++m_sec_sequence.current();
708                                 eDebug("[SEC] unhandled sec command");
709                 }
710                 m_tuneTimer->start(delay,true);
711         }
712 }
713
714 void eDVBFrontend::setFrontend()
715 {
716         eDebug("setting frontend %d", m_fe);
717         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
718         {
719                 perror("FE_SET_FRONTEND failed");
720                 return;
721         }
722         m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
723 }
724
725 RESULT eDVBFrontend::getFrontendType(int &t)
726 {
727         if (m_type == -1)
728                 return -ENODEV;
729         t = m_type;
730         return 0;
731 }
732
733 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
734 {
735         eDebug("(%d)tune", m_fe);
736
737         if (m_type == -1)
738                 return -ENODEV;
739
740         feEvent(-1);
741
742         m_sec_sequence.clear();
743
744         switch (m_type)
745         {
746         case feSatellite:
747         {
748                 int res;
749                 eDVBFrontendParametersSatellite feparm;
750                 if (where.getDVBS(feparm))
751                 {
752                         eDebug("no dvbs data!");
753                         return -EINVAL;
754                 }
755                 if (!m_sec)
756                 {
757                         eWarning("no SEC module active!");
758                         return -ENOENT;
759                 }
760                 
761                 res = m_sec->prepare(*this, parm, feparm, 1 << m_fe);
762                 if (res)
763                         return res;
764                 eDebug("tuning to %d mhz", parm.frequency/1000);
765                 break;
766         }
767         case feCable:
768         {
769                 eDVBFrontendParametersCable feparm;
770                 if (where.getDVBC(feparm))
771                         return -EINVAL;
772                 parm.frequency = feparm.frequency * 1000;
773                 parm.u.qam.symbol_rate = feparm.symbol_rate;
774                 switch (feparm.modulation)
775                 {
776                 case eDVBFrontendParametersCable::Modulation::QAM16:
777                         parm.u.qam.modulation = QAM_16;
778                         break;
779                 case eDVBFrontendParametersCable::Modulation::QAM32:
780                         parm.u.qam.modulation = QAM_32;
781                         break;
782                 case eDVBFrontendParametersCable::Modulation::QAM64:
783                         parm.u.qam.modulation = QAM_64;
784                         break;
785                 case eDVBFrontendParametersCable::Modulation::QAM128:
786                         parm.u.qam.modulation = QAM_128;
787                         break;
788                 case eDVBFrontendParametersCable::Modulation::QAM256:
789                         parm.u.qam.modulation = QAM_256;
790                         break;
791                 default:
792                 case eDVBFrontendParametersCable::Modulation::Auto:
793                         parm.u.qam.modulation = QAM_AUTO;
794                         break;
795                 }
796                 switch (feparm.inversion)
797                 {
798                 case eDVBFrontendParametersCable::Inversion::On:
799                         parm.inversion = INVERSION_ON;
800                         break;
801                 case eDVBFrontendParametersCable::Inversion::Off:
802                         parm.inversion = INVERSION_OFF;
803                         break;
804                 default:
805                 case eDVBFrontendParametersCable::Inversion::Unknown:
806                         parm.inversion = INVERSION_AUTO;
807                         break;
808                 }
809                 switch (feparm.fec_inner)
810                 {
811                 case eDVBFrontendParametersCable::FEC::fNone:
812                         parm.u.qam.fec_inner = FEC_NONE;
813                         break;
814                 case eDVBFrontendParametersCable::FEC::f1_2:
815                         parm.u.qam.fec_inner = FEC_1_2;
816                         break;
817                 case eDVBFrontendParametersCable::FEC::f2_3:
818                         parm.u.qam.fec_inner = FEC_2_3;
819                         break;
820                 case eDVBFrontendParametersCable::FEC::f3_4:
821                         parm.u.qam.fec_inner = FEC_3_4;
822                         break;
823                 case eDVBFrontendParametersCable::FEC::f5_6:
824                         parm.u.qam.fec_inner = FEC_5_6;
825                         break;
826                 case eDVBFrontendParametersCable::FEC::f7_8:
827                         parm.u.qam.fec_inner = FEC_7_8;
828                         break;
829                 case eDVBFrontendParametersCable::FEC::f8_9:
830                         parm.u.qam.fec_inner = FEC_8_9;
831                         break;
832                 default:
833                 case eDVBFrontendParametersCable::FEC::fAuto:
834                         parm.u.qam.fec_inner = FEC_AUTO;
835                         break;
836                 }
837                 break;
838         }
839         case feTerrestrial:
840         {
841                 eDVBFrontendParametersTerrestrial feparm;
842                 if (where.getDVBT(feparm))
843                 {
844                         eDebug("no -T data");
845                         return -EINVAL;
846                 }
847                 parm.frequency = feparm.frequency;
848
849                 switch (feparm.bandwidth)
850                 {
851                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
852                         parm.u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
853                         break;
854                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
855                         parm.u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
856                         break;
857                 case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
858                         parm.u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
859                         break;
860                 default:
861                 case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
862                         parm.u.ofdm.bandwidth = BANDWIDTH_AUTO;
863                         break;
864                 }
865                 switch (feparm.code_rate_LP)
866                 {
867                 case eDVBFrontendParametersCable::FEC::f1_2:
868                         parm.u.ofdm.code_rate_LP = FEC_1_2;
869                         break;
870                 case eDVBFrontendParametersCable::FEC::f2_3:
871                         parm.u.ofdm.code_rate_LP = FEC_2_3;
872                         break;
873                 case eDVBFrontendParametersCable::FEC::f3_4:
874                         parm.u.ofdm.code_rate_LP = FEC_3_4;
875                         break;
876                 case eDVBFrontendParametersCable::FEC::f5_6:
877                         parm.u.ofdm.code_rate_LP = FEC_5_6;
878                         break;
879                 case eDVBFrontendParametersCable::FEC::f7_8:
880                         parm.u.ofdm.code_rate_LP = FEC_7_8;
881                         break;
882                 default:
883                 case eDVBFrontendParametersCable::FEC::fAuto:
884                 case eDVBFrontendParametersCable::FEC::fNone:
885                         parm.u.ofdm.code_rate_LP = FEC_AUTO;
886                         break;
887                 }
888                 switch (feparm.code_rate_HP)
889                 {
890                 case eDVBFrontendParametersCable::FEC::f1_2:
891                         parm.u.ofdm.code_rate_HP = FEC_1_2;
892                         break;
893                 case eDVBFrontendParametersCable::FEC::f2_3:
894                         parm.u.ofdm.code_rate_HP = FEC_2_3;
895                         break;
896                 case eDVBFrontendParametersCable::FEC::f3_4:
897                         parm.u.ofdm.code_rate_HP = FEC_3_4;
898                         break;
899                 case eDVBFrontendParametersCable::FEC::f5_6:
900                         parm.u.ofdm.code_rate_HP = FEC_5_6;
901                         break;
902                 case eDVBFrontendParametersCable::FEC::f7_8:
903                         parm.u.ofdm.code_rate_HP = FEC_7_8;
904                         break;
905                 default:
906                 case eDVBFrontendParametersCable::FEC::fAuto:
907                 case eDVBFrontendParametersCable::FEC::fNone:
908                         parm.u.ofdm.code_rate_HP = FEC_AUTO;
909                         break;
910                 }
911                 switch (feparm.modulation)
912                 {
913                 case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
914                         parm.u.ofdm.constellation = QPSK;
915                         break;
916                 case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
917                         parm.u.ofdm.constellation = QAM_16;
918                         break;
919                 default:
920                 case eDVBFrontendParametersTerrestrial::Modulation::Auto:
921                         parm.u.ofdm.constellation = QAM_AUTO;
922                         break;
923                 }
924                 switch (feparm.transmission_mode)
925                 {
926                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
927                         parm.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
928                         break;
929                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
930                         parm.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
931                         break;
932                 default:
933                 case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
934                         parm.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
935                         break;
936                 }
937                 switch (feparm.guard_interval)
938                 {
939                         case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
940                                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
941                                 break;
942                         case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
943                                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
944                                 break;
945                         case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
946                                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
947                                 break;
948                         case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
949                                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
950                                 break;
951                         default:
952                         case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
953                                 parm.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
954                                 break;
955                 }
956                 switch (feparm.hierarchy)
957                 {
958                         case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
959                                 parm.u.ofdm.hierarchy_information = HIERARCHY_1;
960                                 break;
961                         case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
962                                 parm.u.ofdm.hierarchy_information = HIERARCHY_2;
963                                 break;
964                         case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
965                                 parm.u.ofdm.hierarchy_information = HIERARCHY_4;
966                                 break;
967                         default:
968                         case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
969                                 parm.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
970                                 break;
971                 }
972         }
973         }
974
975         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
976         m_tuneTimer->start(0,true);
977         m_timeout->stop();
978         m_sec_sequence.current() = m_sec_sequence.begin();
979
980         if (m_state != stateTuning)
981         {
982                 m_tuning = 1;
983                 m_state = stateTuning;
984                 m_stateChanged(this);
985         }
986
987         return 0;
988 }
989
990 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
991 {
992         connection = new eConnection(this, m_stateChanged.connect(stateChange));
993         return 0;
994 }
995
996 RESULT eDVBFrontend::setVoltage(int voltage)
997 {
998         if (m_type != feSatellite)
999                 return -1;
1000 #if HAVE_DVB_API_VERSION < 3
1001         secVoltage vlt;
1002 #else
1003         bool increased=false;
1004         fe_sec_voltage_t vlt;
1005 #endif
1006         m_curVoltage=voltage;
1007         switch (voltage)
1008         {
1009         case voltageOff:
1010                 for (int i=0; i < 3; ++i)  // reset diseqc
1011                         m_data[i]=-1;
1012                 vlt = SEC_VOLTAGE_OFF;
1013                 break;
1014         case voltage13_5:
1015 #if HAVE_DVB_API_VERSION < 3
1016                 vlt = SEC_VOLTAGE_13_5;
1017                 break;
1018 #else
1019                 increased = true;
1020 #endif
1021         case voltage13:
1022                 vlt = SEC_VOLTAGE_13;
1023                 break;
1024         case voltage18_5:
1025 #if HAVE_DVB_API_VERSION < 3
1026                 vlt = SEC_VOLTAGE_18_5;
1027                 break;
1028 #else
1029                 increased = true;
1030 #endif
1031         case voltage18:
1032                 vlt = SEC_VOLTAGE_18;
1033                 break;
1034         default:
1035                 return -ENODEV;
1036         }
1037 #if HAVE_DVB_API_VERSION < 3
1038         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
1039 #else
1040         if (::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
1041                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1042         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
1043 #endif
1044 }
1045
1046 RESULT eDVBFrontend::getState(int &state)
1047 {
1048         state = m_state;
1049         return 0;
1050 }
1051
1052 RESULT eDVBFrontend::setTone(int t)
1053 {
1054         if (m_type != feSatellite)
1055                 return -1;
1056 #if HAVE_DVB_API_VERSION < 3
1057         secToneMode_t tone;
1058 #else
1059         fe_sec_tone_mode_t tone;
1060 #endif
1061
1062         switch (t)
1063         {
1064         case toneOn:
1065                 tone = SEC_TONE_ON;
1066                 break;
1067         case toneOff:
1068                 tone = SEC_TONE_OFF;
1069                 break;
1070         default:
1071                 return -ENODEV;
1072         }
1073 #if HAVE_DVB_API_VERSION < 3    
1074         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
1075 #else   
1076         return ::ioctl(m_fd, FE_SET_TONE, tone);
1077 #endif
1078 }
1079
1080 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
1081         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
1082 #endif
1083
1084 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
1085 {
1086 #if HAVE_DVB_API_VERSION < 3
1087         struct secCommand cmd;
1088         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
1089         cmd.u.diseqc.cmdtype = diseqc.data[0];
1090         cmd.u.diseqc.addr = diseqc.data[1];
1091         cmd.u.diseqc.cmd = diseqc.data[2];
1092         cmd.u.diseqc.numParams = diseqc.len-3;
1093         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
1094         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
1095 #else
1096         struct dvb_diseqc_master_cmd cmd;
1097         memcpy(cmd.msg, diseqc.data, diseqc.len);
1098         cmd.msg_len = diseqc.len;
1099         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
1100 #endif
1101                 return -EINVAL;
1102         return 0;
1103 }
1104
1105 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
1106         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
1107 #endif
1108 RESULT eDVBFrontend::sendToneburst(int burst)
1109 {
1110 #if HAVE_DVB_API_VERSION < 3
1111         secMiniCmd cmd = SEC_MINI_NONE;
1112 #else
1113         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
1114 #endif
1115         if ( burst == eDVBSatelliteDiseqcParameters::A )
1116                 cmd = SEC_MINI_A;
1117         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1118                 cmd = SEC_MINI_B;
1119 #if HAVE_DVB_API_VERSION < 3
1120         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
1121                 return -EINVAL;
1122 #else
1123         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
1124                 return -EINVAL;
1125 #endif
1126         return 0;
1127 }
1128
1129 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
1130 {
1131         m_sec = sec;
1132         return 0;
1133 }
1134
1135 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
1136 {
1137         m_sec_sequence = list;
1138         return 0;
1139 }
1140
1141 RESULT eDVBFrontend::getData(int num, int &data)
1142 {
1143         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1144         {
1145                 data = m_data[num];
1146                 return 0;
1147         }
1148         return -EINVAL;
1149 }
1150
1151 RESULT eDVBFrontend::setData(int num, int val)
1152 {
1153         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1154         {
1155                 m_data[num] = val;
1156                 return 0;
1157         }
1158         return -EINVAL;
1159 }
1160
1161 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
1162 {
1163         int type;
1164         if (feparm->getSystem(type) || type != m_type)
1165                 return 0;
1166
1167         if (m_type == eDVBFrontend::feSatellite)
1168         {
1169                 ASSERT(m_sec);
1170                 eDVBFrontendParametersSatellite sat_parm;
1171                 ASSERT(!feparm->getDVBS(sat_parm));
1172                 return m_sec->canTune(sat_parm, this, 1 << m_fe);
1173         }
1174         return 1;
1175 }