Bug Summary

File:dvbdevice.c
Location:line 234, column 16
Description:Value stored to 'q' is never read

Annotated Source Code

1/*
2 * dvbdevice.c: The DVB device tuner interface
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: dvbdevice.c 3.10 2014/01/20 11:46:26 kls Exp $
8 */
9
10#include "dvbdevice.h"
11#include <ctype.h>
12#include <errno(*__errno_location ()).h>
13#include <limits.h>
14#include <linux1/dvb/dmx.h>
15#include <linux1/dvb/frontend.h>
16#include <sys/ioctl.h>
17#include <sys/mman.h>
18#include "channels.h"
19#include "diseqc.h"
20#include "dvbci.h"
21#include "menuitems.h"
22#include "sourceparams.h"
23
24static int DvbApiVersion = 0x0000; // the version of the DVB driver actually in use (will be determined by the first device created)
25
26#define DVBS_TUNE_TIMEOUT9000 9000 //ms
27#define DVBS_LOCK_TIMEOUT2000 2000 //ms
28#define DVBC_TUNE_TIMEOUT9000 9000 //ms
29#define DVBC_LOCK_TIMEOUT2000 2000 //ms
30#define DVBT_TUNE_TIMEOUT9000 9000 //ms
31#define DVBT_LOCK_TIMEOUT2000 2000 //ms
32#define ATSC_TUNE_TIMEOUT9000 9000 //ms
33#define ATSC_LOCK_TIMEOUT2000 2000 //ms
34
35#define SCR_RANDOM_TIMEOUT500 500 // ms (add random value up to this when tuning SCR device to avoid lockups)
36
37// --- DVB Parameter Maps ----------------------------------------------------
38
39const tDvbParameterMap InversionValues[] = {
40 { 0, INVERSION_OFF, trNOOP("off")("off") },
41 { 1, INVERSION_ON, trNOOP("on")("on") },
42 { 999, INVERSION_AUTO, trNOOP("auto")("auto") },
43 { -1, 0, NULL__null }
44 };
45
46const tDvbParameterMap BandwidthValues[] = {
47 { 5, 5000000, "5 MHz" },
48 { 6, 6000000, "6 MHz" },
49 { 7, 7000000, "7 MHz" },
50 { 8, 8000000, "8 MHz" },
51 { 10, 10000000, "10 MHz" },
52 { 1712, 1712000, "1.712 MHz" },
53 { -1, 0, NULL__null }
54 };
55
56const tDvbParameterMap CoderateValues[] = {
57 { 0, FEC_NONE, trNOOP("none")("none") },
58 { 12, FEC_1_2, "1/2" },
59 { 23, FEC_2_3, "2/3" },
60 { 34, FEC_3_4, "3/4" },
61 { 35, FEC_3_5, "3/5" },
62 { 45, FEC_4_5, "4/5" },
63 { 56, FEC_5_6, "5/6" },
64 { 67, FEC_6_7, "6/7" },
65 { 78, FEC_7_8, "7/8" },
66 { 89, FEC_8_9, "8/9" },
67 { 910, FEC_9_10, "9/10" },
68 { 999, FEC_AUTO, trNOOP("auto")("auto") },
69 { -1, 0, NULL__null }
70 };
71
72const tDvbParameterMap ModulationValues[] = {
73 { 16, QAM_16, "QAM16" },
74 { 32, QAM_32, "QAM32" },
75 { 64, QAM_64, "QAM64" },
76 { 128, QAM_128, "QAM128" },
77 { 256, QAM_256, "QAM256" },
78 { 2, QPSK, "QPSK" },
79 { 5, PSK_8, "8PSK" },
80 { 6, APSK_16, "16APSK" },
81 { 7, APSK_32, "32APSK" },
82 { 10, VSB_8, "VSB8" },
83 { 11, VSB_16, "VSB16" },
84 { 12, DQPSK, "DQPSK" },
85 { 999, QAM_AUTO, trNOOP("auto")("auto") },
86 { -1, 0, NULL__null }
87 };
88
89#define DVB_SYSTEM_10 0 // see also nit.c
90#define DVB_SYSTEM_21 1
91
92const tDvbParameterMap SystemValuesSat[] = {
93 { 0, DVB_SYSTEM_10, "DVB-S" },
94 { 1, DVB_SYSTEM_21, "DVB-S2" },
95 { -1, 0, NULL__null }
96 };
97
98const tDvbParameterMap SystemValuesTerr[] = {
99 { 0, DVB_SYSTEM_10, "DVB-T" },
100 { 1, DVB_SYSTEM_21, "DVB-T2" },
101 { -1, 0, NULL__null }
102 };
103
104const tDvbParameterMap TransmissionValues[] = {
105 { 1, TRANSMISSION_MODE_1K, "1K" },
106 { 2, TRANSMISSION_MODE_2K, "2K" },
107 { 4, TRANSMISSION_MODE_4K, "4K" },
108 { 8, TRANSMISSION_MODE_8K, "8K" },
109 { 16, TRANSMISSION_MODE_16K, "16K" },
110 { 32, TRANSMISSION_MODE_32K, "32K" },
111 { 999, TRANSMISSION_MODE_AUTO, trNOOP("auto")("auto") },
112 { -1, 0, NULL__null }
113 };
114
115const tDvbParameterMap GuardValues[] = {
116 { 4, GUARD_INTERVAL_1_4, "1/4" },
117 { 8, GUARD_INTERVAL_1_8, "1/8" },
118 { 16, GUARD_INTERVAL_1_16, "1/16" },
119 { 32, GUARD_INTERVAL_1_32, "1/32" },
120 { 128, GUARD_INTERVAL_1_128, "1/128" },
121 { 19128, GUARD_INTERVAL_19_128, "19/128" },
122 { 19256, GUARD_INTERVAL_19_256, "19/256" },
123 { 999, GUARD_INTERVAL_AUTO, trNOOP("auto")("auto") },
124 { -1, 0, NULL__null }
125 };
126
127const tDvbParameterMap HierarchyValues[] = {
128 { 0, HIERARCHY_NONE, trNOOP("none")("none") },
129 { 1, HIERARCHY_1, "1" },
130 { 2, HIERARCHY_2, "2" },
131 { 4, HIERARCHY_4, "4" },
132 { 999, HIERARCHY_AUTO, trNOOP("auto")("auto") },
133 { -1, 0, NULL__null }
134 };
135
136const tDvbParameterMap RollOffValues[] = {
137 { 0, ROLLOFF_AUTO, trNOOP("auto")("auto") },
138 { 20, ROLLOFF_20, "0.20" },
139 { 25, ROLLOFF_25, "0.25" },
140 { 35, ROLLOFF_35, "0.35" },
141 { -1, 0, NULL__null }
142 };
143
144int UserIndex(int Value, const tDvbParameterMap *Map)
145{
146 const tDvbParameterMap *map = Map;
147 while (map && map->userValue != -1) {
148 if (map->userValue == Value)
149 return map - Map;
150 map++;
151 }
152 return -1;
153}
154
155int DriverIndex(int Value, const tDvbParameterMap *Map)
156{
157 const tDvbParameterMap *map = Map;
158 while (map && map->userValue != -1) {
159 if (map->driverValue == Value)
160 return map - Map;
161 map++;
162 }
163 return -1;
164}
165
166int MapToUser(int Value, const tDvbParameterMap *Map, const char **String)
167{
168 int n = DriverIndex(Value, Map);
169 if (n >= 0) {
170 if (String)
171 *String = tr(Map[n].userString)I18nTranslate(Map[n].userString);
172 return Map[n].userValue;
173 }
174 return -1;
175}
176
177const char *MapToUserString(int Value, const tDvbParameterMap *Map)
178{
179 int n = DriverIndex(Value, Map);
180 if (n >= 0)
181 return Map[n].userString;
182 return "???";
183}
184
185int MapToDriver(int Value, const tDvbParameterMap *Map)
186{
187 int n = UserIndex(Value, Map);
188 if (n >= 0)
189 return Map[n].driverValue;
190 return -1;
191}
192
193// --- cDvbTransponderParameters ---------------------------------------------
194
195cDvbTransponderParameters::cDvbTransponderParameters(const char *Parameters)
196{
197 polarization = 0;
198 inversion = INVERSION_AUTO;
199 bandwidth = 8000000;
200 coderateH = FEC_AUTO;
201 coderateL = FEC_AUTO;
202 modulation = QPSK;
203 system = DVB_SYSTEM_10;
204 transmission = TRANSMISSION_MODE_AUTO;
205 guard = GUARD_INTERVAL_AUTO;
206 hierarchy = HIERARCHY_AUTO;
207 rollOff = ROLLOFF_AUTO;
208 streamId = 0;
209 Parse(Parameters);
210}
211
212int cDvbTransponderParameters::PrintParameter(char *p, char Name, int Value) const
213{
214 return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0;
215}
216
217cString cDvbTransponderParameters::ToString(char Type) const
218{
219#define ST(s)if (strchr(s, type)) if (strchr(s, Type) && (strchr(s, '0' + system + 1) || strchr(s, '*')))
220 char buffer[64];
221 char *q = buffer;
222 *q = 0;
223 ST(" S *")if (strchr(" S *", type)) q += sprintf(q, "%c", polarization);
224 ST(" T*")if (strchr(" T*", type)) q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues));
225 ST(" CST*")if (strchr(" CST*", type)) q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues));
226 ST(" T*")if (strchr(" T*", type)) q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues));
227 ST(" T*")if (strchr(" T*", type)) q += PrintParameter(q, 'G', MapToUser(guard, GuardValues));
228 ST("ACST*")if (strchr("ACST*", type)) q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues));
229 ST("ACST*")if (strchr("ACST*", type)) q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues));
230 ST(" S 2")if (strchr(" S 2", type)) q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues));
231 ST(" ST2")if (strchr(" ST2", type)) q += PrintParameter(q, 'P', streamId);
232 ST(" ST*")if (strchr(" ST*", type)) q += PrintParameter(q, 'S', MapToUser(system, SystemValuesSat)); // we only need the numerical value, so Sat or Terr doesn't matter
233 ST(" T*")if (strchr(" T*", type)) q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues));
234 ST(" T*")if (strchr(" T*", type)) q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues));
Value stored to 'q' is never read
235 return buffer;
236}
237
238const char *cDvbTransponderParameters::ParseParameter(const char *s, int &Value, const tDvbParameterMap *Map)
239{
240 if (*++s) {
241 char *p = NULL__null;
242 errno(*__errno_location ()) = 0;
243 int n = strtol(s, &p, 10);
244 if (!errno(*__errno_location ()) && p != s) {
245 Value = Map ? MapToDriver(n, Map) : n;
246 if (Value >= 0)
247 return p;
248 }
249 }
250 esyslog("ERROR: invalid value for parameter '%c'", *(s - 1))void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: invalid value for parameter '%c'"
, *(s - 1)) : void() )
;
251 return NULL__null;
252}
253
254bool cDvbTransponderParameters::Parse(const char *s)
255{
256 while (s && *s) {
257 switch (toupper(*s)) {
258 case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break;
259 case 'C': s = ParseParameter(s, coderateH, CoderateValues); break;
260 case 'D': s = ParseParameter(s, coderateL, CoderateValues); break;
261 case 'G': s = ParseParameter(s, guard, GuardValues); break;
262 case 'H': polarization = 'H'; s++; break;
263 case 'I': s = ParseParameter(s, inversion, InversionValues); break;
264 case 'L': polarization = 'L'; s++; break;
265 case 'M': s = ParseParameter(s, modulation, ModulationValues); break;
266 case 'O': s = ParseParameter(s, rollOff, RollOffValues); break;
267 case 'P': s = ParseParameter(s, streamId); break;
268 case 'R': polarization = 'R'; s++; break;
269 case 'S': s = ParseParameter(s, system, SystemValuesSat); break; // we only need the numerical value, so Sat or Terr doesn't matter
270 case 'T': s = ParseParameter(s, transmission, TransmissionValues); break;
271 case 'V': polarization = 'V'; s++; break;
272 case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break;
273 default: esyslog("ERROR: unknown parameter key '%c'", *s)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown parameter key '%c'"
, *s) : void() )
;
274 return false;
275 }
276 }
277 return true;
278}
279
280// --- cDvbTuner -------------------------------------------------------------
281
282#define TUNER_POLL_TIMEOUT10 10 // ms
283
284class cDvbTuner : public cThread {
285private:
286 static cMutex bondMutex;
287 enum eTunerStatus { tsIdle, tsSet, tsPositioning, tsTuned, tsLocked };
288 int frontendType;
289 const cDvbDevice *device;
290 int fd_frontend;
291 int adapter, frontend;
292 uint32_t subsystemId;
293 int tuneTimeout;
294 int lockTimeout;
295 time_t lastTimeoutReport;
296 cChannel channel;
297 const cDiseqc *lastDiseqc;
298 int diseqcOffset;
299 int lastSource;
300 cPositioner *positioner;
301 const cScr *scr;
302 bool lnbPowerTurnedOn;
303 eTunerStatus tunerStatus;
304 cMutex mutex;
305 cCondVar locked;
306 cCondVar newSet;
307 cDvbTuner *bondedTuner;
308 bool bondedMaster;
309 bool SetFrontendType(const cChannel *Channel);
310 cString GetBondingParams(const cChannel *Channel = NULL__null) const;
311 cDvbTuner *GetBondedMaster(void);
312 bool IsBondedMaster(void) const { return !bondedTuner || bondedMaster; }
313 void ClearEventQueue(void) const;
314 bool GetFrontendStatus(fe_status_t &Status) const;
315 cPositioner *GetPositioner(void);
316 void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency);
317 void ResetToneAndVoltage(void);
318 bool SetFrontend(void);
319 virtual void Action(void);
320public:
321 cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
322 virtual ~cDvbTuner();
323 int FrontendType(void) const { return frontendType; }
324 bool Bond(cDvbTuner *Tuner);
325 void UnBond(void);
326 bool BondingOk(const cChannel *Channel, bool ConsiderOccupied = false) const;
327 const cChannel *GetTransponder(void) const { return &channel; }
328 uint32_t SubsystemId(void) const { return subsystemId; }
329 bool IsTunedTo(const cChannel *Channel) const;
330 void SetChannel(const cChannel *Channel);
331 bool Locked(int TimeoutMs = 0);
332 const cPositioner *Positioner(void) const { return positioner; }
333 int GetSignalStrength(void) const;
334 int GetSignalQuality(void) const;
335 };
336
337cMutex cDvbTuner::bondMutex;
338
339cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
340{
341 frontendType = SYS_UNDEFINED;
342 device = Device;
343 fd_frontend = Fd_Frontend;
344 adapter = Adapter;
345 frontend = Frontend;
346 subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, frontend);
347 tuneTimeout = 0;
348 lockTimeout = 0;
349 lastTimeoutReport = 0;
350 lastDiseqc = NULL__null;
351 diseqcOffset = 0;
352 lastSource = 0;
353 positioner = NULL__null;
354 scr = NULL__null;
355 lnbPowerTurnedOn = false;
356 tunerStatus = tsIdle;
357 bondedTuner = NULL__null;
358 bondedMaster = false;
359 SetDescription("tuner on frontend %d/%d", adapter, frontend);
360 Start();
361}
362
363cDvbTuner::~cDvbTuner()
364{
365 tunerStatus = tsIdle;
366 newSet.Broadcast();
367 locked.Broadcast();
368 Cancel(3);
369 UnBond();
370 /* looks like this irritates the SCR switch, so let's leave it out for now
371 if (lastDiseqc && lastDiseqc->IsScr()) {
372 unsigned int Frequency = 0;
373 ExecuteDiseqc(lastDiseqc, &Frequency);
374 }
375 */
376}
377
378bool cDvbTuner::Bond(cDvbTuner *Tuner)
379{
380 cMutexLock MutexLock(&bondMutex);
381 if (!bondedTuner) {
382 ResetToneAndVoltage();
383 bondedMaster = false; // makes sure we don't disturb an existing master
384 bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner;
385 Tuner->bondedTuner = this;
386 dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend)void( (SysLogLevel > 2) ? syslog_with_tid(7, "tuner %d/%d bonded with tuner %d/%d"
, adapter, frontend, bondedTuner->adapter, bondedTuner->
frontend) : void() )
;
387 return true;
388 }
389 else
390 esyslog("ERROR: tuner %d/%d already bonded with tuner %d/%d, can't bond with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend, Tuner->adapter, Tuner->frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: tuner %d/%d already bonded with tuner %d/%d, can't bond with tuner %d/%d"
, adapter, frontend, bondedTuner->adapter, bondedTuner->
frontend, Tuner->adapter, Tuner->frontend) : void() )
;
391 return false;
392}
393
394void cDvbTuner::UnBond(void)
395{
396 cMutexLock MutexLock(&bondMutex);
397 if (cDvbTuner *t = bondedTuner) {
398 dsyslog("tuner %d/%d unbonded from tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend)void( (SysLogLevel > 2) ? syslog_with_tid(7, "tuner %d/%d unbonded from tuner %d/%d"
, adapter, frontend, bondedTuner->adapter, bondedTuner->
frontend) : void() )
;
399 while (t->bondedTuner != this)
400 t = t->bondedTuner;
401 if (t == bondedTuner)
402 t->bondedTuner = NULL__null;
403 else
404 t->bondedTuner = bondedTuner;
405 bondedMaster = false; // another one will automatically become master whenever necessary
406 bondedTuner = NULL__null;
407 }
408}
409
410cString cDvbTuner::GetBondingParams(const cChannel *Channel) const
411{
412 if (!Channel)
413 Channel = &channel;
414 cDvbTransponderParameters dtp(Channel->Parameters());
415 if (Setup.DiSEqC) {
416 if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL__null))
417 return diseqc->Commands();
418 }
419 else {
420 bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
421 bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
422 return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
423 }
424 return "";
425}
426
427bool cDvbTuner::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
428{
429 cMutexLock MutexLock(&bondMutex);
430 if (cDvbTuner *t = bondedTuner) {
431 cString BondingParams = GetBondingParams(Channel);
432 do {
433 if (t->device->Priority() > IDLEPRIORITY((-99) - 1) || ConsiderOccupied && t->device->Occupied()) {
434 if (strcmp(BondingParams, t->GetBondedMaster()->GetBondingParams()) != 0)
435 return false;
436 }
437 t = t->bondedTuner;
438 } while (t != bondedTuner);
439 }
440 return true;
441}
442
443cDvbTuner *cDvbTuner::GetBondedMaster(void)
444{
445 if (!bondedTuner)
446 return this; // an unbonded tuner is always "master"
447 cMutexLock MutexLock(&bondMutex);
448 if (bondedMaster)
449 return this;
450 // This tuner is bonded, but it's not the master, so let's see if there is a master at all:
451 if (cDvbTuner *t = bondedTuner) {
452 while (t != this) {
453 if (t->bondedMaster)
454 return t;
455 t = t->bondedTuner;
456 }
457 }
458 // None of the other bonded tuners is master, so make this one the master:
459 bondedMaster = true;
460 dsyslog("tuner %d/%d is now bonded master", adapter, frontend)void( (SysLogLevel > 2) ? syslog_with_tid(7, "tuner %d/%d is now bonded master"
, adapter, frontend) : void() )
;
461 return this;
462}
463
464bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
465{
466 if (tunerStatus == tsIdle)
467 return false; // not tuned to
468 if (channel.Source() != Channel->Source() || channel.Transponder() != Channel->Transponder())
469 return false; // sufficient mismatch
470 // Polarization is already checked as part of the Transponder.
471 return strcmp(channel.Parameters(), Channel->Parameters()) == 0;
472}
473
474void cDvbTuner::SetChannel(const cChannel *Channel)
475{
476 if (Channel) {
477 if (bondedTuner) {
478 cMutexLock MutexLock(&bondMutex);
479 cDvbTuner *BondedMaster = GetBondedMaster();
480 if (BondedMaster == this) {
481 if (strcmp(GetBondingParams(Channel), GetBondingParams()) != 0) {
482 // switching to a completely different band, so set all others to idle:
483 for (cDvbTuner *t = bondedTuner; t && t != this; t = t->bondedTuner)
484 t->SetChannel(NULL__null);
485 }
486 }
487 else if (strcmp(GetBondingParams(Channel), BondedMaster->GetBondingParams()) != 0)
488 BondedMaster->SetChannel(Channel);
489 }
490 cMutexLock MutexLock(&mutex);
491 if (!IsTunedTo(Channel))
492 tunerStatus = tsSet;
493 diseqcOffset = 0;
494 channel = *Channel;
495 lastTimeoutReport = 0;
496 newSet.Broadcast();
497 }
498 else {
499 cMutexLock MutexLock(&mutex);
500 tunerStatus = tsIdle;
501 ResetToneAndVoltage();
502 }
503 if (bondedTuner && device->IsPrimaryDevice())
504 cDevice::PrimaryDevice()->DelLivePids(); // 'device' is const, so we must do it this way
505}
506
507bool cDvbTuner::Locked(int TimeoutMs)
508{
509 bool isLocked = (tunerStatus >= tsLocked);
510 if (isLocked || !TimeoutMs)
511 return isLocked;
512
513 cMutexLock MutexLock(&mutex);
514 if (TimeoutMs && tunerStatus < tsLocked)
515 locked.TimedWait(mutex, TimeoutMs);
516 return tunerStatus >= tsLocked;
517}
518
519void cDvbTuner::ClearEventQueue(void) const
520{
521 cPoller Poller(fd_frontend);
522 if (Poller.Poll(TUNER_POLL_TIMEOUT10)) {
523 dvb_frontend_event Event;
524 while (ioctl(fd_frontend, FE_GET_EVENT(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((78)) << 0) | ((((sizeof(struct dvb_frontend_event))
)) << ((0 +8)+8)))
, &Event) == 0)
525 ; // just to clear the event queue - we'll read the actual status below
526 }
527}
528
529bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
530{
531 ClearEventQueue();
532 while (1) {
533 if (ioctl(fd_frontend, FE_READ_STATUS(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((69)) << 0) | ((((sizeof(fe_status_t)))) << ((
0 +8)+8)))
, &Status) != -1)
534 return true;
535 if (errno(*__errno_location ()) != EINTR4)
536 break;
537 }
538 return false;
539}
540
541//#define DEBUG_SIGNALSTRENGTH
542//#define DEBUG_SIGNALQUALITY
543
544int cDvbTuner::GetSignalStrength(void) const
545{
546 ClearEventQueue();
547 uint16_t Signal;
548 while (1) {
549 if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((71)) << 0) | ((((sizeof(__u16)))) << ((0 +8)+
8)))
, &Signal) != -1)
550 break;
551 if (errno(*__errno_location ()) != EINTR4)
552 return -1;
553 }
554 uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
555 // Use the subsystemId to identify individual devices in case they need
556 // special treatment to map their Signal value into the range 0...0xFFFF.
557 switch (subsystemId) {
558 case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
559 case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
560 MaxSignal = 670; break;
561 }
562 int s = int(Signal) * 100 / MaxSignal;
563 if (s > 100)
564 s = 100;
565#ifdef DEBUG_SIGNALSTRENGTH
566 fprintf(stderrstderr, "FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
567#endif
568 return s;
569}
570
571#define LOCK_THRESHOLD5 5 // indicates that all 5 FE_HAS_* flags are set
572
573int cDvbTuner::GetSignalQuality(void) const
574{
575 fe_status_t Status;
576 if (GetFrontendStatus(Status)) {
577 // Actually one would expect these checks to be done from FE_HAS_SIGNAL to FE_HAS_LOCK, but some drivers (like the stb0899) are broken, so FE_HAS_LOCK is the only one that (hopefully) is generally reliable...
578 if ((Status & FE_HAS_LOCK) == 0) {
579 if ((Status & FE_HAS_SIGNAL) == 0)
580 return 0;
581 if ((Status & FE_HAS_CARRIER) == 0)
582 return 1;
583 if ((Status & FE_HAS_VITERBI) == 0)
584 return 2;
585 if ((Status & FE_HAS_SYNC) == 0)
586 return 3;
587 return 4;
588 }
589#ifdef DEBUG_SIGNALQUALITY
590 bool HasSnr = true;
591#endif
592 uint16_t Snr;
593 while (1) {
594 if (ioctl(fd_frontend, FE_READ_SNR(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((72)) << 0) | ((((sizeof(__u16)))) << ((0 +8)+
8)))
, &Snr) != -1)
595 break;
596 if (errno(*__errno_location ()) != EINTR4) {
597 Snr = 0xFFFF;
598#ifdef DEBUG_SIGNALQUALITY
599 HasSnr = false;
600#endif
601 break;
602 }
603 }
604#ifdef DEBUG_SIGNALQUALITY
605 bool HasBer = true;
606#endif
607 uint32_t Ber;
608 while (1) {
609 if (ioctl(fd_frontend, FE_READ_BER(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((70)) << 0) | ((((sizeof(__u32)))) << ((0 +8)+
8)))
, &Ber) != -1)
610 break;
611 if (errno(*__errno_location ()) != EINTR4) {
612 Ber = 0;
613#ifdef DEBUG_SIGNALQUALITY
614 HasBer = false;
615#endif
616 break;
617 }
618 }
619#ifdef DEBUG_SIGNALQUALITY
620 bool HasUnc = true;
621#endif
622 uint32_t Unc;
623 while (1) {
624 if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((73)) << 0) | ((((sizeof(__u32)))) << ((0 +8)+
8)))
, &Unc) != -1)
625 break;
626 if (errno(*__errno_location ()) != EINTR4) {
627 Unc = 0;
628#ifdef DEBUG_SIGNALQUALITY
629 HasUnc = false;
630#endif
631 break;
632 }
633 }
634 uint16_t MinSnr = 0x0000;
635 uint16_t MaxSnr = 0xFFFF; // Let's assume the default is using the entire range.
636 // Use the subsystemId to identify individual devices in case they need
637 // special treatment to map their Snr value into the range 0...0xFFFF.
638 switch (subsystemId) {
639 case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
640 case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
641 if (frontendType == SYS_DVBS2) {
642 MinSnr = 10;
643 MaxSnr = 70;
644 }
645 else
646 MaxSnr = 200;
647 break;
648 case 0x20130245: // PCTV Systems PCTV 73ESE
649 case 0x2013024F: // PCTV Systems nanoStick T2 290e
650 MaxSnr = 255; break;
651 }
652 int a = int(constrain(Snr, MinSnr, MaxSnr)) * 100 / (MaxSnr - MinSnr);
653 int b = 100 - (Unc * 10 + (Ber / 256) * 5);
654 if (b < 0)
655 b = 0;
656 int q = LOCK_THRESHOLD5 + a * b * (100 - LOCK_THRESHOLD5) / 100 / 100;
657 if (q > 100)
658 q = 100;
659#ifdef DEBUG_SIGNALQUALITY
660 fprintf(stderrstderr, "FE %d/%d: %08X Q = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSnr, Snr, HasSnr, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, q);
661#endif
662 return q;
663 }
664 return -1;
665}
666
667static unsigned int FrequencyToHz(unsigned int f)
668{
669 while (f && f < 1000000)
670 f *= 1000;
671 return f;
672}
673
674cPositioner *cDvbTuner::GetPositioner(void)
675{
676 if (!positioner) {
677 positioner = cPositioner::GetPositioner();
678 positioner->SetFrontend(fd_frontend);
679 }
680 return positioner;
681}
682
683void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
684{
685 if (!lnbPowerTurnedOn) {
686 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((67)) << 0) | ((0) <<
((0 +8)+8))), SEC_VOLTAGE_13)) < 0) void( (SysLogLevel >
0) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 686
) : void() ); }
; // must explicitly turn on LNB power
687 lnbPowerTurnedOn = true;
688 }
689 static cMutex Mutex;
690 if (Diseqc->IsScr())
691 Mutex.Lock();
692 struct dvb_diseqc_master_cmd cmd;
693 const char *CurrentAction = NULL__null;
694 cPositioner *Positioner = NULL__null;
695 bool Break = false;
696 for (int i = 0; !Break; i++) {
697 cmd.msg_len = sizeof(cmd.msg);
698 cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency);
699 if (da == cDiseqc::daNone) {
700 diseqcOffset = 0;
701 break;
702 }
703 bool d = i >= diseqcOffset;
704 switch (da) {
705 case cDiseqc::daToneOff: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((66)) << 0) | ((0) <<
((0 +8)+8))), SEC_TONE_OFF)) < 0) void( (SysLogLevel >
0) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 705
) : void() ); }
; break;
706 case cDiseqc::daToneOn: if (d) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((66)) << 0) | ((0) <<
((0 +8)+8))), SEC_TONE_ON)) < 0) void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 706
) : void() ); }
; break;
707 case cDiseqc::daVoltage13: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((67)) << 0) | ((0) <<
((0 +8)+8))), SEC_VOLTAGE_13)) < 0) void( (SysLogLevel >
0) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 707
) : void() ); }
; break;
708 case cDiseqc::daVoltage18: if (d) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((67)) << 0) | ((0) <<
((0 +8)+8))), SEC_VOLTAGE_18)) < 0) void( (SysLogLevel >
0) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 708
) : void() ); }
; break;
709 case cDiseqc::daMiniA: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((65)) << 0) | ((0) <<
((0 +8)+8))), SEC_MINI_A)) < 0) void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 709
) : void() ); }
; break;
710 case cDiseqc::daMiniB: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((65)) << 0) | ((0) <<
((0 +8)+8))), SEC_MINI_B)) < 0) void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 710
) : void() ); }
; break;
711 case cDiseqc::daCodes: if (d) CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)){ if ((ioctl(fd_frontend, (((1U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((63)) << 0) | ((((sizeof(struct
dvb_diseqc_master_cmd)))) << ((0 +8)+8))), &cmd)) <
0) void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 711) : void() ); }
; break;
712 case cDiseqc::daPositionN: if ((Positioner = GetPositioner()) != NULL__null) {
713 if (d) {
714 Positioner->GotoPosition(Diseqc->Position(), cSource::Position(channel.Source()));
715 Break = Positioner->IsMoving();
716 }
717 }
718 break;
719 case cDiseqc::daPositionA: if ((Positioner = GetPositioner()) != NULL__null) {
720 if (d) {
721 Positioner->GotoAngle(cSource::Position(channel.Source()));
722 Break = Positioner->IsMoving();
723 }
724 }
725 break;
726 case cDiseqc::daScr:
727 case cDiseqc::daWait: break;
728 default: esyslog("ERROR: unknown diseqc command %d", da)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown diseqc command %d"
, da) : void() )
;
729 }
730 if (Break)
731 diseqcOffset = i + 1;
732 }
733 positioner = Positioner;
734 if (scr && !Break)
735 ResetToneAndVoltage(); // makes sure we don't block the bus!
736 if (Diseqc->IsScr())
737 Mutex.Unlock();
738}
739
740void cDvbTuner::ResetToneAndVoltage(void)
741{
742 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((67)) << 0) | ((0) <<
((0 +8)+8))), bondedTuner ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_13
)) < 0) void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 742) : void() ); }
;
743 CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((66)) << 0) | ((0) <<
((0 +8)+8))), SEC_TONE_OFF)) < 0) void( (SysLogLevel >
0) ? syslog_with_tid(3, "ERROR (%s,%d): %m", "dvbdevice.c", 743
) : void() ); }
;
744}
745
746static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp)
747{
748 int ds = SYS_UNDEFINED;
749 if (Channel->IsAtsc())
750 ds = SYS_ATSC;
751 else if (Channel->IsCable())
752 ds = SYS_DVBC_ANNEX_ACSYS_DVBC_ANNEX_A;
753 else if (Channel->IsSat())
754 ds = Dtp->System() == DVB_SYSTEM_10 ? SYS_DVBS : SYS_DVBS2;
755 else if (Channel->IsTerr())
756 ds = Dtp->System() == DVB_SYSTEM_10 ? SYS_DVBT : SYS_DVBT2;
757 else
758 esyslog("ERROR: can't determine frontend type for channel %d", Channel->Number())void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't determine frontend type for channel %d"
, Channel->Number()) : void() )
;
759 return ds;
760}
761
762bool cDvbTuner::SetFrontend(void)
763{
764#define MAXFRONTENDCMDS16 16
765#define SETCMD(c, d){ Frontend[CmdSeq.num].cmd = (c); Frontend[CmdSeq.num].u.data
= (d); if (CmdSeq.num++ > 16) { void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
{ Frontend[CmdSeq.num].cmd = (c);\
766 Frontend[CmdSeq.num].u.data = (d);\
767 if (CmdSeq.num++ > MAXFRONTENDCMDS16) {\
768 esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() )
;\
769 return false;\
770 }\
771 }
772 dtv_property Frontend[MAXFRONTENDCMDS16];
773 memset(&Frontend, 0, sizeof(Frontend));
774 dtv_properties CmdSeq;
775 memset(&CmdSeq, 0, sizeof(CmdSeq));
776 CmdSeq.props = Frontend;
777 SETCMD(DTV_CLEAR, 0){ Frontend[CmdSeq.num].cmd = (2); Frontend[CmdSeq.num].u.data
= (0); if (CmdSeq.num++ > 16) { void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
778 if (ioctl(fd_frontend, FE_SET_PROPERTY(((1U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((82)) << 0) | ((((sizeof(struct dtv_properties)))) <<
((0 +8)+8)))
, &CmdSeq) < 0) {
779 esyslog("ERROR: frontend %d/%d: %m", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: frontend %d/%d: %m"
, adapter, frontend) : void() )
;
780 return false;
781 }
782 CmdSeq.num = 0;
783
784 cDvbTransponderParameters dtp(channel.Parameters());
785
786 // Determine the required frontend type:
787 frontendType = GetRequiredDeliverySystem(&channel, &dtp);
788 if (frontendType == SYS_UNDEFINED)
789 return false;
790
791 SETCMD(DTV_DELIVERY_SYSTEM, frontendType){ Frontend[CmdSeq.num].cmd = (17); Frontend[CmdSeq.num].u.data
= (frontendType); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
792 if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
793 unsigned int frequency = channel.Frequency();
794 if (Setup.DiSEqC) {
795 if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
796 frequency -= diseqc->Lof();
797 if (diseqc != lastDiseqc || diseqc->IsScr() || diseqc->Position() >= 0 && channel.Source() != lastSource) {
798 if (IsBondedMaster()) {
799 ExecuteDiseqc(diseqc, &frequency);
800 if (frequency == 0)
801 return false;
802 }
803 else
804 ResetToneAndVoltage();
805 lastDiseqc = diseqc;
806 lastSource = channel.Source();
807 }
808 }
809 else {
810 esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number())void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: no DiSEqC parameters found for channel %d"
, channel.Number()) : void() )
;
811 return false;
812 }
813 }
814 else {
815 int tone = SEC_TONE_OFF;
816 if (frequency < (unsigned int)Setup.LnbSLOF) {
817 frequency -= Setup.LnbFrequLo;
818 tone = SEC_TONE_OFF;
819 }
820 else {
821 frequency -= Setup.LnbFrequHi;
822 tone = SEC_TONE_ON;
823 }
824 int volt = (dtp.Polarization() == 'V' || dtp.Polarization() == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
825 if (!IsBondedMaster()) {
826 tone = SEC_TONE_OFF;
827 volt = SEC_VOLTAGE_13;
828 }
829 CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((67)) << 0) | ((0) <<
((0 +8)+8))), volt)) < 0) void( (SysLogLevel > 0) ? syslog_with_tid
(3, "ERROR (%s,%d): %m", "dvbdevice.c", 829) : void() ); }
;
830 CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)){ if ((ioctl(fd_frontend, (((0U) << (((0 +8)+8)+14)) | (
(('o')) << (0 +8)) | (((66)) << 0) | ((0) <<
((0 +8)+8))), tone)) < 0) void( (SysLogLevel > 0) ? syslog_with_tid
(3, "ERROR (%s,%d): %m", "dvbdevice.c", 830) : void() ); }
;
831 }
832 frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF
833
834 // DVB-S/DVB-S2 (common parts)
835 SETCMD(DTV_FREQUENCY, frequency * 1000UL){ Frontend[CmdSeq.num].cmd = (3); Frontend[CmdSeq.num].u.data
= (frequency * 1000UL); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
836 SETCMD(DTV_MODULATION, dtp.Modulation()){ Frontend[CmdSeq.num].cmd = (4); Frontend[CmdSeq.num].u.data
= (dtp.Modulation()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
837 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL){ Frontend[CmdSeq.num].cmd = (8); Frontend[CmdSeq.num].u.data
= (channel.Srate() * 1000UL); if (CmdSeq.num++ > 16) { void
( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
838 SETCMD(DTV_INNER_FEC, dtp.CoderateH()){ Frontend[CmdSeq.num].cmd = (9); Frontend[CmdSeq.num].u.data
= (dtp.CoderateH()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
839 SETCMD(DTV_INVERSION, dtp.Inversion()){ Frontend[CmdSeq.num].cmd = (6); Frontend[CmdSeq.num].u.data
= (dtp.Inversion()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
840 if (frontendType == SYS_DVBS2) {
841 // DVB-S2
842 SETCMD(DTV_PILOT, PILOT_AUTO){ Frontend[CmdSeq.num].cmd = (12); Frontend[CmdSeq.num].u.data
= (PILOT_AUTO); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
843 SETCMD(DTV_ROLLOFF, dtp.RollOff()){ Frontend[CmdSeq.num].cmd = (13); Frontend[CmdSeq.num].u.data
= (dtp.RollOff()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
844 if (DvbApiVersion >= 0x0508)
845 SETCMD(DTV_STREAM_ID, dtp.StreamId()){ Frontend[CmdSeq.num].cmd = (42); Frontend[CmdSeq.num].u.data
= (dtp.StreamId()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
846 }
847 else {
848 // DVB-S
849 SETCMD(DTV_ROLLOFF, ROLLOFF_35){ Frontend[CmdSeq.num].cmd = (13); Frontend[CmdSeq.num].u.data
= (ROLLOFF_35); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
; // DVB-S always has a ROLLOFF of 0.35
850 }
851
852 tuneTimeout = DVBS_TUNE_TIMEOUT9000;
853 lockTimeout = DVBS_LOCK_TIMEOUT2000;
854 }
855 else if (frontendType == SYS_DVBC_ANNEX_ACSYS_DVBC_ANNEX_A || frontendType == SYS_DVBC_ANNEX_B) {
856 // DVB-C
857 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())){ Frontend[CmdSeq.num].cmd = (3); Frontend[CmdSeq.num].u.data
= (FrequencyToHz(channel.Frequency())); if (CmdSeq.num++ >
16) { void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
858 SETCMD(DTV_INVERSION, dtp.Inversion()){ Frontend[CmdSeq.num].cmd = (6); Frontend[CmdSeq.num].u.data
= (dtp.Inversion()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
859 SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL){ Frontend[CmdSeq.num].cmd = (8); Frontend[CmdSeq.num].u.data
= (channel.Srate() * 1000UL); if (CmdSeq.num++ > 16) { void
( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
860 SETCMD(DTV_INNER_FEC, dtp.CoderateH()){ Frontend[CmdSeq.num].cmd = (9); Frontend[CmdSeq.num].u.data
= (dtp.CoderateH()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
861 SETCMD(DTV_MODULATION, dtp.Modulation()){ Frontend[CmdSeq.num].cmd = (4); Frontend[CmdSeq.num].u.data
= (dtp.Modulation()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
862
863 tuneTimeout = DVBC_TUNE_TIMEOUT9000;
864 lockTimeout = DVBC_LOCK_TIMEOUT2000;
865 }
866 else if (frontendType == SYS_DVBT || frontendType == SYS_DVBT2) {
867 // DVB-T/DVB-T2 (common parts)
868 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())){ Frontend[CmdSeq.num].cmd = (3); Frontend[CmdSeq.num].u.data
= (FrequencyToHz(channel.Frequency())); if (CmdSeq.num++ >
16) { void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
869 SETCMD(DTV_INVERSION, dtp.Inversion()){ Frontend[CmdSeq.num].cmd = (6); Frontend[CmdSeq.num].u.data
= (dtp.Inversion()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
870 SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth()){ Frontend[CmdSeq.num].cmd = (5); Frontend[CmdSeq.num].u.data
= (dtp.Bandwidth()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
871 SETCMD(DTV_CODE_RATE_HP, dtp.CoderateH()){ Frontend[CmdSeq.num].cmd = (36); Frontend[CmdSeq.num].u.data
= (dtp.CoderateH()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
872 SETCMD(DTV_CODE_RATE_LP, dtp.CoderateL()){ Frontend[CmdSeq.num].cmd = (37); Frontend[CmdSeq.num].u.data
= (dtp.CoderateL()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
873 SETCMD(DTV_MODULATION, dtp.Modulation()){ Frontend[CmdSeq.num].cmd = (4); Frontend[CmdSeq.num].u.data
= (dtp.Modulation()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
874 SETCMD(DTV_TRANSMISSION_MODE, dtp.Transmission()){ Frontend[CmdSeq.num].cmd = (39); Frontend[CmdSeq.num].u.data
= (dtp.Transmission()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
875 SETCMD(DTV_GUARD_INTERVAL, dtp.Guard()){ Frontend[CmdSeq.num].cmd = (38); Frontend[CmdSeq.num].u.data
= (dtp.Guard()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
876 SETCMD(DTV_HIERARCHY, dtp.Hierarchy()){ Frontend[CmdSeq.num].cmd = (40); Frontend[CmdSeq.num].u.data
= (dtp.Hierarchy()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
877 if (frontendType == SYS_DVBT2) {
878 // DVB-T2
879 if (DvbApiVersion >= 0x0508) {
880 SETCMD(DTV_STREAM_ID, dtp.StreamId()){ Frontend[CmdSeq.num].cmd = (42); Frontend[CmdSeq.num].u.data
= (dtp.StreamId()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
881 }
882 else if (DvbApiVersion >= 0x0503)
883 SETCMD(DTV_DVBT2_PLP_ID_LEGACY, dtp.StreamId()){ Frontend[CmdSeq.num].cmd = (43); Frontend[CmdSeq.num].u.data
= (dtp.StreamId()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
884 }
885
886 tuneTimeout = DVBT_TUNE_TIMEOUT9000;
887 lockTimeout = DVBT_LOCK_TIMEOUT2000;
888 }
889 else if (frontendType == SYS_ATSC) {
890 // ATSC
891 SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())){ Frontend[CmdSeq.num].cmd = (3); Frontend[CmdSeq.num].u.data
= (FrequencyToHz(channel.Frequency())); if (CmdSeq.num++ >
16) { void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
892 SETCMD(DTV_INVERSION, dtp.Inversion()){ Frontend[CmdSeq.num].cmd = (6); Frontend[CmdSeq.num].u.data
= (dtp.Inversion()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
893 SETCMD(DTV_MODULATION, dtp.Modulation()){ Frontend[CmdSeq.num].cmd = (4); Frontend[CmdSeq.num].u.data
= (dtp.Modulation()); if (CmdSeq.num++ > 16) { void( (SysLogLevel
> 0) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
894
895 tuneTimeout = ATSC_TUNE_TIMEOUT9000;
896 lockTimeout = ATSC_LOCK_TIMEOUT2000;
897 }
898 else {
899 esyslog("ERROR: attempt to set channel with unknown DVB frontend type")void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: attempt to set channel with unknown DVB frontend type"
) : void() )
;
900 return false;
901 }
902 SETCMD(DTV_TUNE, 0){ Frontend[CmdSeq.num].cmd = (1); Frontend[CmdSeq.num].u.data
= (0); if (CmdSeq.num++ > 16) { void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
903 if (ioctl(fd_frontend, FE_SET_PROPERTY(((1U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((82)) << 0) | ((((sizeof(struct dtv_properties)))) <<
((0 +8)+8)))
, &CmdSeq) < 0) {
904 esyslog("ERROR: frontend %d/%d: %m", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: frontend %d/%d: %m"
, adapter, frontend) : void() )
;
905 return false;
906 }
907 return true;
908}
909
910void cDvbTuner::Action(void)
911{
912 cTimeMs Timer;
913 bool LostLock = false;
914 fe_status_t Status = (fe_status_t)0;
915 while (Running()) {
916 fe_status_t NewStatus;
917 if (GetFrontendStatus(NewStatus))
918 Status = NewStatus;
919 cMutexLock MutexLock(&mutex);
920 int WaitTime = 1000;
921 switch (tunerStatus) {
922 case tsIdle:
923 break; // we want the TimedWait() below!
924 case tsSet:
925 tunerStatus = SetFrontend() ? tsPositioning : tsIdle;
926 continue;
927 case tsPositioning:
928 if (positioner) {
929 if (positioner->IsMoving())
930 break; // we want the TimedWait() below!
931 else if (diseqcOffset) {
932 lastDiseqc = NULL__null;
933 tunerStatus = tsSet; // have it process the rest of the DiSEqC sequence
934 continue;
935 }
936 }
937 tunerStatus = tsTuned;
938 Timer.Set(tuneTimeout + (scr ? rand() % SCR_RANDOM_TIMEOUT500 : 0));
939 if (positioner)
940 continue;
941 // otherwise run directly into tsTuned...
942 case tsTuned:
943 if (Timer.TimedOut()) {
944 tunerStatus = tsSet;
945 lastDiseqc = NULL__null;
946 lastSource = 0;
947 if (time(NULL__null) - lastTimeoutReport > 60) { // let's not get too many of these
948 isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder())void( (SysLogLevel > 1) ? syslog_with_tid(6, "frontend %d/%d timed out while tuning to channel %d, tp %d"
, adapter, frontend, channel.Number(), channel.Transponder())
: void() )
;
949 lastTimeoutReport = time(NULL__null);
950 }
951 continue;
952 }
953 WaitTime = 100; // allows for a quick change from tsTuned to tsLocked
954 // run into tsLocked...
955 case tsLocked:
956 if (Status & FE_REINIT) {
957 tunerStatus = tsSet;
958 lastDiseqc = NULL__null;
959 lastSource = 0;
960 isyslog("frontend %d/%d was reinitialized", adapter, frontend)void( (SysLogLevel > 1) ? syslog_with_tid(6, "frontend %d/%d was reinitialized"
, adapter, frontend) : void() )
;
961 lastTimeoutReport = 0;
962 continue;
963 }
964 else if (Status & FE_HAS_LOCK) {
965 if (LostLock) {
966 isyslog("frontend %d/%d regained lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder())void( (SysLogLevel > 1) ? syslog_with_tid(6, "frontend %d/%d regained lock on channel %d, tp %d"
, adapter, frontend, channel.Number(), channel.Transponder())
: void() )
;
967 LostLock = false;
968 }
969 tunerStatus = tsLocked;
970 locked.Broadcast();
971 lastTimeoutReport = 0;
972 }
973 else if (tunerStatus == tsLocked) {
974 LostLock = true;
975 isyslog("frontend %d/%d lost lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder())void( (SysLogLevel > 1) ? syslog_with_tid(6, "frontend %d/%d lost lock on channel %d, tp %d"
, adapter, frontend, channel.Number(), channel.Transponder())
: void() )
;
976 tunerStatus = tsTuned;
977 Timer.Set(lockTimeout);
978 lastTimeoutReport = 0;
979 continue;
980 }
981 break;
982 default: esyslog("ERROR: unknown tuner status %d", tunerStatus)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown tuner status %d"
, tunerStatus) : void() )
;
983 }
984 newSet.TimedWait(mutex, WaitTime);
985 }
986}
987
988// --- cDvbSourceParam -------------------------------------------------------
989
990class cDvbSourceParam : public cSourceParam {
991private:
992 int param;
993 int srate;
994 cDvbTransponderParameters dtp;
995public:
996 cDvbSourceParam(char Source, const char *Description);
997 virtual void SetData(cChannel *Channel);
998 virtual void GetData(cChannel *Channel);
999 virtual cOsdItem *GetOsdItem(void);
1000 };
1001
1002cDvbSourceParam::cDvbSourceParam(char Source, const char *Description)
1003:cSourceParam(Source, Description)
1004{
1005 param = 0;
1006 srate = 0;
1007}
1008
1009void cDvbSourceParam::SetData(cChannel *Channel)
1010{
1011 srate = Channel->Srate();
1012 dtp.Parse(Channel->Parameters());
1013 param = 0;
1014}
1015
1016void cDvbSourceParam::GetData(cChannel *Channel)
1017{
1018 Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), srate, dtp.ToString(Source()), true);
1019}
1020
1021cOsdItem *cDvbSourceParam::GetOsdItem(void)
1022{
1023 char type = Source();
1024 const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr;
1025#undef ST
1026#define ST(s)if (strchr(s, type)) if (strchr(s, type))
1027 switch (param++) {
1028 case 0: ST(" S ")if (strchr(" S ", type)) return new cMenuEditChrItem( tr("Polarization")I18nTranslate("Polarization"), &dtp.polarization, "HVLR"); else return GetOsdItem();
1029 case 1: ST(" ST")if (strchr(" ST", type)) return new cMenuEditMapItem( tr("System")I18nTranslate("System"), &dtp.system, SystemValues); else return GetOsdItem();
1030 case 2: ST(" CS ")if (strchr(" CS ", type)) return new cMenuEditIntItem( tr("Srate")I18nTranslate("Srate"), &srate); else return GetOsdItem();
1031 case 3: ST("ACST")if (strchr("ACST", type)) return new cMenuEditMapItem( tr("Inversion")I18nTranslate("Inversion"), &dtp.inversion, InversionValues); else return GetOsdItem();
1032 case 4: ST(" CST")if (strchr(" CST", type)) return new cMenuEditMapItem( tr("CoderateH")I18nTranslate("CoderateH"), &dtp.coderateH, CoderateValues); else return GetOsdItem();
1033 case 5: ST(" T")if (strchr(" T", type)) return new cMenuEditMapItem( tr("CoderateL")I18nTranslate("CoderateL"), &dtp.coderateL, CoderateValues); else return GetOsdItem();
1034 case 6: ST("ACST")if (strchr("ACST", type)) return new cMenuEditMapItem( tr("Modulation")I18nTranslate("Modulation"), &dtp.modulation, ModulationValues); else return GetOsdItem();
1035 case 7: ST(" T")if (strchr(" T", type)) return new cMenuEditMapItem( tr("Bandwidth")I18nTranslate("Bandwidth"), &dtp.bandwidth, BandwidthValues); else return GetOsdItem();
1036 case 8: ST(" T")if (strchr(" T", type)) return new cMenuEditMapItem( tr("Transmission")I18nTranslate("Transmission"), &dtp.transmission, TransmissionValues); else return GetOsdItem();
1037 case 9: ST(" T")if (strchr(" T", type)) return new cMenuEditMapItem( tr("Guard")I18nTranslate("Guard"), &dtp.guard, GuardValues); else return GetOsdItem();
1038 case 10: ST(" T")if (strchr(" T", type)) return new cMenuEditMapItem( tr("Hierarchy")I18nTranslate("Hierarchy"), &dtp.hierarchy, HierarchyValues); else return GetOsdItem();
1039 case 11: ST(" S ")if (strchr(" S ", type)) return new cMenuEditMapItem( tr("Rolloff")I18nTranslate("Rolloff"), &dtp.rollOff, RollOffValues); else return GetOsdItem();
1040 case 12: ST(" ST")if (strchr(" ST", type)) return new cMenuEditIntItem( tr("StreamId")I18nTranslate("StreamId"), &dtp.streamId, 0, 255); else return GetOsdItem();
1041 default: return NULL__null;
1042 }
1043 return NULL__null;
1044}
1045
1046// --- cDvbDevice ------------------------------------------------------------
1047
1048int cDvbDevice::setTransferModeForDolbyDigital = 1;
1049cMutex cDvbDevice::bondMutex;
1050
1051const char *DeliverySystemNames[] = {
1052 "",
1053 "DVB-C",
1054 "DVB-C",
1055 "DVB-T",
1056 "DSS",
1057 "DVB-S",
1058 "DVB-S2",
1059 "DVB-H",
1060 "ISDBT",
1061 "ISDBS",
1062 "ISDBC",
1063 "ATSC",
1064 "ATSCMH",
1065 "DMBTH",
1066 "CMMB",
1067 "DAB",
1068 "DVB-T2",
1069 "TURBO",
1070 NULL__null
1071 };
1072
1073cDvbDevice::cDvbDevice(int Adapter, int Frontend)
1074{
1075 adapter = Adapter;
1076 frontend = Frontend;
1077 ciAdapter = NULL__null;
1078 dvbTuner = NULL__null;
1079 numDeliverySystems = 0;
1080 numModulations = 0;
1081 bondedDevice = NULL__null;
1082 needsDetachBondedReceivers = false;
1083 tsBuffer = NULL__null;
1084
1085 // Devices that are present on all card types:
1086
1087 int fd_frontend = DvbOpen(DEV_DVB_FRONTEND"frontend", adapter, frontend, O_RDWR02 | O_NONBLOCK04000);
1088
1089 // Common Interface:
1090
1091 fd_ca = DvbOpen(DEV_DVB_CA"ca", adapter, frontend, O_RDWR02);
1092 if (fd_ca >= 0)
1093 ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
1094
1095 // The DVR device (will be opened and closed as needed):
1096
1097 fd_dvr = -1;
1098
1099 // We only check the devices that must be present - the others will be checked before accessing them://XXX
1100
1101 if (fd_frontend >= 0) {
1102 if (QueryDeliverySystems(fd_frontend))
1103 dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend);
1104 }
1105 else
1106 esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't open DVB device %d/%d"
, adapter, frontend) : void() )
;
1107
1108 StartSectionHandler();
1109}
1110
1111cDvbDevice::~cDvbDevice()
1112{
1113 StopSectionHandler();
1114 delete dvbTuner;
1115 delete ciAdapter;
1116 UnBond();
1117 // We're not explicitly closing any device files here, since this sometimes
1118 // caused segfaults. Besides, the program is about to terminate anyway...
1119}
1120
1121cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
1122{
1123 return cString::sprintf("%s/%s%d/%s%d", DEV_DVB_BASE"/dev/dvb", DEV_DVB_ADAPTER"adapter", Adapter, Name, Frontend);
1124}
1125
1126int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
1127{
1128 cString FileName = DvbName(Name, Adapter, Frontend);
1129 int fd = open(FileName, Mode);
1130 if (fd < 0 && ReportError)
1131 LOG_ERROR_STR(*FileName)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %s: %m"
, "dvbdevice.c", 1131, *FileName) : void() )
;
1132 return fd;
1133}
1134
1135bool cDvbDevice::Exists(int Adapter, int Frontend)
1136{
1137 cString FileName = DvbName(DEV_DVB_FRONTEND"frontend", Adapter, Frontend);
1138 if (access(FileName, F_OK0) == 0) {
1139 int f = open(FileName, O_RDONLY00);
1140 if (f >= 0) {
1141 close(f);
1142 return true;
1143 }
1144 else if (errno(*__errno_location ()) != ENODEV19 && errno(*__errno_location ()) != EINVAL22)
1145 LOG_ERROR_STR(*FileName)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %s: %m"
, "dvbdevice.c", 1145, *FileName) : void() )
;
1146 }
1147 else if (errno(*__errno_location ()) != ENOENT2)
1148 LOG_ERROR_STR(*FileName)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %s: %m"
, "dvbdevice.c", 1148, *FileName) : void() )
;
1149 return false;
1150}
1151
1152bool cDvbDevice::Probe(int Adapter, int Frontend)
1153{
1154 cString FileName = DvbName(DEV_DVB_FRONTEND"frontend", Adapter, Frontend);
1155 dsyslog("probing %s", *FileName)void( (SysLogLevel > 2) ? syslog_with_tid(7, "probing %s",
*FileName) : void() )
;
1156 for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
1157 if (dp->Probe(Adapter, Frontend))
1158 return true; // a plugin has created the actual device
1159 }
1160 dsyslog("creating cDvbDevice")void( (SysLogLevel > 2) ? syslog_with_tid(7, "creating cDvbDevice"
) : void() )
;
1161 new cDvbDevice(Adapter, Frontend); // it's a "budget" device
1162 return true;
1163}
1164
1165cString cDvbDevice::DeviceType(void) const
1166{
1167 if (dvbTuner) {
1168 if (dvbTuner->FrontendType() != SYS_UNDEFINED)
1169 return DeliverySystemNames[dvbTuner->FrontendType()];
1170 if (numDeliverySystems)
1171 return DeliverySystemNames[deliverySystems[0]]; // to have some reasonable default
1172 }
1173 return "";
1174}
1175
1176cString cDvbDevice::DeviceName(void) const
1177{
1178 return frontendInfo.name;
1179}
1180
1181bool cDvbDevice::Initialize(void)
1182{
1183 new cDvbSourceParam('A', "ATSC");
1184 new cDvbSourceParam('C', "DVB-C");
1185 new cDvbSourceParam('S', "DVB-S");
1186 new cDvbSourceParam('T', "DVB-T");
1187 cStringList Nodes;
1188 cReadDir DvbDir(DEV_DVB_BASE"/dev/dvb");
1189 if (DvbDir.Ok()) {
1190 struct dirent *a;
1191 while ((a = DvbDir.Next()) != NULL__null) {
1192 if (strstr(a->d_name, DEV_DVB_ADAPTER"adapter") == a->d_name) {
1193 int Adapter = strtol(a->d_name + strlen(DEV_DVB_ADAPTER"adapter"), NULL__null, 10);
1194 cReadDir AdapterDir(AddDirectory(DEV_DVB_BASE"/dev/dvb", a->d_name));
1195 if (AdapterDir.Ok()) {
1196 struct dirent *f;
1197 while ((f = AdapterDir.Next()) != NULL__null) {
1198 if (strstr(f->d_name, DEV_DVB_FRONTEND"frontend") == f->d_name) {
1199 int Frontend = strtol(f->d_name + strlen(DEV_DVB_FRONTEND"frontend"), NULL__null, 10);
1200 Nodes.Append(strdup(cString::sprintf("%2d %2d", Adapter, Frontend)));
1201 }
1202 }
1203 }
1204 }
1205 }
1206 }
1207 int Found = 0;
1208 int Used = 0;
1209 if (Nodes.Size() > 0) {
1210 Nodes.Sort();
1211 for (int i = 0; i < Nodes.Size(); i++) {
1212 int Adapter;
1213 int Frontend;
1214 if (2 == sscanf(Nodes[i], "%d %d", &Adapter, &Frontend)) {
1215 if (Exists(Adapter, Frontend)) {
1216 if (Found < MAXDEVICES16) {
1217 Found++;
1218 if (UseDevice(NextCardIndex())) {
1219 if (Probe(Adapter, Frontend))
1220 Used++;
1221 }
1222 else
1223 NextCardIndex(1); // skips this one
1224 }
1225 }
1226 }
1227 }
1228 }
1229 if (Found > 0) {
1230 isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "")void( (SysLogLevel > 1) ? syslog_with_tid(6, "found %d DVB device%s"
, Found, Found > 1 ? "s" : "") : void() )
;
1231 if (Used != Found)
1232 isyslog("using only %d DVB device%s", Used, Used > 1 ? "s" : "")void( (SysLogLevel > 1) ? syslog_with_tid(6, "using only %d DVB device%s"
, Used, Used > 1 ? "s" : "") : void() )
;
1233 }
1234 else
1235 isyslog("no DVB device found")void( (SysLogLevel > 1) ? syslog_with_tid(6, "no DVB device found"
) : void() )
;
1236 return Found > 0;
1237}
1238
1239bool cDvbDevice::QueryDeliverySystems(int fd_frontend)
1240{
1241 numDeliverySystems = 0;
1242 if (ioctl(fd_frontend, FE_GET_INFO(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((61)) << 0) | ((((sizeof(struct dvb_frontend_info)))
) << ((0 +8)+8)))
, &frontendInfo) < 0) {
1243 LOG_ERRORvoid( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 1243) : void() )
;
1244 return false;
1245 }
1246 dtv_property Frontend[1];
1247 dtv_properties CmdSeq;
1248 // Determine the version of the running DVB API:
1249 if (!DvbApiVersion) {
1250 memset(&Frontend, 0, sizeof(Frontend));
1251 memset(&CmdSeq, 0, sizeof(CmdSeq));
1252 CmdSeq.props = Frontend;
1253 SETCMD(DTV_API_VERSION, 0){ Frontend[CmdSeq.num].cmd = (35); Frontend[CmdSeq.num].u.data
= (0); if (CmdSeq.num++ > 16) { void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
1254 if (ioctl(fd_frontend, FE_GET_PROPERTY(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((83)) << 0) | ((((sizeof(struct dtv_properties)))) <<
((0 +8)+8)))
, &CmdSeq) != 0) {
1255 LOG_ERRORvoid( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 1255) : void() )
;
1256 return false;
1257 }
1258 DvbApiVersion = Frontend[0].u.data;
1259 isyslog("DVB API version is 0x%04X (VDR was built with 0x%04X)", DvbApiVersion, DVBAPIVERSION)void( (SysLogLevel > 1) ? syslog_with_tid(6, "DVB API version is 0x%04X (VDR was built with 0x%04X)"
, DvbApiVersion, (5 << 8 | 10)) : void() )
;
1260 }
1261 // Determine the types of delivery systems this device provides:
1262 bool LegacyMode = true;
1263 if (DvbApiVersion >= 0x0505) {
1264 memset(&Frontend, 0, sizeof(Frontend));
1265 memset(&CmdSeq, 0, sizeof(CmdSeq));
1266 CmdSeq.props = Frontend;
1267 SETCMD(DTV_ENUM_DELSYS, 0){ Frontend[CmdSeq.num].cmd = (44); Frontend[CmdSeq.num].u.data
= (0); if (CmdSeq.num++ > 16) { void( (SysLogLevel > 0
) ? syslog_with_tid(3, "ERROR: too many tuning commands on frontend %d/%d"
, adapter, frontend) : void() ); return false; } }
;
1268 int Result = ioctl(fd_frontend, FE_GET_PROPERTY(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((83)) << 0) | ((((sizeof(struct dtv_properties)))) <<
((0 +8)+8)))
, &CmdSeq);
1269 if (Result == 0) {
1270 for (uint i = 0; i < Frontend[0].u.buffer.len; i++) {
1271 if (numDeliverySystems >= MAXDELIVERYSYSTEMS8) {
1272 esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: too many delivery systems on frontend %d/%d"
, adapter, frontend) : void() )
;
1273 break;
1274 }
1275 deliverySystems[numDeliverySystems++] = Frontend[0].u.buffer.data[i];
1276 }
1277 LegacyMode = false;
1278 }
1279 else {
1280 esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode"
, adapter, frontend) : void() )
;
1281 }
1282 }
1283 if (LegacyMode) {
1284 // Legacy mode (DVB-API < 5.5):
1285 switch (frontendInfo.type) {
1286 case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS;
1287 if (frontendInfo.caps & FE_CAN_2G_MODULATION)
1288 deliverySystems[numDeliverySystems++] = SYS_DVBS2;
1289 break;
1290 case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT;
1291 if (frontendInfo.caps & FE_CAN_2G_MODULATION)
1292 deliverySystems[numDeliverySystems++] = SYS_DVBT2;
1293 break;
1294 case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_ACSYS_DVBC_ANNEX_A; break;
1295 case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break;
1296 default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown frontend type %d on frontend %d/%d"
, frontendInfo.type, adapter, frontend) : void() )
;
1297 }
1298 }
1299 if (numDeliverySystems > 0) {
1300 cString ds("");
1301 for (int i = 0; i < numDeliverySystems; i++)
1302 ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", DeliverySystemNames[deliverySystems[i]]);
1303 cString ms("");
1304 if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
1305 if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
1306 if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); }
1307 if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); }
1308 if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); }
1309 if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); }
1310 if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); }
1311 if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); }
1312 if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); }
1313 if (!**ms)
1314 ms = "unknown modulations";
1315 isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name)void( (SysLogLevel > 1) ? syslog_with_tid(6, "frontend %d/%d provides %s with %s (\"%s\")"
, adapter, frontend, *ds, *ms, frontendInfo.name) : void() )
;
1316 return true;
1317 }
1318 else
1319 esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: frontend %d/%d doesn't provide any delivery systems"
, adapter, frontend) : void() )
;
1320 return false;
1321}
1322
1323bool cDvbDevice::BondDevices(const char *Bondings)
1324{
1325 UnBondDevices();
1326 if (Bondings) {
1327 cSatCableNumbers SatCableNumbers(MAXDEVICES16, Bondings);
1328 for (int i = 0; i < cDevice::NumDevices(); i++) {
1329 int d = SatCableNumbers.FirstDeviceIndex(i);
1330 if (d >= 0) {
1331 int ErrorDevice = 0;
1332 if (cDevice *Device1 = cDevice::GetDevice(i)) {
1333 if (cDevice *Device2 = cDevice::GetDevice(d)) {
1334 if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
1335 if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
1336 if (!DvbDevice1->Bond(DvbDevice2))
1337 return false; // Bond() has already logged the error
1338 }
1339 else
1340 ErrorDevice = d + 1;
1341 }
1342 else
1343 ErrorDevice = i + 1;
1344 if (ErrorDevice) {
1345 esyslog("ERROR: device '%d' in device bondings '%s' is not a cDvbDevice", ErrorDevice, Bondings)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: device '%d' in device bondings '%s' is not a cDvbDevice"
, ErrorDevice, Bondings) : void() )
;
1346 return false;
1347 }
1348 }
1349 else
1350 ErrorDevice = d + 1;
1351 }
1352 else
1353 ErrorDevice = i + 1;
1354 if (ErrorDevice) {
1355 esyslog("ERROR: unknown device '%d' in device bondings '%s'", ErrorDevice, Bondings)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: unknown device '%d' in device bondings '%s'"
, ErrorDevice, Bondings) : void() )
;
1356 return false;
1357 }
1358 }
1359 }
1360 }
1361 return true;
1362}
1363
1364void cDvbDevice::UnBondDevices(void)
1365{
1366 for (int i = 0; i < cDevice::NumDevices(); i++) {
1367 if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i)))
1368 d->UnBond();
1369 }
1370}
1371
1372bool cDvbDevice::Bond(cDvbDevice *Device)
1373{
1374 cMutexLock MutexLock(&bondMutex);
1375 if (!bondedDevice) {
1376 if (Device != this) {
1377 if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) {
1378 if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) {
1379 bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device;
1380 Device->bondedDevice = this;
1381 dsyslog("device %d bonded with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1)void( (SysLogLevel > 2) ? syslog_with_tid(7, "device %d bonded with device %d"
, CardIndex() + 1, bondedDevice->CardIndex() + 1) : void()
)
;
1382 return true;
1383 }
1384 }
1385 else
1386 esyslog("ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)", CardIndex() + 1, Device->CardIndex() + 1)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't bond device %d with device %d (only DVB-S(2) devices can be bonded)"
, CardIndex() + 1, Device->CardIndex() + 1) : void() )
;
1387 }
1388 else
1389 esyslog("ERROR: can't bond device %d with itself", CardIndex() + 1)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't bond device %d with itself"
, CardIndex() + 1) : void() )
;
1390 }
1391 else
1392 esyslog("ERROR: device %d already bonded with device %d, can't bond with device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->CardIndex() + 1)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: device %d already bonded with device %d, can't bond with device %d"
, CardIndex() + 1, bondedDevice->CardIndex() + 1, Device->
CardIndex() + 1) : void() )
;
1393 return false;
1394}
1395
1396void cDvbDevice::UnBond(void)
1397{
1398 cMutexLock MutexLock(&bondMutex);
1399 if (cDvbDevice *d = bondedDevice) {
1400 if (dvbTuner)
1401 dvbTuner->UnBond();
1402 dsyslog("device %d unbonded from device %d", CardIndex() + 1, bondedDevice->CardIndex() + 1)void( (SysLogLevel > 2) ? syslog_with_tid(7, "device %d unbonded from device %d"
, CardIndex() + 1, bondedDevice->CardIndex() + 1) : void()
)
;
1403 while (d->bondedDevice != this)
1404 d = d->bondedDevice;
1405 if (d == bondedDevice)
1406 d->bondedDevice = NULL__null;
1407 else
1408 d->bondedDevice = bondedDevice;
1409 bondedDevice = NULL__null;
1410 }
1411}
1412
1413bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const
1414{
1415 cMutexLock MutexLock(&bondMutex);
1416 if (bondedDevice || Positioner())
1417 return dvbTuner && dvbTuner->BondingOk(Channel, ConsiderOccupied);
1418 return true;
1419}
1420
1421bool cDvbDevice::HasCi(void)
1422{
1423 return ciAdapter;
1424}
1425
1426bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
1427{
1428 if (Handle->pid) {
1429 dmx_pes_filter_params pesFilterParams;
1430 memset(&pesFilterParams, 0, sizeof(pesFilterParams));
1431 if (On) {
1432 if (Handle->handle < 0) {
1433 Handle->handle = DvbOpen(DEV_DVB_DEMUX"demux", adapter, frontend, O_RDWR02 | O_NONBLOCK04000, true);
1434 if (Handle->handle < 0) {
1435 LOG_ERRORvoid( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 1435) : void() )
;
1436 return false;
1437 }
1438 }
1439 pesFilterParams.pid = Handle->pid;
1440 pesFilterParams.input = DMX_IN_FRONTEND;
1441 pesFilterParams.output = DMX_OUT_TS_TAP;
1442 pesFilterParams.pes_type= DMX_PES_OTHER;
1443 pesFilterParams.flags = DMX_IMMEDIATE_START4;
1444 if (ioctl(Handle->handle, DMX_SET_PES_FILTER(((1U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((44)) << 0) | ((((sizeof(struct dmx_pes_filter_params
)))) << ((0 +8)+8)))
, &pesFilterParams) < 0) {
1445 LOG_ERRORvoid( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR (%s,%d): %m"
, "dvbdevice.c", 1445) : void() )
;
1446 return false;
1447 }
1448 }
1449 else if (!Handle->used) {
1450 CHECK(ioctl(Handle->handle, DMX_STOP)){ if ((ioctl(Handle->handle, (((0U) << (((0 +8)+8)+14
)) | ((('o')) << (0 +8)) | (((42)) << 0) | ((0) <<
((0 +8)+8))))) < 0) void( (SysLogLevel > 0) ? syslog_with_tid
(3, "ERROR (%s,%d): %m", "dvbdevice.c", 1450) : void() ); }
;
1451 if (Type <= ptTeletext) {
1452 pesFilterParams.pid = 0x1FFF;
1453 pesFilterParams.input = DMX_IN_FRONTEND;
1454 pesFilterParams.output = DMX_OUT_DECODER;
1455 pesFilterParams.pes_type= DMX_PES_OTHER;
1456 pesFilterParams.flags = DMX_IMMEDIATE_START4;
1457 CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)){ if ((ioctl(Handle->handle, (((1U) << (((0 +8)+8)+14
)) | ((('o')) << (0 +8)) | (((44)) << 0) | ((((sizeof
(struct dmx_pes_filter_params)))) << ((0 +8)+8))), &
pesFilterParams)) < 0) void( (SysLogLevel > 0) ? syslog_with_tid
(3, "ERROR (%s,%d): %m", "dvbdevice.c", 1457) : void() ); }
;
1458 }
1459 close(Handle->handle);
1460 Handle->handle = -1;
1461 }
1462 }
1463 return true;
1464}
1465
1466int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
1467{
1468 cString FileName = DvbName(DEV_DVB_DEMUX"demux", adapter, frontend);
1469 int f = open(FileName, O_RDWR02 | O_NONBLOCK04000);
1470 if (f >= 0) {
1471 dmx_sct_filter_params sctFilterParams;
1472 memset(&sctFilterParams, 0, sizeof(sctFilterParams));
1473 sctFilterParams.pid = Pid;
1474 sctFilterParams.timeout = 0;
1475 sctFilterParams.flags = DMX_IMMEDIATE_START4;
1476 sctFilterParams.filter.filter[0] = Tid;
1477 sctFilterParams.filter.mask[0] = Mask;
1478 if (ioctl(f, DMX_SET_FILTER(((1U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((43)) << 0) | ((((sizeof(struct dmx_sct_filter_params
)))) << ((0 +8)+8)))
, &sctFilterParams) >= 0)
1479 return f;
1480 else {
1481 esyslog("ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m", Pid, Tid, Mask)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't set filter (pid=%d, tid=%02X, mask=%02X): %m"
, Pid, Tid, Mask) : void() )
;
1482 close(f);
1483 }
1484 }
1485 else
1486 esyslog("ERROR: can't open filter handle on '%s'", *FileName)void( (SysLogLevel > 0) ? syslog_with_tid(3, "ERROR: can't open filter handle on '%s'"
, *FileName) : void() )
;
1487 return -1;
1488}
1489
1490void cDvbDevice::CloseFilter(int Handle)
1491{
1492 close(Handle);
1493}
1494
1495bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const
1496{
1497 for (int i = 0; i < numDeliverySystems; i++) {
1498 if (deliverySystems[i] == DeliverySystem)
1499 return true;
1500 }
1501 return false;
1502}
1503
1504bool cDvbDevice::ProvidesSource(int Source) const
1505{
1506 int type = Source & cSource::st_Mask;
1507 return type == cSource::stNone
1508 || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
1509 || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_ACSYS_DVBC_ANNEX_A) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B))
1510 || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2))
1511 || type == cSource::stTerr && (ProvidesDeliverySystem(SYS_DVBT) || ProvidesDeliverySystem(SYS_DVBT2));
1512}
1513
1514bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
1515{
1516 if (!ProvidesSource(Channel->Source()))
1517 return false; // doesn't provide source
1518 cDvbTransponderParameters dtp(Channel->Parameters());
1519 if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) ||
1520 dtp.StreamId() != 0 && !(frontendInfo.caps & FE_CAN_MULTISTREAM) ||
1521 dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) ||
1522 dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) ||
1523 dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) ||
1524 dtp.Modulation() == QAM_64 && !(frontendInfo.caps & FE_CAN_QAM_64) ||
1525 dtp.Modulation() == QAM_128 && !(frontendInfo.caps & FE_CAN_QAM_128) ||
1526 dtp.Modulation() == QAM_256 && !(frontendInfo.caps & FE_CAN_QAM_256) ||
1527 dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
1528 dtp.Modulation() == VSB_8 && !(frontendInfo.caps & FE_CAN_8VSB) ||
1529 dtp.Modulation() == VSB_16 && !(frontendInfo.caps & FE_CAN_16VSB) ||
1530 dtp.Modulation() == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition
1531 return false; // requires modulation system which frontend doesn't provide
1532 if (!cSource::IsSat(Channel->Source()) ||
1533 (!Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL__null)))
1534 return DeviceHooksProvidesTransponder(Channel);
1535 return false;
1536}
1537
1538bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
1539{
1540 bool result = false;
1541 bool hasPriority = Priority == IDLEPRIORITY((-99) - 1) || Priority > this->Priority();
1542 bool needsDetachReceivers = false;
1543 needsDetachBondedReceivers = false;
1544
1545 if (dvbTuner && ProvidesTransponder(Channel)) {
1546 result = hasPriority;
1547 if (Priority > IDLEPRIORITY((-99) - 1)) {
1548 if (Receiving()) {
1549 if (dvbTuner->IsTunedTo(Channel)) {
1550 if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0)) || Channel->Dpid(0) && !HasPid(Channel->Dpid(0))) {
1551 if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN0x0100) {
1552 if (CamSlot()->CanDecrypt(Channel))
1553 result = true;
1554 else
1555 needsDetachReceivers = true;
1556 }
1557 else
1558 result = true;
1559 }
1560 else
1561 result = true;
1562 }
1563 else
1564 needsDetachReceivers = Receiving();
1565 }
1566 if (result) {
1567 cMutexLock MutexLock(&bondMutex);
1568 if (!BondingOk(Channel)) {
1569 // This device is bonded, so we need to check the priorities of the others:
1570 for (cDvbDevice *d = bondedDevice; d && d != this; d = d->bondedDevice) {
1571 if (d->Priority() >= Priority) {
1572 result = false;
1573 break;
1574 }
1575 needsDetachReceivers |= d->Receiving();
1576 }
1577 needsDetachBondedReceivers = true;
1578 needsDetachReceivers |= Receiving();
1579 }
1580 }
1581 }
1582 }
1583 if (NeedsDetachReceivers)
1584 *NeedsDetachReceivers = needsDetachReceivers;
1585 return result;
1586}
1587
1588bool cDvbDevice::ProvidesEIT(void) const
1589{
1590 return dvbTuner != NULL__null;
1591}
1592
1593int cDvbDevice::NumProvidedSystems(void) const
1594{
1595 return numDeliverySystems + numModulations;
1596}
1597
1598const cPositioner *cDvbDevice::Positioner(void) const
1599{
1600 return dvbTuner ? dvbTuner->Positioner() : NULL__null;
1601}
1602
1603int cDvbDevice::SignalStrength(void) const
1604{
1605 return dvbTuner ? dvbTuner->GetSignalStrength() : -1;
1606}
1607
1608int cDvbDevice::SignalQuality(void) const
1609{
1610 return dvbTuner ? dvbTuner->GetSignalQuality() : -1;
1611}
1612
1613const cChannel *cDvbDevice::GetCurrentlyTunedTransponder(void) const
1614{
1615 return dvbTuner ? dvbTuner->GetTransponder() : NULL__null;
1616}
1617
1618bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel) const
1619{
1620 return dvbTuner ? dvbTuner->IsTunedTo(Channel) : false;
1621}
1622
1623bool cDvbDevice::MaySwitchTransponder(const cChannel *Channel) const
1624{
1625 return BondingOk(Channel, true) && cDevice::MaySwitchTransponder(Channel);
1626}
1627
1628bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
1629{
1630 if (dvbTuner)
1631 dvbTuner->SetChannel(Channel);
1632 return true;
1633}
1634
1635bool cDvbDevice::HasLock(int TimeoutMs) const
1636{
1637 return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
1638}
1639
1640void cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
1641{
1642 setTransferModeForDolbyDigital = Mode;
1643}
1644
1645bool cDvbDevice::OpenDvr(void)
1646{
1647 CloseDvr();
1648 fd_dvr = DvbOpen(DEV_DVB_DVR"dvr", adapter, frontend, O_RDONLY00 | O_NONBLOCK04000, true);
1649 if (fd_dvr >= 0)
1650 tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5)((5) * 1024LL * 1024LL), CardIndex() + 1);
1651 return fd_dvr >= 0;
1652}
1653
1654void cDvbDevice::CloseDvr(void)
1655{
1656 if (fd_dvr >= 0) {
1657 delete tsBuffer;
1658 tsBuffer = NULL__null;
1659 close(fd_dvr);
1660 fd_dvr = -1;
1661 }
1662}
1663
1664bool cDvbDevice::GetTSPacket(uchar *&Data)
1665{
1666 if (tsBuffer) {
1667 if (cCamSlot *cs = CamSlot()) {
1668 if (cs->WantsTsData()) {
1669 int Available;
1670 Data = tsBuffer->Get(&Available);
1671 if (Data) {
1672 Data = cs->Decrypt(Data, Available);
1673 tsBuffer->Skip(Available);
1674 }
1675 return true;
1676 }
1677 }
1678 Data = tsBuffer->Get();
1679 return true;
1680 }
1681 return false;
1682}
1683
1684void cDvbDevice::DetachAllReceivers(void)
1685{
1686 cMutexLock MutexLock(&bondMutex);
1687 cDvbDevice *d = this;
1688 do {
1689 d->cDevice::DetachAllReceivers();
1690 d = d->bondedDevice;
1691 } while (d && d != this && needsDetachBondedReceivers);
1692 needsDetachBondedReceivers = false;
1693}
1694
1695// --- cDvbDeviceProbe -------------------------------------------------------
1696
1697cList<cDvbDeviceProbe> DvbDeviceProbes;
1698
1699cDvbDeviceProbe::cDvbDeviceProbe(void)
1700{
1701 DvbDeviceProbes.Add(this);
1702}
1703
1704cDvbDeviceProbe::~cDvbDeviceProbe()
1705{
1706 DvbDeviceProbes.Del(this, false);
1707}
1708
1709uint32_t cDvbDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
1710{
1711 uint32_t SubsystemId = 0;
1712 cString FileName = cString::sprintf("/dev/dvb/adapter%d/frontend%d", Adapter, Frontend);
1713 struct stat st;
1714 if (stat(FileName, &st) == 0) {
1715 cReadDir d("/sys/class/dvb");
1716 if (d.Ok()) {
1717 struct dirent *e;
1718 while ((e = d.Next()) != NULL__null) {
1719 if (strstr(e->d_name, "frontend")) {
1720 FileName = cString::sprintf("/sys/class/dvb/%s/dev", e->d_name);
1721 if (FILE *f = fopen(FileName, "r")) {
1722 cReadLine ReadLine;
1723 char *s = ReadLine.Read(f);
1724 fclose(f);
1725 unsigned Major;
1726 unsigned Minor;
1727 if (s && 2 == sscanf(s, "%u:%u", &Major, &Minor)) {
1728 if (((Major << 8) | Minor) == st.st_rdev) {
1729 FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_vendor", e->d_name);
1730 if ((f = fopen(FileName, "r")) != NULL__null) {
1731 if (char *s = ReadLine.Read(f))
1732 SubsystemId = strtoul(s, NULL__null, 0) << 16;
1733 fclose(f);
1734 }
1735 FileName = cString::sprintf("/sys/class/dvb/%s/device/subsystem_device", e->d_name);
1736 if ((f = fopen(FileName, "r")) != NULL__null) {
1737 if (char *s = ReadLine.Read(f))
1738 SubsystemId |= strtoul(s, NULL__null, 0);
1739 fclose(f);
1740 }
1741 break;
1742 }
1743 }
1744 }
1745 }
1746 }
1747 }
1748 }
1749 return SubsystemId;
1750}