@@ -285,9 +285,10 @@
private:
static cMutex bondMutex;
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
+ bool SendDiseqc;
int frontendType;
const cDvbDevice *device;
- int fd_frontend;
+ mutable int fd_frontend;
int adapter, frontend;
uint32_t subsystemId;
int tuneTimeout;
@@ -298,9 +299,10 @@
const cScr *scr;
bool lnbPowerTurnedOn;
eTunerStatus tunerStatus;
- cMutex mutex;
+ mutable cMutex mutex;
cCondVar locked;
cCondVar newSet;
+ dvb_diseqc_master_cmd diseqc_cmd;
cDvbTuner *bondedTuner;
bool bondedMaster;
bool SetFrontendType(const cChannel *Channel);
@@ -313,6 +315,10 @@
void ResetToneAndVoltage(void);
bool SetFrontend(void);
virtual void Action(void);
+
+ mutable bool isIdle;
+ bool OpenFrontend(void) const;
+ bool CloseFrontend(void);
public:
cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend);
virtual ~cDvbTuner();
@@ -327,12 +333,18 @@
bool Locked(int TimeoutMs = 0);
int GetSignalStrength(void) const;
int GetSignalQuality(void) const;
+ bool SetIdle(bool Idle);
+ bool IsIdle(void) const { return isIdle; }
+ bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd);
+private:
+ int GetCurrentDeliverySystem(void);
};
cMutex cDvbTuner::bondMutex;
cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend)
{
+ SendDiseqc = false;
frontendType = SYS_UNDEFINED;
device = Device;
fd_frontend = Fd_Frontend;
@@ -348,6 +360,7 @@
tunerStatus = tsIdle;
bondedTuner = NULL;
bondedMaster = false;
+ isIdle = false;
SetDescription("tuner on frontend %d/%d", adapter, frontend);
Start();
}
@@ -365,6 +378,8 @@
ExecuteDiseqc(lastDiseqc, &Frequency);
}
*/
+ if (device && device->IsSubDevice())
+ CloseFrontend();
}
bool cDvbTuner::Bond(cDvbTuner *Tuner)
@@ -509,6 +524,8 @@
void cDvbTuner::ClearEventQueue(void) const
{
+ if (!OpenFrontend())
+ return;
cPoller Poller(fd_frontend);
if (Poller.Poll(TUNER_POLL_TIMEOUT)) {
dvb_frontend_event Event;
@@ -531,32 +548,104 @@
//#define DEBUG_SIGNALSTRENGTH
//#define DEBUG_SIGNALQUALITY
-
+#define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
+// Inizio Modifica
int cDvbTuner::GetSignalStrength(void) const
{
- ClearEventQueue();
- uint16_t Signal;
- while (1) {
- if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
- break;
- if (errno != EINTR)
- return -1;
+ fe_status_t Status;
+ if (GetFrontendStatus(Status)) {
+ // 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...
+ if ((Status & FE_HAS_LOCK) == 0) {
+ if ((Status & FE_HAS_SIGNAL) == 0)
+ return 0;
+ if ((Status & FE_HAS_CARRIER) == 0)
+ return 1;
+ if ((Status & FE_HAS_VITERBI) == 0)
+ return 2;
+ if ((Status & FE_HAS_SYNC) == 0)
+ return 3;
+ return 4;
}
- uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
- // Use the subsystemId to identify individual devices in case they need
- // special treatment to map their Signal value into the range 0...0xFFFF.
- switch (subsystemId) {
- case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
- case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
- MaxSignal = 670; break;
- }
- int s = int(Signal) * 100 / MaxSignal;
- if (s > 100)
- s = 100;
#ifdef DEBUG_SIGNALSTRENGTH
- fprintf(stderr, "FE %d/%d: %08X S = %04X %04X %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, s);
+ bool HasSignal = true;
#endif
- return s;
+ uint16_t Signal;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &Signal) != -1)
+ break;
+ if (errno != EINTR) {
+ Signal = 0xFFFF;
+#ifdef DEBUG_SIGNALSTRENGTH
+ HasSignal = false;
+#endif
+ break;
+ }
+ }
+#ifdef DEBUG_SIGNALSTRENGTH
+ bool HasBer = true;
+#endif
+ uint32_t Ber;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
+ break;
+ if (errno != EINTR) {
+ Ber = 0;
+#ifdef DEBUG_SIGNALSTRENGTH
+ HasBer = false;
+#endif
+ break;
+ }
+ }
+#ifdef DEBUG_SIGNALSTRENGTH
+ bool HasUnc = true;
+#endif
+ uint32_t Unc;
+ while (1) {
+ if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
+ break;
+ if (errno != EINTR) {
+ Unc = 0;
+#ifdef DEBUG_SIGNALSTRENGTH
+ HasUnc = false;
+#endif
+ break;
+ }
+ }
+ uint16_t MinSignal = 0x0000;
+ uint16_t MaxSignal = 0xFFFF; // Let's assume the default is using the entire range.
+ // Use the subsystemId to identify individual devices in case they need
+ // special treatment to map their Snr value into the range 0...0xFFFF.
+ switch (subsystemId) {
+ case 0x13C21019: // TT-budget S2-3200 (DVB-S/DVB-S2)
+ case 0x1AE40001: // TechniSat SkyStar HD2 (DVB-S/DVB-S2)
+ if (frontendType == SYS_DVBS2) {
+ MinSignal = 10;
+ MaxSignal = 70;
+ }
+ else
+// MaxSignal = 200;
+ MaxSignal = 670;
+
+ break;
+ case 0x20130245: // PCTV Systems PCTV 73ESE
+ case 0x2013024F: // PCTV Systems nanoStick T2 290e
+// MaxSignal = 255; break;
+ MaxSignal = 670;
+
+ }
+ int a = int(constrain(Signal, MinSignal, MaxSignal)) * 350 / (MaxSignal - MinSignal);
+ int b = 100 - (Unc * 10 + (Ber / 256) * 5);
+ if (b < 0)
+ b = 0;
+ int s = LOCK_THRESHOLD + a * b * (100 - LOCK_THRESHOLD) / 100 / 100;
+ if (s > 100)
+ s = 100;
+ #ifdef DEBUG_SIGNALSTRENGTH
+ fprintf(stderr, "FE %d/%d: %08X S = %04X %04X %d %5d %5d %3d%%\n", adapter, frontend, subsystemId, MaxSignal, Signal, HasSignal, HasBer ? int(Ber) : -1, HasUnc ? int(Unc) : -1, s);
+#endif
+ return s;
+ }
+ return -1;
}
#define LOCK_THRESHOLD 5 // indicates that all 5 FE_HAS_* flags are set
@@ -655,6 +744,35 @@
return -1;
}
+int cDvbTuner::GetCurrentDeliverySystem()
+{
+ dtv_property Frontend[1];
+ memset(&Frontend, 0, sizeof(Frontend));
+ dtv_properties CmdSeq;
+ memset(&CmdSeq, 0, sizeof(CmdSeq));
+ CmdSeq.props = Frontend;
+ Frontend[0].cmd = DTV_DELIVERY_SYSTEM;
+ Frontend[0].u.data = 0;
+ if (ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq) < 0) {
+ esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ return SYS_UNDEFINED;
+ }
+ return Frontend[0].u.data;
+}
+
+bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd)
+{
+ cMutexLock MutexLock(&mutex);
+ int frontendType = GetCurrentDeliverySystem();
+ if ((frontendType != SYS_DVBS && frontendType != SYS_DVBS2) || SendDiseqc)
+ return false;
+ diseqc_cmd=cmd;
+ SendDiseqc=true;
+ newSet.Broadcast();
+ return true;
+}
+
+
static unsigned int FrequencyToHz(unsigned int f)
{
while (f && f < 1000000)
@@ -719,6 +837,8 @@
bool cDvbTuner::SetFrontend(void)
{
+ if (!OpenFrontend())
+ return false;
#define MAXFRONTENDCMDS 16
#define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\
Frontend[CmdSeq.num].u.data = (d);\
@@ -870,10 +990,16 @@
bool LostLock = false;
fe_status_t Status = (fe_status_t)0;
while (Running()) {
- fe_status_t NewStatus;
- if (GetFrontendStatus(NewStatus))
- Status = NewStatus;
+ if (!isIdle) {
+ fe_status_t NewStatus;
+ if (GetFrontendStatus(NewStatus))
+ Status = NewStatus;
+ }
cMutexLock MutexLock(&mutex);
+ if (SendDiseqc) {
+ CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd));
+ SendDiseqc=false;
+ }
int WaitTime = 1000;
switch (tunerStatus) {
case tsIdle:
@@ -925,6 +1051,40 @@
}
}
+bool cDvbTuner::SetIdle(bool Idle)
+{
+ if (isIdle == Idle)
+ return true;
+ isIdle = Idle;
+ if (Idle)
+ return CloseFrontend();
+ return OpenFrontend();
+}
+
+bool cDvbTuner::OpenFrontend(void) const
+{
+ if (fd_frontend >= 0)
+ return true;
+ cMutexLock MutexLock(&mutex);
+ fd_frontend = cDvbDevice::DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
+ if (fd_frontend < 0)
+ return false;
+ isIdle = false;
+ return true;
+}
+
+bool cDvbTuner::CloseFrontend(void)
+{
+ if (fd_frontend < 0)
+ return true;
+ cMutexLock MutexLock(&mutex);
+ tunerStatus = tsIdle;
+ newSet.Broadcast();
+ close(fd_frontend);
+ fd_frontend = -1;
+ return true;
+}
+
// --- cDvbSourceParam -------------------------------------------------------
class cDvbSourceParam : public cSourceParam {
@@ -1010,7 +1170,8 @@
NULL
};
-cDvbDevice::cDvbDevice(int Adapter, int Frontend)
+cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice)
+:cDevice(ParentDevice)
{
adapter = Adapter;
frontend = Frontend;
@@ -1028,9 +1189,8 @@
// Common Interface:
- fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
- if (fd_ca >= 0)
- ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
+ int fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
+ ciAdapter = cDvbCiAdapter::CreateCiAdapter(parentDevice ? parentDevice : this, fd_ca, adapter, frontend);
// The DVR device (will be opened and closed as needed):
@@ -1274,7 +1434,11 @@
if (d >= 0) {
int ErrorDevice = 0;
if (cDevice *Device1 = cDevice::GetDevice(i)) {
+ if (Device1->HasSubDevice())
+ Device1 = Device1->SubDevice();
if (cDevice *Device2 = cDevice::GetDevice(d)) {
+ if (Device2->HasSubDevice())
+ Device2 = Device2->SubDevice();
if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) {
if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) {
if (!DvbDevice1->Bond(DvbDevice2))
@@ -1308,7 +1472,10 @@
void cDvbDevice::UnBondDevices(void)
{
for (int i = 0; i < cDevice::NumDevices(); i++) {
- if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i)))
+ cDevice *dev = cDevice::GetDevice(i);
+ if (dev && dev->HasSubDevice())
+ dev = dev->SubDevice();
+ if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(dev))
d->UnBond();
}
}
@@ -1362,6 +1529,26 @@
return true;
}
+bool cDvbDevice::SetIdleDevice(bool Idle, bool TestOnly)
+{
+ if (TestOnly) {
+ if (ciAdapter)
+ return ciAdapter->SetIdle(Idle, true);
+ return true;
+ }
+ if (!dvbTuner->SetIdle(Idle))
+ return false;
+ if (ciAdapter && !ciAdapter->SetIdle(Idle, false)) {
+ dvbTuner->SetIdle(!Idle);
+ return false;
+ }
+ if (Idle)
+ StopSectionHandler();
+ else
+ StartSectionHandler();
+ return true;
+}
+
bool cDvbDevice::HasCi(void)
{
return ciAdapter;
@@ -1447,6 +1634,10 @@
bool cDvbDevice::ProvidesSource(int Source) const
{
+ if (Setup.ChannelBlocker == 1) {
+ if (IsPrimaryDevice()) return false;
+ //isyslog("ChannelBlocker aktive on primary Interface");
+ }
int type = Source & cSource::st_Mask;
return type == cSource::stNone
|| type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC)
@@ -1531,7 +1722,7 @@
bool cDvbDevice::ProvidesEIT(void) const
{
- return dvbTuner != NULL;
+ return !IsIdle() && (dvbTuner != NULL) && !dvbTuner->IsIdle() && ((ciAdapter == NULL) || !ciAdapter->IsIdle());
}
int cDvbDevice::NumProvidedSystems(void) const
@@ -1576,6 +1767,11 @@
return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
}
+bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd)
+{
+ return dvbTuner->SendDiseqcCmd(cmd);
+}
+
void cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
{
setTransferModeForDolbyDigital = Mode;
@@ -1585,8 +1781,12 @@
{
CloseDvr();
fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
- if (fd_dvr >= 0)
- tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5), CardIndex() + 1);
+ if (fd_dvr >= 0) {
+ if (ciAdapter)
+ tsBuffer = ciAdapter->GetTSBuffer(fd_dvr);
+ if (tsBuffer == NULL)
+ tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(5), CardIndex() + 1);
+ }
return fd_dvr >= 0;
}