more changes for dvb-s2
[vuplus_dvbapp] / 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_inversion parm.Inversion
22 #define parm_u_qpsk_symbol_rate parm.u.qpsk.SymbolRate
23 #define parm_u_qpsk_fec_inner parm.u.qpsk.FEC_inner
24 #define parm_u_qam_symbol_rate parm.u.qam.SymbolRate
25 #define parm_u_qam_fec_inner parm.u.qam.FEC_inner
26 #define parm_u_qam_modulation parm.u.qam.QAM
27 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandWidth
28 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.LP_CodeRate
29 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.HP_CodeRate
30 #define parm_u_ofdm_constellation parm.u.ofdm.Constellation
31 #define parm_u_ofdm_transmission_mode parm.u.ofdm.TransmissionMode
32 #define parm_u_ofdm_guard_interval parm.u.ofdm.guardInterval
33 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.HierarchyInformation
34 #else
35 #include <linux/dvb/frontend.h>
36 #define parm_frequency parm.frequency
37 #define parm_inversion parm.inversion
38 #define parm_u_qpsk_symbol_rate parm.u.qpsk.symbol_rate
39 #define parm_u_qpsk_fec_inner parm.u.qpsk.fec_inner
40 #define parm_u_qam_symbol_rate parm.u.qam.symbol_rate
41 #define parm_u_qam_fec_inner parm.u.qam.fec_inner
42 #define parm_u_qam_modulation parm.u.qam.modulation
43 #define parm_u_ofdm_bandwidth parm.u.ofdm.bandwidth
44 #define parm_u_ofdm_code_rate_LP parm.u.ofdm.code_rate_LP
45 #define parm_u_ofdm_code_rate_HP parm.u.ofdm.code_rate_HP
46 #define parm_u_ofdm_constellation parm.u.ofdm.constellation
47 #define parm_u_ofdm_transmission_mode parm.u.ofdm.transmission_mode
48 #define parm_u_ofdm_guard_interval parm.u.ofdm.guard_interval
49 #define parm_u_ofdm_hierarchy_information parm.u.ofdm.hierarchy_information
50 #ifdef FEC_9_10
51         #warning "FEC_9_10 already exist in dvb api ... it seems it is now ready for DVB-S2"
52 #else
53         #define FEC_S2_1_2 (fe_code_rate_t)(FEC_AUTO+1)
54         #define FEC_S2_2_3 (fe_code_rate_t)(FEC_S2_1_2+1)
55         #define FEC_S2_3_4 (fe_code_rate_t)(FEC_S2_2_3+1)
56         #define FEC_S2_5_6 (fe_code_rate_t)(FEC_S2_3_4+1)
57         #define FEC_S2_7_8 (fe_code_rate_t)(FEC_S2_5_6+1)
58         #define FEC_S2_8_9 (fe_code_rate_t)(FEC_S2_7_8+1)
59         #define FEC_S2_3_5 (fe_code_rate_t)(FEC_S2_8_9+1)
60         #define FEC_S2_4_5 (fe_code_rate_t)(FEC_S2_3_5+1)
61         #define FEC_S2_9_10 (fe_code_rate_t)(FEC_S2_4_5+1)
62 #endif
63 #endif
64
65 #include <dvbsi++/satellite_delivery_system_descriptor.h>
66 #include <dvbsi++/cable_delivery_system_descriptor.h>
67 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
68
69 void eDVBDiseqcCommand::setCommandString(const char *str)
70 {
71         if (!str)
72                 return;
73         len=0;
74         int slen = strlen(str);
75         if (slen % 2)
76         {
77                 eDebug("invalid diseqc command string length (not 2 byte aligned)");
78                 return;
79         }
80         if (slen > MAX_DISEQC_LENGTH*2)
81         {
82                 eDebug("invalid diseqc command string length (string is to long)");
83                 return;
84         }
85         unsigned char val=0;
86         for (int i=0; i < slen; ++i)
87         {
88                 unsigned char c = str[i];
89                 switch(c)
90                 {
91                         case '0' ... '9': c-=48; break;
92                         case 'a' ... 'f': c-=87; break;
93                         case 'A' ... 'F': c-=55; break;
94                         default:
95                                 eDebug("invalid character in hex string..ignore complete diseqc command !");
96                                 return;
97                 }
98                 if ( i % 2 )
99                 {
100                         val |= c;
101                         data[i/2] = val;
102                 }
103                 else
104                         val = c << 4;
105         }
106         len = slen/2;
107 }
108
109 void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
110 {
111         frequency    = descriptor.getFrequency() * 10;
112         symbol_rate  = descriptor.getSymbolRate() * 100;
113         polarisation = descriptor.getPolarization();
114         fec = descriptor.getFecInner();
115         if ( fec != FEC::fNone && fec > FEC::f9_10 )
116                 fec = FEC::fAuto;
117         inversion = Inversion::Unknown;
118         orbital_position  = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
119         orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
120         orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
121         orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
122         if (orbital_position && (!descriptor.getWestEastFlag()))
123                 orbital_position = 3600 - orbital_position;
124         system = descriptor.getModulationSystem();
125         modulation = descriptor.getModulation();
126         if (system == System::DVB_S && modulation == Modulation::M8PSK)
127         {
128                 eDebug("satellite_delivery_descriptor non valid modulation type.. force QPSK");
129                 modulation=QPSK;
130         }
131         roll_off = descriptor.getRollOff();
132         if (system == System::DVB_S2)
133         {
134                 eDebug("SAT DVB-S2 freq %d, %s, pos %d, sr %d, fec %d, modulation %d, roll_off %d",
135                         frequency,
136                         polarisation ? "hor" : "vert",
137                         orbital_position,
138                         symbol_rate, fec,
139                         modulation,
140                         roll_off);
141         }
142         else
143         {
144                 eDebug("SAT DVB-S freq %d, %s, pos %d, sr %d, fec %d",
145                         frequency,
146                         polarisation ? "hor" : "vert",
147                         orbital_position,
148                         symbol_rate, fec);
149         }
150 }
151
152 void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
153 {
154         frequency = descriptor.getFrequency() / 10;
155         symbol_rate = descriptor.getSymbolRate() * 100;
156         fec_inner = descriptor.getFecInner();
157         if ( fec_inner == 0xF )
158                 fec_inner = FEC::fNone;
159         modulation = descriptor.getModulation();
160         if ( modulation > 0x5 )
161                 modulation = Modulation::Auto;
162         inversion = Inversion::Unknown;
163         eDebug("Cable freq %d, mod %d, sr %d, fec %d",
164                 frequency,
165                 modulation, symbol_rate, fec_inner);
166 }
167
168 void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &descriptor)
169 {
170         frequency = descriptor.getCentreFrequency() * 10;
171         bandwidth = descriptor.getBandwidth();
172         if ( bandwidth > 2 ) // 5Mhz forced to auto
173                 bandwidth = Bandwidth::BwAuto;
174         code_rate_HP = descriptor.getCodeRateHpStream();
175         if (code_rate_HP > 4)
176                 code_rate_HP = FEC::fAuto;
177         code_rate_LP = descriptor.getCodeRateLpStream();
178         if (code_rate_LP > 4)
179                 code_rate_LP = FEC::fAuto;
180         transmission_mode = descriptor.getTransmissionMode();
181         if (transmission_mode > 1) // TM4k forced to auto
182                 transmission_mode = TransmissionMode::TMAuto;
183         guard_interval = descriptor.getGuardInterval();
184         if (guard_interval > 3)
185                 guard_interval = GuardInterval::GI_Auto;
186         hierarchy = descriptor.getHierarchyInformation()&3;
187         modulation = descriptor.getConstellation();
188         if (modulation > 2)
189                 modulation = Modulation::Auto;
190         inversion = Inversion::Unknown;
191         eDebug("Terr freq %d, bw %d, cr_hp %d, cr_lp %d, tm_mode %d, guard %d, hierarchy %d, const %d",
192                 frequency, bandwidth, code_rate_HP, code_rate_LP, transmission_mode,
193                 guard_interval, hierarchy, modulation);
194 }
195
196 eDVBFrontendParameters::eDVBFrontendParameters(): m_type(-1)
197 {
198 }
199
200 DEFINE_REF(eDVBFrontendParameters);
201
202 RESULT eDVBFrontendParameters::getSystem(int &t) const
203 {
204         if (m_type == -1)
205                 return -1;
206         t = m_type;
207         return 0;
208 }
209
210 RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
211 {
212         if (m_type != iDVBFrontend::feSatellite)
213                 return -1;
214         p = sat;
215         return 0;
216 }
217
218 RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
219 {
220         if (m_type != iDVBFrontend::feCable)
221                 return -1;
222         p = cable;
223         return 0;
224 }
225
226 RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
227 {
228         if (m_type != iDVBFrontend::feTerrestrial)
229                 return -1;
230         p = terrestrial;
231         return 0;
232 }
233
234 RESULT eDVBFrontendParameters::setDVBS(const eDVBFrontendParametersSatellite &p, bool no_rotor_command_on_tune)
235 {
236         sat = p;
237         sat.no_rotor_command_on_tune = no_rotor_command_on_tune;
238         m_type = iDVBFrontend::feSatellite;
239         return 0;
240 }
241
242 RESULT eDVBFrontendParameters::setDVBC(const eDVBFrontendParametersCable &p)
243 {
244         cable = p;
245         m_type = iDVBFrontend::feCable;
246         return 0;
247 }
248
249 RESULT eDVBFrontendParameters::setDVBT(const eDVBFrontendParametersTerrestrial &p)
250 {
251         terrestrial = p;
252         m_type = iDVBFrontend::feTerrestrial;
253         return 0;
254 }
255
256 RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff) const
257 {
258         if (!parm)
259                 return -1;
260         int type;
261         if (parm->getSystem(type))
262                 return -1;
263         if (type != m_type)
264         {
265                 diff = 1<<30; // big difference
266                 return 0;
267         }
268         
269         switch (type)
270         {
271         case iDVBFrontend::feSatellite:
272         {
273                 eDVBFrontendParametersSatellite osat;
274                 if (parm->getDVBS(osat))
275                         return -2;
276                 
277                 if (sat.orbital_position != osat.orbital_position)
278                         diff = 1<<29;
279                 else if (sat.polarisation != osat.polarisation)
280                         diff = 1<<28;
281                 else
282                 {
283                         diff = abs(sat.frequency - osat.frequency);
284                         diff += abs(sat.symbol_rate - osat.symbol_rate);
285                 }
286                 return 0;
287         }
288         case iDVBFrontend::feCable:
289                 eDVBFrontendParametersCable ocable;
290                 if (parm->getDVBC(ocable))
291                         return -2;
292                 
293                 if (cable.modulation != ocable.modulation && cable.modulation != eDVBFrontendParametersCable::Modulation::Auto && ocable.modulation != eDVBFrontendParametersCable::Modulation::Auto)
294                         diff = 1 << 29;
295                 else if (cable.inversion != ocable.inversion && cable.inversion != eDVBFrontendParametersCable::Inversion::Unknown && ocable.inversion != eDVBFrontendParametersCable::Inversion::Unknown)
296                         diff = 1 << 28;
297                 else
298                 {
299                         diff = abs(cable.frequency - ocable.frequency);
300                         diff += abs(cable.symbol_rate - ocable.symbol_rate);
301                 }
302                 
303                 return 0;
304         case iDVBFrontend::feTerrestrial:
305                 eDVBFrontendParametersTerrestrial oterrestrial;
306                 if (parm->getDVBT(oterrestrial))
307                         return -2;
308                 
309                 diff = abs(terrestrial.frequency - oterrestrial.frequency);
310
311                 return 0;
312         default:
313                 return -1;
314         }
315         return 0;
316 }
317
318 RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const
319 {
320         switch (m_type)
321         {
322         case iDVBFrontend::feSatellite:
323         {
324                 hash = (sat.orbital_position << 16);
325                 hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15);
326                 return 0;
327         }
328         case iDVBFrontend::feCable:
329                 hash = 0xFFFF0000;
330                 return 0;
331         case iDVBFrontend::feTerrestrial:
332                 hash = 0xEEEE0000;
333                 return 0;
334         default:
335                 return -1;
336         }
337 }
338
339 DEFINE_REF(eDVBFrontend);
340
341 eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok)
342         :m_type(-1), m_fe(fe), m_fd(-1), m_sn(0), m_timeout(0), m_tuneTimer(0)
343 #if HAVE_DVB_API_VERSION < 3
344         ,m_secfd(-1)
345 #endif
346 {
347 #if HAVE_DVB_API_VERSION < 3
348         sprintf(m_filename, "/dev/dvb/card%d/frontend%d", adap, fe);
349         sprintf(m_sec_filename, "/dev/dvb/card%d/sec%d", adap, fe);
350 #else
351         sprintf(m_filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
352 #endif
353         m_timeout = new eTimer(eApp);
354         CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
355
356         m_tuneTimer = new eTimer(eApp);
357         CONNECT(m_tuneTimer->timeout, eDVBFrontend::tuneLoop);
358
359         int entries = sizeof(m_data) / sizeof(int);
360         for (int i=0; i<entries; ++i)
361                 m_data[i] = -1;
362
363         m_idleInputpower[0]=m_idleInputpower[1]=0;
364
365         ok = !openFrontend();
366         closeFrontend();
367 }
368
369 int eDVBFrontend::openFrontend()
370 {
371         if (m_sn)
372                 return -1;  // already opened
373
374         m_state=0;
375         m_tuning=0;
376
377 #if HAVE_DVB_API_VERSION < 3
378         if (m_secfd < 0)
379         {
380                 m_secfd = ::open(m_sec_filename, O_RDWR);
381                 if (m_secfd < 0)
382                 {
383                         eWarning("failed! (%s) %m", m_sec_filename);
384                         return -1;
385                 }
386         }
387         else
388                 eWarning("sec %d already opened", m_fe);
389         FrontendInfo fe_info;
390 #else
391         dvb_frontend_info fe_info;
392 #endif
393         eDebug("opening frontend %d", m_fe);
394         if (m_fd < 0)
395         {
396                 m_fd = ::open(m_filename, O_RDWR|O_NONBLOCK);
397                 if (m_fd < 0)
398                 {
399                         eWarning("failed! (%s) %m", m_filename);
400 #if HAVE_DVB_API_VERSION < 3
401                         ::close(m_secfd);
402                         m_secfd=-1;
403 #endif
404                         return -1;
405                 }
406         }
407         else
408                 eWarning("frontend %d already opened", m_fe);
409         if (m_type == -1)
410         {
411                 if (::ioctl(m_fd, FE_GET_INFO, &fe_info) < 0)
412                 {
413                         eWarning("ioctl FE_GET_INFO failed");
414                         ::close(m_fd);
415                         m_fd = -1;
416 #if HAVE_DVB_API_VERSION < 3
417                         ::close(m_secfd);
418                         m_secfd=-1;
419 #endif
420                         return -1;
421                 }
422
423                 switch (fe_info.type)
424                 {
425                 case FE_QPSK:
426                         m_type = iDVBFrontend::feSatellite;
427                         break;
428                 case FE_QAM:
429                         m_type = iDVBFrontend::feCable;
430                         break;
431                 case FE_OFDM:
432                         m_type = iDVBFrontend::feTerrestrial;
433                         break;
434                 default:
435                         eWarning("unknown frontend type.");
436                         ::close(m_fd);
437                         m_fd = -1;
438 #if HAVE_DVB_API_VERSION < 3
439                         ::close(m_secfd);
440                         m_secfd=-1;
441 #endif
442                         return -1;
443                 }
444                 eDebug("detected %s frontend", "satellite\0cable\0    terrestrial"+fe_info.type*10);
445         }
446
447         setTone(iDVBFrontend::toneOff);
448         setVoltage(iDVBFrontend::voltageOff);
449
450         m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
451         CONNECT(m_sn->activated, eDVBFrontend::feEvent);
452
453         return 0;
454 }
455
456 int eDVBFrontend::closeFrontend()
457 {
458         if (!m_fe && m_data[7] != -1)
459         {
460                 // try to close the first frontend.. but the second is linked to the first
461                 eDVBRegisteredFrontend *linked_fe = (eDVBRegisteredFrontend*)m_data[7];
462                 if (linked_fe->m_inuse)
463                 {
464                         eDebug("dont close frontend %d until the linked frontend %d is still in use",
465                                 m_fe, linked_fe->m_frontend->getID());
466                         return -1;
467                 }
468         }
469         if (m_fd >= 0)
470         {
471                 eDebug("close frontend %d", m_fe);
472                 m_tuneTimer->stop();
473                 setTone(iDVBFrontend::toneOff);
474                 setVoltage(iDVBFrontend::voltageOff);
475                 if (m_sec)
476                         m_sec->setRotorMoving(false);
477                 if (!::close(m_fd))
478                         m_fd=-1;
479                 else
480                         eWarning("couldnt close frontend %d", m_fe);
481                 m_data[0] = m_data[1] = m_data[2] = -1;
482         }
483 #if HAVE_DVB_API_VERSION < 3
484         if (m_secfd >= 0)
485         {
486                 if (!::close(m_secfd))
487                         m_secfd=-1;
488                 else
489                         eWarning("couldnt close sec %d", m_fe);
490         }
491 #endif
492         delete m_sn;
493         m_sn=0;
494
495         return 0;
496 }
497
498 eDVBFrontend::~eDVBFrontend()
499 {
500         closeFrontend();
501         delete m_timeout;
502         delete m_tuneTimer;
503 }
504
505 void eDVBFrontend::feEvent(int w)
506 {
507         while (1)
508         {
509 #if HAVE_DVB_API_VERSION < 3
510                 FrontendEvent event;
511 #else
512                 dvb_frontend_event event;
513 #endif
514                 int res;
515                 int state;
516                 res = ::ioctl(m_fd, FE_GET_EVENT, &event);
517                 
518                 if (res && (errno == EAGAIN))
519                         break;
520
521                 if (res)
522                 {
523                         eWarning("FE_GET_EVENT failed! %m");
524                         return;
525                 }
526                 
527                 if (w < 0)
528                         continue;
529
530 #if HAVE_DVB_API_VERSION < 3
531                 if (event.type == FE_COMPLETION_EV)
532 #else
533                 eDebug("(%d)fe event: status %x, inversion %s", m_fe, event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
534                 if (event.status & FE_HAS_LOCK)
535 #endif
536                 {
537                         state = stateLock;
538                 } else
539                 {
540                         if (m_tuning)
541                                 state = stateTuning;
542                         else
543                         {
544                                 state = stateLostLock;
545                                 m_data[0] = m_data[1] = m_data[2] = -1; // reset diseqc
546                         }
547                 }
548                 if (m_state != state)
549                 {
550                         m_state = state;
551                         m_stateChanged(this);
552                 }
553         }
554 }
555
556 void eDVBFrontend::timeout()
557 {
558         m_tuning = 0;
559         if (m_state == stateTuning)
560         {
561                 m_state = stateFailed;
562                 m_stateChanged(this);
563         }
564 }
565
566 int eDVBFrontend::readFrontendData(int type)
567 {
568         switch(type)
569         {
570                 case bitErrorRate:
571                 {
572                         uint32_t ber=0;
573                         if (ioctl(m_fd, FE_READ_BER, &ber) < 0 && errno != ERANGE)
574                                 eDebug("FE_READ_BER failed (%m)");
575                         return ber;
576                 }
577                 case signalPower:
578                 {
579                         uint16_t snr=0;
580                         if (ioctl(m_fd, FE_READ_SNR, &snr) < 0 && errno != ERANGE)
581                                 eDebug("FE_READ_SNR failed (%m)");
582                         return snr;
583                 }
584                 case signalQuality:
585                 {
586                         uint16_t strength=0;
587                         if (ioctl(m_fd, FE_READ_SIGNAL_STRENGTH, &strength) < 0 && errno != ERANGE)
588                                 eDebug("FE_READ_SIGNAL_STRENGTH failed (%m)");
589                         return strength;
590                 }
591                 case Locked:
592                 {
593 #if HAVE_DVB_API_VERSION < 3
594                         FrontendStatus status=0;
595 #else
596                         fe_status_t status;
597 #endif
598                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
599                                 eDebug("FE_READ_STATUS failed (%m)");
600                         return !!(status&FE_HAS_LOCK);
601                 }
602                 case Synced:
603                 {
604 #if HAVE_DVB_API_VERSION < 3
605                         FrontendStatus status=0;
606 #else
607                         fe_status_t status;
608 #endif
609                         if ( ioctl(m_fd, FE_READ_STATUS, &status) < 0 && errno != ERANGE )
610                                 eDebug("FE_READ_STATUS failed (%m)");
611                         return !!(status&FE_HAS_SYNC);
612                 }
613         }
614         return 0;
615 }
616
617 void PutToDict(PyObject *dict, const char*key, long value)
618 {
619         PyObject *item = PyInt_FromLong(value);
620         if (item)
621         {
622                 if (PyDict_SetItemString(dict, key, item))
623                         eDebug("put %s to dict failed", key);
624                 Py_DECREF(item);
625         }
626         else
627                 eDebug("could not create PyObject for %s", key);
628 }
629
630 void PutToDict(PyObject *dict, const char*key, const char *value)
631 {
632         PyObject *item = PyString_FromString(value);
633         if (item)
634         {
635                 if (PyDict_SetItemString(dict, key, item))
636                         eDebug("put %s to dict failed", key);
637                 Py_DECREF(item);
638         }
639         else
640                 eDebug("could not create PyObject for %s", key);
641 }
642
643 void fillDictWithSatelliteData(PyObject *dict, const FRONTENDPARAMETERS &parm, eDVBFrontend *fe)
644 {
645         int freq_offset=0;
646         int csw=0;
647         const char *tmp=0;
648         fe->getData(0, csw);
649         fe->getData(9, freq_offset);
650         int frequency = parm_frequency + freq_offset;
651         PutToDict(dict, "frequency", frequency);
652         PutToDict(dict, "symbol_rate", parm_u_qpsk_symbol_rate);
653         switch(parm_u_qpsk_fec_inner)
654         {
655         case FEC_1_2:
656                 tmp = "FEC_1_2";
657                 break;
658         case FEC_2_3:
659                 tmp = "FEC_2_3";
660                 break;
661         case FEC_3_4:
662                 tmp = "FEC_3_4";
663                 break;
664         case FEC_5_6:
665                 tmp = "FEC_5_6";
666                 break;
667         case FEC_7_8:
668                 tmp = "FEC_7_8";
669                 break;
670         case FEC_NONE:
671                 tmp = "FEC_NONE";
672         default:
673         case FEC_AUTO:
674                 tmp = "FEC_AUTO";
675                 break;
676 #if HAVE_DVB_API_VERSION >=3
677         case FEC_S2_1_2:
678                 tmp = "FEC_1_2";
679                 break;
680         case FEC_S2_2_3:
681                 tmp = "FEC_2_3";
682                 break;
683         case FEC_S2_3_4:
684                 tmp = "FEC_3_4";
685                 break;
686         case FEC_S2_5_6:
687                 tmp = "FEC_5_6";
688                 break;
689         case FEC_S2_7_8:
690                 tmp = "FEC_7_8";
691                 break;
692         case FEC_S2_8_9:
693                 tmp = "FEC_8_9";
694                 break;
695         case FEC_S2_3_5:
696                 tmp = "FEC_3_5";
697                 break;
698         case FEC_S2_4_5:
699                 tmp = "FEC_4_5";
700                 break;
701         case FEC_S2_9_10:
702                 tmp = "FEC_9_10";
703                 break;
704 #endif
705         }
706         PutToDict(dict, "fec_inner", tmp);
707         tmp = parm_u_qpsk_fec_inner > FEC_AUTO ?
708                 "DVB-S2" : "DVB-S";
709         PutToDict(dict, "system", tmp);
710 }
711
712 void fillDictWithCableData(PyObject *dict, const FRONTENDPARAMETERS &parm)
713 {
714         const char *tmp=0;
715         PutToDict(dict, "frequency", parm_frequency/1000);
716         PutToDict(dict, "symbol_rate", parm_u_qam_symbol_rate);
717         switch(parm_u_qam_fec_inner)
718         {
719         case FEC_NONE:
720                 tmp = "FEC_NONE";
721                 break;
722         case FEC_1_2:
723                 tmp = "FEC_1_2";
724                 break;
725         case FEC_2_3:
726                 tmp = "FEC_2_3";
727                 break;
728         case FEC_3_4:
729                 tmp = "FEC_3_4";
730                 break;
731         case FEC_5_6:
732                 tmp = "FEC_5_6";
733                 break;
734         case FEC_7_8:
735                 tmp = "FEC_7_8";
736                 break;
737 #if HAVE_DVB_API_VERSION >= 3
738         case FEC_8_9:
739                 tmp = "FEC_8_9";
740                 break;
741 #endif
742         default:
743         case FEC_AUTO:
744                 tmp = "FEC_AUTO";
745                 break;
746         }
747         PutToDict(dict, "fec_inner", tmp);
748         switch(parm_u_qam_modulation)
749         {
750         case QAM_16:
751                 tmp = "QAM_16";
752                 break;
753         case QAM_32:
754                 tmp = "QAM_32";
755                 break;
756         case QAM_64:
757                 tmp = "QAM_64";
758                 break;
759         case QAM_128:
760                 tmp = "QAM_128";
761                 break;
762         case QAM_256:
763                 tmp = "QAM_256";
764                 break;
765         default:
766         case QAM_AUTO:
767                 tmp = "QAM_AUTO";
768                 break;
769         }
770         PutToDict(dict, "modulation", tmp);
771 }
772
773 void fillDictWithTerrestrialData(PyObject *dict, const FRONTENDPARAMETERS &parm)
774 {
775         const char *tmp=0;
776         PutToDict(dict, "frequency", parm_frequency);
777         switch (parm_u_ofdm_bandwidth)
778         {
779         case BANDWIDTH_8_MHZ:
780                 tmp = "BANDWIDTH_8_MHZ";
781                 break;
782         case BANDWIDTH_7_MHZ:
783                 tmp = "BANDWIDTH_7_MHZ";
784                 break;
785         case BANDWIDTH_6_MHZ:
786                 tmp = "BANDWIDTH_6_MHZ";
787                 break;
788         default:
789         case BANDWIDTH_AUTO:
790                 tmp = "BANDWIDTH_AUTO";
791                 break;
792         }
793         PutToDict(dict, "bandwidth", tmp);
794         switch (parm_u_ofdm_code_rate_LP)
795         {
796         case FEC_1_2:
797                 tmp = "FEC_1_2";
798                 break;
799         case FEC_2_3:
800                 tmp = "FEC_2_3";
801                 break;
802         case FEC_3_4:
803                 tmp = "FEC_3_4";
804                 break;
805         case FEC_5_6:
806                 tmp = "FEC_5_6";
807                 break;
808         case FEC_7_8:
809                 tmp = "FEC_7_8";
810                 break;
811         default:
812         case FEC_AUTO:
813                 tmp = "FEC_AUTO";
814                 break;
815         }
816         PutToDict(dict, "code_rate_lp", tmp);
817         switch (parm_u_ofdm_code_rate_HP)
818         {
819         case FEC_1_2:
820                 tmp = "FEC_1_2";
821                 break;
822         case FEC_2_3:
823                 tmp = "FEC_2_3";
824                 break;
825         case FEC_3_4:
826                 tmp = "FEC_3_4";
827                 break;
828         case FEC_5_6:
829                 tmp = "FEC_5_6";
830                 break;
831         case FEC_7_8:
832                 tmp = "FEC_7_8";
833                 break;
834         default:
835         case FEC_AUTO:
836                 tmp = "FEC_AUTO";
837                 break;
838         }
839         PutToDict(dict, "code_rate_hp", tmp);
840         switch (parm_u_ofdm_constellation)
841         {
842         case QPSK:
843                 tmp = "QPSK";
844                 break;
845         case QAM_16:
846                 tmp = "QAM_16";
847                 break;
848         case QAM_64:
849                 tmp = "QAM_64";
850                 break;
851         default:
852         case QAM_AUTO:
853                 tmp = "QAM_AUTO";
854                 break;
855         }
856         PutToDict(dict, "constellation", tmp);
857         switch (parm_u_ofdm_transmission_mode)
858         {
859         case TRANSMISSION_MODE_2K:
860                 tmp = "TRANSMISSION_MODE_2K";
861                 break;
862         case TRANSMISSION_MODE_8K:
863                 tmp = "TRANSMISSION_MODE_8K";
864                 break;
865         default:
866         case TRANSMISSION_MODE_AUTO:
867                 tmp = "TRANSMISSION_MODE_AUTO";
868                 break;
869         }
870         PutToDict(dict, "transmission_mode", tmp);
871         switch (parm_u_ofdm_guard_interval)
872         {
873                 case GUARD_INTERVAL_1_32:
874                         tmp = "GUARD_INTERVAL_1_32";
875                         break;
876                 case GUARD_INTERVAL_1_16:
877                         tmp = "GUARD_INTERVAL_1_16";
878                         break;
879                 case GUARD_INTERVAL_1_8:
880                         tmp = "GUARD_INTERVAL_1_8";
881                         break;
882                 case GUARD_INTERVAL_1_4:
883                         tmp = "GUARD_INTERVAL_1_4";
884                         break;
885                 default:
886                 case GUARD_INTERVAL_AUTO:
887                         tmp = "GUARD_INTERVAL_AUTO";
888                         break;
889         }
890         PutToDict(dict, "guard_interval", tmp);
891         switch (parm_u_ofdm_hierarchy_information)
892         {
893                 case HIERARCHY_NONE:
894                         tmp = "HIERARCHY_NONE";
895                         break;
896                 case HIERARCHY_1:
897                         tmp = "HIERARCHY_1";
898                         break;
899                 case HIERARCHY_2:
900                         tmp = "HIERARCHY_2";
901                         break;
902                 case HIERARCHY_4:
903                         tmp = "HIERARCHY_4";
904                         break;
905                 default:
906                 case HIERARCHY_AUTO:
907                         tmp = "HIERARCHY_AUTO";
908                         break;
909         }
910         PutToDict(dict, "hierarchy_information", tmp);
911 }
912
913 PyObject *eDVBFrontend::readTransponderData(bool original)
914 {
915         PyObject *ret=PyDict_New();
916
917         if (ret)
918         {
919                 bool read=m_fd != -1;
920                 const char *tmp=0;
921
922                 PutToDict(ret, "tuner_number", m_fe);
923
924                 switch(m_type)
925                 {
926                         case feSatellite:
927                                 tmp = "DVB-S";
928                                 break;
929                         case feCable:
930                                 tmp = "DVB-C";
931                                 break;
932                         case feTerrestrial:
933                                 tmp = "DVB-T";
934                                 break;
935                         default:
936                                 tmp = "UNKNOWN";
937                                 read=false;
938                                 break;
939                 }
940                 PutToDict(ret, "tuner_type", tmp);
941
942                 if (read)
943                 {
944                         FRONTENDPARAMETERS front;
945
946                         tmp = "UNKNOWN";
947                         switch(m_state)
948                         {
949                                 case stateIdle:
950                                         tmp="IDLE";
951                                         break;
952                                 case stateTuning:
953                                         tmp="TUNING";
954                                         break;
955                                 case stateFailed:
956                                         tmp="FAILED";
957                                         break;
958                                 case stateLock:
959                                         tmp="LOCKED";
960                                         break;
961                                 case stateLostLock:
962                                         tmp="LOSTLOCK";
963                                         break;
964                                 default:
965                                         break;
966                         }
967                         PutToDict(ret, "tuner_state", tmp);
968
969                         PutToDict(ret, "tuner_locked", readFrontendData(Locked));
970                         PutToDict(ret, "tuner_synced", readFrontendData(Synced));
971                         PutToDict(ret, "tuner_bit_error_rate", readFrontendData(bitErrorRate));
972                         PutToDict(ret, "tuner_signal_power", readFrontendData(signalPower));
973                         PutToDict(ret, "tuner_signal_quality", readFrontendData(signalQuality));
974
975                         if (!original && ioctl(m_fd, FE_GET_FRONTEND, &front)<0)
976                                 eDebug("FE_GET_FRONTEND (%m)");
977                         else
978                         {
979                                 tmp = "INVERSION_AUTO";
980                                 switch(parm_inversion)
981                                 {
982                                         case INVERSION_ON:
983                                                 tmp = "INVERSION_ON";
984                                                 break;
985                                         case INVERSION_OFF:
986                                                 tmp = "INVERSION_OFF";
987                                                 break;
988                                         default:
989                                                 break;
990                                 }
991                                 if (tmp)
992                                         PutToDict(ret, "inversion", tmp);
993
994                                 switch(m_type)
995                                 {
996                                         case feSatellite:
997                                                 fillDictWithSatelliteData(ret, original?parm:front, this);
998                                                 break;
999                                         case feCable:
1000                                                 fillDictWithCableData(ret, original?parm:front);
1001                                                 break;
1002                                         case feTerrestrial:
1003                                                 fillDictWithTerrestrialData(ret, original?parm:front);
1004                                                 break;
1005                                 }
1006                         }
1007                 }
1008         }
1009         else
1010         {
1011                 Py_INCREF(Py_None);
1012                 ret = Py_None;
1013         }
1014         return ret;
1015 }
1016
1017 #ifndef FP_IOCTL_GET_ID
1018 #define FP_IOCTL_GET_ID 0
1019 #endif
1020 int eDVBFrontend::readInputpower()
1021 {
1022         int power=m_fe;  // this is needed for read inputpower from the correct tuner !
1023
1024         // open front prozessor
1025         int fp=::open("/dev/dbox/fp0", O_RDWR);
1026         if (fp < 0)
1027         {
1028                 eDebug("couldn't open fp");
1029                 return -1;
1030         }
1031         static bool old_fp = (::ioctl(fp, FP_IOCTL_GET_ID) < 0);
1032         if ( ioctl( fp, old_fp ? 9 : 0x100, &power ) < 0 )
1033         {
1034                 eDebug("FP_IOCTL_GET_LNB_CURRENT failed (%m)");
1035                 return -1;
1036         }
1037         ::close(fp);
1038
1039         return power;
1040 }
1041
1042 bool eDVBFrontend::setSecSequencePos(int steps)
1043 {
1044         eDebug("set sequence pos %d", steps);
1045         if (!steps)
1046                 return false;
1047         while( steps > 0 )
1048         {
1049                 if (m_sec_sequence.current() != m_sec_sequence.end())
1050                         ++m_sec_sequence.current();
1051                 --steps;
1052         }
1053         while( steps < 0 )
1054         {
1055                 if (m_sec_sequence.current() != m_sec_sequence.begin() && m_sec_sequence.current() != m_sec_sequence.end())
1056                         --m_sec_sequence.current();
1057                 ++steps;
1058         }
1059         return true;
1060 }
1061
1062 void eDVBFrontend::tuneLoop()  // called by m_tuneTimer
1063 {
1064         int delay=0;
1065         if ( m_sec_sequence && m_sec_sequence.current() != m_sec_sequence.end() )
1066         {
1067 //              eDebug("tuneLoop %d\n", m_sec_sequence.current()->cmd);
1068                 switch (m_sec_sequence.current()->cmd)
1069                 {
1070                         case eSecCommand::SLEEP:
1071                                 delay = m_sec_sequence.current()++->msec;
1072                                 eDebug("[SEC] sleep %dms", delay);
1073                                 break;
1074                         case eSecCommand::GOTO:
1075                                 if ( !setSecSequencePos(m_sec_sequence.current()->steps) )
1076                                         ++m_sec_sequence.current();
1077                                 break;
1078                         case eSecCommand::SET_VOLTAGE:
1079                         {
1080                                 int voltage = m_sec_sequence.current()++->voltage;
1081                                 eDebug("[SEC] setVoltage %d", voltage);
1082                                 setVoltage(voltage);
1083                                 break;
1084                         }
1085                         case eSecCommand::IF_VOLTAGE_GOTO:
1086                         {
1087                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1088                                 if ( compare.voltage == m_curVoltage && setSecSequencePos(compare.steps) )
1089                                         break;
1090                                 ++m_sec_sequence.current();
1091                                 break;
1092                         }
1093                         case eSecCommand::IF_NOT_VOLTAGE_GOTO:
1094                         {
1095                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1096                                 if ( compare.voltage != m_curVoltage && setSecSequencePos(compare.steps) )
1097                                         break;
1098                                 ++m_sec_sequence.current();
1099                                 break;
1100                         }
1101                         case eSecCommand::SET_TONE:
1102                                 eDebug("[SEC] setTone %d", m_sec_sequence.current()->tone);
1103                                 setTone(m_sec_sequence.current()++->tone);
1104                                 break;
1105                         case eSecCommand::SEND_DISEQC:
1106                                 sendDiseqc(m_sec_sequence.current()->diseqc);
1107                                 eDebugNoNewLine("[SEC] sendDiseqc: ");
1108                                 for (int i=0; i < m_sec_sequence.current()->diseqc.len; ++i)
1109                                     eDebugNoNewLine("%02x", m_sec_sequence.current()->diseqc.data[i]);
1110                                 eDebug("");
1111                                 ++m_sec_sequence.current();
1112                                 break;
1113                         case eSecCommand::SEND_TONEBURST:
1114                                 eDebug("[SEC] sendToneburst: %d", m_sec_sequence.current()->toneburst);
1115                                 sendToneburst(m_sec_sequence.current()++->toneburst);
1116                                 break;
1117                         case eSecCommand::SET_FRONTEND:
1118                                 eDebug("[SEC] setFrontend");
1119                                 setFrontend();
1120                                 ++m_sec_sequence.current();
1121                                 break;
1122                         case eSecCommand::START_TUNE_TIMEOUT:
1123                                 m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
1124                                 ++m_sec_sequence.current();
1125                                 break;
1126                         case eSecCommand::SET_TIMEOUT:
1127                                 m_timeoutCount = m_sec_sequence.current()++->val;
1128                                 eDebug("[SEC] set timeout %d", m_timeoutCount);
1129                                 break;
1130                         case eSecCommand::IF_TIMEOUT_GOTO:
1131                                 if (!m_timeoutCount)
1132                                 {
1133                                         eDebug("[SEC] rotor timout");
1134                                         m_sec->setRotorMoving(false);
1135                                         setSecSequencePos(m_sec_sequence.current()->steps);
1136                                 }
1137                                 else
1138                                         ++m_sec_sequence.current();
1139                                 break;
1140                         case eSecCommand::MEASURE_IDLE_INPUTPOWER:
1141                         {
1142                                 int idx = m_sec_sequence.current()++->val;
1143                                 if ( idx == 0 || idx == 1 )
1144                                 {
1145                                         m_idleInputpower[idx] = readInputpower();
1146                                         eDebug("[SEC] idleInputpower[%d] is %d", idx, m_idleInputpower[idx]);
1147                                 }
1148                                 else
1149                                         eDebug("[SEC] idleInputpower measure index(%d) out of bound !!!", idx);
1150                                 break;
1151                         }
1152                         case eSecCommand::IF_MEASURE_IDLE_WAS_NOT_OK_GOTO:
1153                         {
1154                                 eSecCommand::pair &compare = m_sec_sequence.current()->compare;
1155                                 int idx = compare.voltage;
1156                                 if ( idx == 0 || idx == 1 )
1157                                 {
1158                                         int idle = readInputpower();
1159                                         int diff = abs(idle-m_idleInputpower[idx]);
1160                                         if ( diff > 0)
1161                                         {
1162                                                 eDebug("measure idle(%d) was not okay.. (%d - %d = %d) retry", idx, m_idleInputpower[idx], idle, diff);
1163                                                 setSecSequencePos(compare.steps);
1164                                                 break;
1165                                         }
1166                                 }
1167                                 ++m_sec_sequence.current();
1168                                 break;
1169                         }
1170                         case eSecCommand::IF_TUNER_LOCKED_GOTO:
1171                         {
1172                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1173                                 if (readFrontendData(Locked))
1174                                 {
1175                                         eDebug("[SEC] locked step %d ok", cmd.okcount);
1176                                         ++cmd.okcount;
1177                                         if (cmd.okcount > 12)
1178                                         {
1179                                                 eDebug("ok > 12 .. goto %d\n",m_sec_sequence.current()->steps);
1180                                                 setSecSequencePos(cmd.steps);
1181                                                 break;
1182                                         }
1183                                 }
1184                                 else
1185                                 {
1186                                         eDebug("[SEC] rotor locked step %d failed", cmd.okcount);
1187                                         --m_timeoutCount;
1188                                         if (!m_timeoutCount && m_retryCount > 0)
1189                                                 --m_retryCount;
1190                                         cmd.okcount=0;
1191                                 }
1192                                 ++m_sec_sequence.current();
1193                                 break;
1194                         }
1195                         case eSecCommand::MEASURE_RUNNING_INPUTPOWER:
1196                                 m_runningInputpower = readInputpower();
1197                                 eDebug("[SEC] runningInputpower is %d", m_runningInputpower);
1198                                 ++m_sec_sequence.current();
1199                                 break;
1200                         case eSecCommand::IF_INPUTPOWER_DELTA_GOTO:
1201                         {
1202                                 int idleInputpower = m_idleInputpower[ (m_curVoltage&1) ? 0 : 1];
1203                                 eSecCommand::rotor &cmd = m_sec_sequence.current()->measure;
1204                                 const char *txt = cmd.direction ? "running" : "stopped";
1205                                 eDebug("[SEC] waiting for rotor %s %d, idle %d, delta %d",
1206                                         txt,
1207                                         m_runningInputpower,
1208                                         idleInputpower,
1209                                         cmd.deltaA);
1210                                 if ( (cmd.direction && abs(m_runningInputpower - idleInputpower) >= cmd.deltaA)
1211                                         || (!cmd.direction && abs(m_runningInputpower - idleInputpower) <= cmd.deltaA) )
1212                                 {
1213                                         ++cmd.okcount;
1214                                         eDebug("[SEC] rotor %s step %d ok", txt, cmd.okcount);
1215                                         if ( cmd.okcount > 6 )
1216                                         {
1217                                                 m_sec->setRotorMoving(cmd.direction);
1218                                                 eDebug("[SEC] rotor is %s", txt);
1219                                                 if (setSecSequencePos(cmd.steps))
1220                                                         break;
1221                                         }
1222                                 }
1223                                 else
1224                                 {
1225                                         eDebug("[SEC] rotor not %s... reset counter.. increase timeout", txt);
1226                                         --m_timeoutCount;
1227                                         if (!m_timeoutCount && m_retryCount > 0)
1228                                                 --m_retryCount;
1229                                         cmd.okcount=0;
1230                                 }
1231                                 ++m_sec_sequence.current();
1232                                 break;
1233                         }
1234                         case eSecCommand::IF_ROTORPOS_VALID_GOTO:
1235                                 if (m_data[5] != -1 && m_data[6] != -1)
1236                                         setSecSequencePos(m_sec_sequence.current()->steps);
1237                                 else
1238                                         ++m_sec_sequence.current();
1239                                 break;
1240                         case eSecCommand::INVALIDATE_CURRENT_ROTORPARMS:
1241                                 m_data[5] = m_data[6] = -1;
1242                                 eDebug("[SEC] invalidate current rotorparams");
1243                                 ++m_sec_sequence.current();
1244                                 break;
1245                         case eSecCommand::UPDATE_CURRENT_ROTORPARAMS:
1246                                 m_data[5] = m_data[3];
1247                                 m_data[6] = m_data[4];
1248                                 eDebug("[SEC] update current rotorparams %d %04x %d", m_timeoutCount, m_data[5], m_data[6]);
1249                                 ++m_sec_sequence.current();
1250                                 break;
1251                         case eSecCommand::SET_ROTOR_DISEQC_RETRYS:
1252                                 m_retryCount = m_sec_sequence.current()++->val;
1253                                 eDebug("[SEC] set rotor retries %d", m_retryCount);
1254                                 break;
1255                         case eSecCommand::IF_NO_MORE_ROTOR_DISEQC_RETRYS_GOTO:
1256                                 if (!m_retryCount)
1257                                 {
1258                                         eDebug("[SEC] no more rotor retrys");
1259                                         setSecSequencePos(m_sec_sequence.current()->steps);
1260                                 }
1261                                 else
1262                                         ++m_sec_sequence.current();
1263                                 break;
1264                         case eSecCommand::SET_POWER_LIMITING_MODE:
1265                         {
1266                                 int fd = m_fe ?
1267                                         ::open("/dev/i2c/1", O_RDWR) :
1268                                         ::open("/dev/i2c/0", O_RDWR);
1269
1270                                 unsigned char data[2];
1271                                 ::ioctl(fd, I2C_SLAVE_FORCE, 0x10 >> 1);
1272                                 if(::read(fd, data, 1) != 1)
1273                                         eDebug("[SEC] error read lnbp (%m)");
1274                                 if ( m_sec_sequence.current()->mode == eSecCommand::modeStatic )
1275                                 {
1276                                         data[0] |= 0x80;  // enable static current limiting
1277                                         eDebug("[SEC] set static current limiting");
1278                                 }
1279                                 else
1280                                 {
1281                                         data[0] &= ~0x80;  // enable dynamic current limiting
1282                                         eDebug("[SEC] set dynamic current limiting");
1283                                 }
1284                                 if(::write(fd, data, 1) != 1)
1285                                         eDebug("[SEC] error write lnbp (%m)");
1286                                 ::close(fd);
1287                                 ++m_sec_sequence.current();
1288                                 break;
1289                         }
1290                         default:
1291                                 ++m_sec_sequence.current();
1292                                 eDebug("[SEC] unhandled sec command");
1293                 }
1294                 m_tuneTimer->start(delay,true);
1295         }
1296 }
1297
1298 void eDVBFrontend::setFrontend()
1299 {
1300         eDebug("setting frontend %d", m_fe);
1301         m_sn->start();
1302         feEvent(-1);
1303         if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
1304         {
1305                 perror("FE_SET_FRONTEND failed");
1306                 return;
1307         }
1308 }
1309
1310 RESULT eDVBFrontend::getFrontendType(int &t)
1311 {
1312         if (m_type == -1)
1313                 return -ENODEV;
1314         t = m_type;
1315         return 0;
1316 }
1317
1318 RESULT eDVBFrontend::prepare_sat(const eDVBFrontendParametersSatellite &feparm)
1319 {
1320         int res;
1321         if (!m_sec)
1322         {
1323                 eWarning("no SEC module active!");
1324                 return -ENOENT;
1325         }
1326         res = m_sec->prepare(*this, parm, feparm, 1 << m_fe);
1327         if (!res)
1328         {
1329                 parm_u_qpsk_symbol_rate = feparm.symbol_rate;
1330                 switch (feparm.inversion)
1331                 {
1332                         case eDVBFrontendParametersSatellite::Inversion::On:
1333                                 parm_inversion = INVERSION_ON;
1334                                 break;
1335                         case eDVBFrontendParametersSatellite::Inversion::Off:
1336                                 parm_inversion = INVERSION_OFF;
1337                                 break;
1338                         default:
1339                         case eDVBFrontendParametersSatellite::Inversion::Unknown:
1340                                 parm_inversion = INVERSION_AUTO;
1341                                 break;
1342                 }
1343                 if (feparm.system == eDVBFrontendParametersSatellite::System::DVB_S)
1344                         switch (feparm.fec)
1345                         {
1346                                 case eDVBFrontendParametersSatellite::FEC::fNone:
1347                                         parm_u_qpsk_fec_inner = FEC_NONE;
1348                                         break;
1349                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1350                                         parm_u_qpsk_fec_inner = FEC_1_2;
1351                                         break;
1352                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1353                                         parm_u_qpsk_fec_inner = FEC_2_3;
1354                                         break;
1355                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1356                                         parm_u_qpsk_fec_inner = FEC_3_4;
1357                                         break;
1358                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1359                                         parm_u_qpsk_fec_inner = FEC_5_6;
1360                                         break;
1361                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1362                                         parm_u_qpsk_fec_inner = FEC_7_8;
1363                                         break;
1364                                 default:
1365                                         eDebug("no valid fec for DVB-S set.. assume auto");
1366                                 case eDVBFrontendParametersSatellite::FEC::fAuto:
1367                                         parm_u_qpsk_fec_inner = FEC_AUTO;
1368                                         break;
1369                         }
1370 #if HAVE_DVB_API_VERSION >= 3
1371                 else // DVB_S2
1372                         switch (feparm.fec)
1373                         {
1374                                 case eDVBFrontendParametersSatellite::FEC::f1_2:
1375                                         parm_u_qpsk_fec_inner = FEC_S2_1_2;
1376                                         break;
1377                                 case eDVBFrontendParametersSatellite::FEC::f2_3:
1378                                         parm_u_qpsk_fec_inner = FEC_S2_2_3;
1379                                         break;
1380                                 case eDVBFrontendParametersSatellite::FEC::f3_4:
1381                                         parm_u_qpsk_fec_inner = FEC_S2_3_4;
1382                                         break;
1383                                 case eDVBFrontendParametersSatellite::FEC::f3_5:
1384                                         parm_u_qpsk_fec_inner = FEC_S2_3_5;
1385                                         break;
1386                                 case eDVBFrontendParametersSatellite::FEC::f4_5:
1387                                         parm_u_qpsk_fec_inner = FEC_S2_4_5;
1388                                         break;
1389                                 case eDVBFrontendParametersSatellite::FEC::f5_6:
1390                                         parm_u_qpsk_fec_inner = FEC_S2_5_6;
1391                                         break;
1392                                 case eDVBFrontendParametersSatellite::FEC::f7_8:
1393                                         parm_u_qpsk_fec_inner = FEC_S2_7_8;
1394                                         break;
1395                                 case eDVBFrontendParametersSatellite::FEC::f8_9:
1396                                         parm_u_qpsk_fec_inner = FEC_S2_8_9;
1397                                         break;
1398                                 case eDVBFrontendParametersSatellite::FEC::f9_10:
1399                                         parm_u_qpsk_fec_inner = FEC_S2_9_10;
1400                                         break;
1401                                 default:
1402                                         eDebug("no valid fec for DVB-S2 set.. abort !!");
1403                                         return -EINVAL;
1404                         }
1405 #endif
1406                 // FIXME !!! get frequency range from tuner
1407                 if ( parm_frequency < 900000 || parm_frequency > 2200000 )
1408                 {
1409                         eDebug("%d mhz out of tuner range.. dont tune", parm_frequency/1000);
1410                         return -EINVAL;
1411                 }
1412                 eDebug("tuning to %d mhz", parm_frequency/1000);
1413         }
1414         return res;
1415 }
1416
1417 RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm)
1418 {
1419         parm_frequency = feparm.frequency * 1000;
1420         parm_u_qam_symbol_rate = feparm.symbol_rate;
1421         switch (feparm.modulation)
1422         {
1423         case eDVBFrontendParametersCable::Modulation::QAM16:
1424                 parm_u_qam_modulation = QAM_16;
1425                 break;
1426         case eDVBFrontendParametersCable::Modulation::QAM32:
1427                 parm_u_qam_modulation = QAM_32;
1428                 break;
1429         case eDVBFrontendParametersCable::Modulation::QAM64:
1430                 parm_u_qam_modulation = QAM_64;
1431                 break;
1432         case eDVBFrontendParametersCable::Modulation::QAM128:
1433                 parm_u_qam_modulation = QAM_128;
1434                 break;
1435         case eDVBFrontendParametersCable::Modulation::QAM256:
1436                 parm_u_qam_modulation = QAM_256;
1437                 break;
1438         default:
1439         case eDVBFrontendParametersCable::Modulation::Auto:
1440                 parm_u_qam_modulation = QAM_AUTO;
1441                 break;
1442         }
1443         switch (feparm.inversion)
1444         {
1445         case eDVBFrontendParametersCable::Inversion::On:
1446                 parm_inversion = INVERSION_ON;
1447                 break;
1448         case eDVBFrontendParametersCable::Inversion::Off:
1449                 parm_inversion = INVERSION_OFF;
1450                 break;
1451         default:
1452         case eDVBFrontendParametersCable::Inversion::Unknown:
1453                 parm_inversion = INVERSION_AUTO;
1454                 break;
1455         }
1456         switch (feparm.fec_inner)
1457         {
1458         case eDVBFrontendParametersCable::FEC::fNone:
1459                 parm_u_qam_fec_inner = FEC_NONE;
1460                 break;
1461         case eDVBFrontendParametersCable::FEC::f1_2:
1462                 parm_u_qam_fec_inner = FEC_1_2;
1463                 break;
1464         case eDVBFrontendParametersCable::FEC::f2_3:
1465                 parm_u_qam_fec_inner = FEC_2_3;
1466                 break;
1467         case eDVBFrontendParametersCable::FEC::f3_4:
1468                 parm_u_qam_fec_inner = FEC_3_4;
1469                 break;
1470         case eDVBFrontendParametersCable::FEC::f5_6:
1471                 parm_u_qam_fec_inner = FEC_5_6;
1472                 break;
1473         case eDVBFrontendParametersCable::FEC::f7_8:
1474                 parm_u_qam_fec_inner = FEC_7_8;
1475                 break;
1476 #if HAVE_DVB_API_VERSION >= 3
1477         case eDVBFrontendParametersCable::FEC::f8_9:
1478                 parm_u_qam_fec_inner = FEC_8_9;
1479                 break;
1480 #endif
1481         default:
1482         case eDVBFrontendParametersCable::FEC::fAuto:
1483                 parm_u_qam_fec_inner = FEC_AUTO;
1484                 break;
1485         }
1486         return 0;
1487 }
1488
1489 RESULT eDVBFrontend::prepare_terrestrial(const eDVBFrontendParametersTerrestrial &feparm)
1490 {
1491         parm_frequency = feparm.frequency;
1492
1493         switch (feparm.bandwidth)
1494         {
1495         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz:
1496                 parm_u_ofdm_bandwidth = BANDWIDTH_8_MHZ;
1497                 break;
1498         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz:
1499                 parm_u_ofdm_bandwidth = BANDWIDTH_7_MHZ;
1500                 break;
1501         case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz:
1502                 parm_u_ofdm_bandwidth = BANDWIDTH_6_MHZ;
1503                 break;
1504         default:
1505         case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto:
1506                 parm_u_ofdm_bandwidth = BANDWIDTH_AUTO;
1507                 break;
1508         }
1509         switch (feparm.code_rate_LP)
1510         {
1511         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1512                 parm_u_ofdm_code_rate_LP = FEC_1_2;
1513                 break;
1514         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1515                 parm_u_ofdm_code_rate_LP = FEC_2_3;
1516                 break;
1517         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1518                 parm_u_ofdm_code_rate_LP = FEC_3_4;
1519                 break;
1520         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1521                 parm_u_ofdm_code_rate_LP = FEC_5_6;
1522                 break;
1523         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1524                 parm_u_ofdm_code_rate_LP = FEC_7_8;
1525                 break;
1526         default:
1527         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1528                 parm_u_ofdm_code_rate_LP = FEC_AUTO;
1529                 break;
1530         }
1531         switch (feparm.code_rate_HP)
1532         {
1533         case eDVBFrontendParametersTerrestrial::FEC::f1_2:
1534                 parm_u_ofdm_code_rate_HP = FEC_1_2;
1535                 break;
1536         case eDVBFrontendParametersTerrestrial::FEC::f2_3:
1537                 parm_u_ofdm_code_rate_HP = FEC_2_3;
1538                 break;
1539         case eDVBFrontendParametersTerrestrial::FEC::f3_4:
1540                 parm_u_ofdm_code_rate_HP = FEC_3_4;
1541                 break;
1542         case eDVBFrontendParametersTerrestrial::FEC::f5_6:
1543                 parm_u_ofdm_code_rate_HP = FEC_5_6;
1544                 break;
1545         case eDVBFrontendParametersTerrestrial::FEC::f7_8:
1546                 parm_u_ofdm_code_rate_HP = FEC_7_8;
1547                 break;
1548         default:
1549         case eDVBFrontendParametersTerrestrial::FEC::fAuto:
1550                 parm_u_ofdm_code_rate_HP = FEC_AUTO;
1551                 break;
1552         }
1553         switch (feparm.modulation)
1554         {
1555         case eDVBFrontendParametersTerrestrial::Modulation::QPSK:
1556                 parm_u_ofdm_constellation = QPSK;
1557                 break;
1558         case eDVBFrontendParametersTerrestrial::Modulation::QAM16:
1559                 parm_u_ofdm_constellation = QAM_16;
1560                 break;
1561         case eDVBFrontendParametersTerrestrial::Modulation::QAM64:
1562                 parm_u_ofdm_constellation = QAM_64;
1563                 break;
1564         default:
1565         case eDVBFrontendParametersTerrestrial::Modulation::Auto:
1566                 parm_u_ofdm_constellation = QAM_AUTO;
1567                 break;
1568         }
1569         switch (feparm.transmission_mode)
1570         {
1571         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k:
1572                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_2K;
1573                 break;
1574         case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k:
1575                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_8K;
1576                 break;
1577         default:
1578         case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto:
1579                 parm_u_ofdm_transmission_mode = TRANSMISSION_MODE_AUTO;
1580                 break;
1581         }
1582         switch (feparm.guard_interval)
1583         {
1584                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32:
1585                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_32;
1586                         break;
1587                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16:
1588                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_16;
1589                         break;
1590                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8:
1591                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_8;
1592                         break;
1593                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4:
1594                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_1_4;
1595                         break;
1596                 default:
1597                 case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto:
1598                         parm_u_ofdm_guard_interval = GUARD_INTERVAL_AUTO;
1599                         break;
1600         }
1601         switch (feparm.hierarchy)
1602         {
1603                 case eDVBFrontendParametersTerrestrial::Hierarchy::HNone:
1604                         parm_u_ofdm_hierarchy_information = HIERARCHY_NONE;
1605                         break;
1606                 case eDVBFrontendParametersTerrestrial::Hierarchy::H1:
1607                         parm_u_ofdm_hierarchy_information = HIERARCHY_1;
1608                         break;
1609                 case eDVBFrontendParametersTerrestrial::Hierarchy::H2:
1610                         parm_u_ofdm_hierarchy_information = HIERARCHY_2;
1611                         break;
1612                 case eDVBFrontendParametersTerrestrial::Hierarchy::H4:
1613                         parm_u_ofdm_hierarchy_information = HIERARCHY_4;
1614                         break;
1615                 default:
1616                 case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto:
1617                         parm_u_ofdm_hierarchy_information = HIERARCHY_AUTO;
1618                         break;
1619         }
1620         switch (feparm.inversion)
1621         {
1622         case eDVBFrontendParametersTerrestrial::Inversion::On:
1623                 parm_inversion = INVERSION_ON;
1624                 break;
1625         case eDVBFrontendParametersTerrestrial::Inversion::Off:
1626                 parm_inversion = INVERSION_OFF;
1627                 break;
1628         default:
1629         case eDVBFrontendParametersTerrestrial::Inversion::Unknown:
1630                 parm_inversion = INVERSION_AUTO;
1631                 break;
1632         }
1633         return 0;
1634 }
1635
1636 RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
1637 {
1638         eDebug("(%d)tune", m_fe);
1639
1640         m_timeout->stop();
1641
1642         int res=0;
1643
1644         if (m_type == -1)
1645                 return -ENODEV;
1646
1647         m_sn->stop();
1648         m_sec_sequence.clear();
1649
1650         switch (m_type)
1651         {
1652         case feSatellite:
1653         {
1654                 eDVBFrontendParametersSatellite feparm;
1655                 if (where.getDVBS(feparm))
1656                 {
1657                         eDebug("no dvbs data!");
1658                         return -EINVAL;
1659                 }
1660                 res=prepare_sat(feparm);
1661                 m_sec->setRotorMoving(false);
1662                 break;
1663         }
1664         case feCable:
1665         {
1666                 eDVBFrontendParametersCable feparm;
1667                 if (where.getDVBC(feparm))
1668                         return -EINVAL;
1669                 res=prepare_cable(feparm);
1670                 if (!res)
1671                 {
1672                         m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT) );
1673                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
1674                 }
1675                 break;
1676         }
1677         case feTerrestrial:
1678         {
1679                 eDVBFrontendParametersTerrestrial feparm;
1680                 if (where.getDVBT(feparm))
1681                 {
1682                         eDebug("no -T data");
1683                         return -EINVAL;
1684                 }
1685                 res=prepare_terrestrial(feparm);
1686                 if (!res)
1687                 {
1688                         m_sec_sequence.push_back( eSecCommand(eSecCommand::START_TUNE_TIMEOUT) );
1689                         m_sec_sequence.push_back( eSecCommand(eSecCommand::SET_FRONTEND) );
1690                 }
1691                 break;
1692         }
1693         }
1694
1695         if (!res)  // prepare ok
1696         {
1697                 m_tuneTimer->start(0,true);
1698                 m_sec_sequence.current() = m_sec_sequence.begin();
1699
1700                 if (m_state != stateTuning)
1701                 {
1702                         m_tuning = 1;
1703                         m_state = stateTuning;
1704                         m_stateChanged(this);
1705                 }
1706         }
1707
1708         return res;
1709 }
1710
1711 RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
1712 {
1713         connection = new eConnection(this, m_stateChanged.connect(stateChange));
1714         return 0;
1715 }
1716
1717 RESULT eDVBFrontend::setVoltage(int voltage)
1718 {
1719         if (m_type != feSatellite)
1720                 return -1;
1721 #if HAVE_DVB_API_VERSION < 3
1722         secVoltage vlt;
1723 #else
1724         bool increased=false;
1725         fe_sec_voltage_t vlt;
1726 #endif
1727         m_curVoltage=voltage;
1728         switch (voltage)
1729         {
1730         case voltageOff:
1731                 for (int i=0; i < 3; ++i)  // reset diseqc
1732                         m_data[i]=-1;
1733                 vlt = SEC_VOLTAGE_OFF;
1734                 break;
1735         case voltage13_5:
1736 #if HAVE_DVB_API_VERSION < 3
1737                 vlt = SEC_VOLTAGE_13_5;
1738                 break;
1739 #else
1740                 increased = true;
1741 #endif
1742         case voltage13:
1743                 vlt = SEC_VOLTAGE_13;
1744                 break;
1745         case voltage18_5:
1746 #if HAVE_DVB_API_VERSION < 3
1747                 vlt = SEC_VOLTAGE_18_5;
1748                 break;
1749 #else
1750                 increased = true;
1751 #endif
1752         case voltage18:
1753                 vlt = SEC_VOLTAGE_18;
1754                 break;
1755         default:
1756                 return -ENODEV;
1757         }
1758 #if HAVE_DVB_API_VERSION < 3
1759         return ::ioctl(m_secfd, SEC_SET_VOLTAGE, vlt);
1760 #else
1761         if (::ioctl(m_fd, FE_ENABLE_HIGH_LNB_VOLTAGE, increased) < 0)
1762                 perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1763         return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
1764 #endif
1765 }
1766
1767 RESULT eDVBFrontend::getState(int &state)
1768 {
1769         state = m_state;
1770         return 0;
1771 }
1772
1773 RESULT eDVBFrontend::setTone(int t)
1774 {
1775         if (m_type != feSatellite)
1776                 return -1;
1777 #if HAVE_DVB_API_VERSION < 3
1778         secToneMode_t tone;
1779 #else
1780         fe_sec_tone_mode_t tone;
1781 #endif
1782
1783         switch (t)
1784         {
1785         case toneOn:
1786                 tone = SEC_TONE_ON;
1787                 break;
1788         case toneOff:
1789                 tone = SEC_TONE_OFF;
1790                 break;
1791         default:
1792                 return -ENODEV;
1793         }
1794 #if HAVE_DVB_API_VERSION < 3    
1795         return ::ioctl(m_secfd, SEC_SET_TONE, tone);
1796 #else   
1797         return ::ioctl(m_fd, FE_SET_TONE, tone);
1798 #endif
1799 }
1800
1801 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_MASTER_CMD)
1802         #define SEC_DISEQC_SEND_MASTER_CMD _IOW('o', 97, struct secCommand *)
1803 #endif
1804
1805 RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
1806 {
1807 #if HAVE_DVB_API_VERSION < 3
1808         struct secCommand cmd;
1809         cmd.type = SEC_CMDTYPE_DISEQC_RAW;
1810         cmd.u.diseqc.cmdtype = diseqc.data[0];
1811         cmd.u.diseqc.addr = diseqc.data[1];
1812         cmd.u.diseqc.cmd = diseqc.data[2];
1813         cmd.u.diseqc.numParams = diseqc.len-3;
1814         memcpy(cmd.u.diseqc.params, diseqc.data+3, diseqc.len-3);
1815         if (::ioctl(m_secfd, SEC_DISEQC_SEND_MASTER_CMD, &cmd))
1816 #else
1817         struct dvb_diseqc_master_cmd cmd;
1818         memcpy(cmd.msg, diseqc.data, diseqc.len);
1819         cmd.msg_len = diseqc.len;
1820         if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
1821 #endif
1822                 return -EINVAL;
1823         return 0;
1824 }
1825
1826 #if HAVE_DVB_API_VERSION < 3 && !defined(SEC_DISEQC_SEND_BURST)
1827         #define SEC_DISEQC_SEND_BURST _IO('o', 96)
1828 #endif
1829 RESULT eDVBFrontend::sendToneburst(int burst)
1830 {
1831 #if HAVE_DVB_API_VERSION < 3
1832         secMiniCmd cmd = SEC_MINI_NONE;
1833 #else
1834         fe_sec_mini_cmd_t cmd = SEC_MINI_A;
1835 #endif
1836         if ( burst == eDVBSatelliteDiseqcParameters::A )
1837                 cmd = SEC_MINI_A;
1838         else if ( burst == eDVBSatelliteDiseqcParameters::B )
1839                 cmd = SEC_MINI_B;
1840 #if HAVE_DVB_API_VERSION < 3
1841         if (::ioctl(m_secfd, SEC_DISEQC_SEND_BURST, cmd))
1842                 return -EINVAL;
1843 #else
1844         if (::ioctl(m_fd, FE_DISEQC_SEND_BURST, cmd))
1845                 return -EINVAL;
1846 #endif
1847         return 0;
1848 }
1849
1850 RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
1851 {
1852         m_sec = sec;
1853         return 0;
1854 }
1855
1856 RESULT eDVBFrontend::setSecSequence(const eSecCommandList &list)
1857 {
1858         m_sec_sequence = list;
1859         return 0;
1860 }
1861
1862 RESULT eDVBFrontend::getData(int num, int &data)
1863 {
1864         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1865         {
1866                 data = m_data[num];
1867                 return 0;
1868         }
1869         return -EINVAL;
1870 }
1871
1872 RESULT eDVBFrontend::setData(int num, int val)
1873 {
1874         if ( num < (int)(sizeof(m_data)/sizeof(int)) )
1875         {
1876                 m_data[num] = val;
1877                 return 0;
1878         }
1879         return -EINVAL;
1880 }
1881
1882 int eDVBFrontend::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm)
1883 {
1884         int type;
1885         if (feparm->getSystem(type) || type != m_type)
1886                 return 0;
1887
1888         if (m_type == eDVBFrontend::feSatellite)
1889         {
1890                 ASSERT(m_sec);
1891                 eDVBFrontendParametersSatellite sat_parm;
1892                 ASSERT(!feparm->getDVBS(sat_parm));
1893                 return m_sec->canTune(sat_parm, this, 1 << m_fe);
1894         }
1895         return 1;
1896 }