diff options
Diffstat (limited to 'dvbdevice.c')
-rw-r--r-- | dvbdevice.c | 226 |
1 files changed, 146 insertions, 80 deletions
diff --git a/dvbdevice.c b/dvbdevice.c index d69a1340..c93328f5 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 2.50 2011/12/10 14:59:34 kls Exp $ + * $Id: dvbdevice.c 2.51 2012/01/07 10:42:47 kls Exp $ */ #include "dvbdevice.h" @@ -81,9 +81,18 @@ const tDvbParameterMap ModulationValues[] = { { -1, 0, NULL } }; -const tDvbParameterMap SystemValues[] = { - { 0, SYS_DVBS, "DVB-S" }, - { 1, SYS_DVBS2, "DVB-S2" }, +#define DVB_SYSTEM_1 0 // see also nit.c +#define DVB_SYSTEM_2 1 + +const tDvbParameterMap SystemValuesSat[] = { + { 0, DVB_SYSTEM_1, "DVB-S" }, + { 1, DVB_SYSTEM_2, "DVB-S2" }, + { -1, 0, NULL } + }; + +const tDvbParameterMap SystemValuesTerr[] = { + { 0, DVB_SYSTEM_1, "DVB-T" }, + { 1, DVB_SYSTEM_2, "DVB-T2" }, { -1, 0, NULL } }; @@ -179,7 +188,7 @@ cDvbTransponderParameters::cDvbTransponderParameters(const char *Parameters) coderateH = FEC_AUTO; coderateL = FEC_AUTO; modulation = QPSK; - system = SYS_DVBS; + system = DVB_SYSTEM_1; transmission = TRANSMISSION_MODE_AUTO; guard = GUARD_INTERVAL_AUTO; hierarchy = HIERARCHY_AUTO; @@ -206,7 +215,7 @@ cString cDvbTransponderParameters::ToString(char Type) const ST("ACST") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues)); ST("ACST") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues)); ST(" S ") q += PrintParameter(q, 'O', MapToUser(rollOff, RollOffValues)); - ST(" S ") q += PrintParameter(q, 'S', MapToUser(system, SystemValues)); + ST(" S ") q += PrintParameter(q, 'S', MapToUser(system, SystemValuesSat)); // we only need the numerical value, so Sat or Terr doesn't matter ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); return buffer; @@ -242,7 +251,7 @@ bool cDvbTransponderParameters::Parse(const char *s) case 'M': s = ParseParameter(s, modulation, ModulationValues); break; case 'O': s = ParseParameter(s, rollOff, RollOffValues); break; case 'R': polarization = *s++; break; - case 'S': s = ParseParameter(s, system, SystemValues); break; + case 'S': s = ParseParameter(s, system, SystemValuesSat); break; // we only need the numerical value, so Sat or Terr doesn't matter case 'T': s = ParseParameter(s, transmission, TransmissionValues); break; case 'V': polarization = *s++; break; case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break; @@ -268,10 +277,10 @@ private: int tuneTimeout; int lockTimeout; time_t lastTimeoutReport; - fe_delivery_system frontendType; cChannel channel; const cDiseqc *lastDiseqc; const cScr *scr; + bool lnbPowerTurnedOn; eTunerStatus tunerStatus; cMutex mutex; cCondVar locked; @@ -279,6 +288,7 @@ private: cDvbTuner *bondedTuner; bool bondedMaster; bool bondedMasterFailed; + bool SetFrontendType(const cChannel *Channel); cString GetBondingParams(const cChannel *Channel = NULL) const; void ClearEventQueue(void) const; bool GetFrontendStatus(fe_status_t &Status) const; @@ -287,7 +297,7 @@ private: bool SetFrontend(void); virtual void Action(void); public: - cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType); + cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend); virtual ~cDvbTuner(); bool Bond(cDvbTuner *Tuner); void UnBond(void); @@ -304,25 +314,23 @@ public: cMutex cDvbTuner::bondMutex; -cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType) +cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend) { device = Device; fd_frontend = Fd_Frontend; adapter = Adapter; frontend = Frontend; - frontendType = FrontendType; subsystemId = cDvbDeviceProbe::GetSubsystemId(adapter, frontend); tuneTimeout = 0; lockTimeout = 0; lastTimeoutReport = 0; lastDiseqc = NULL; scr = NULL; + lnbPowerTurnedOn = false; tunerStatus = tsIdle; bondedTuner = NULL; bondedMaster = false; bondedMasterFailed = false; - if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) - ResetToneAndVoltage(); // must explicitly turn on LNB power SetDescription("tuner on frontend %d/%d", adapter, frontend); Start(); } @@ -346,16 +354,12 @@ bool cDvbTuner::Bond(cDvbTuner *Tuner) { cMutexLock MutexLock(&bondMutex); if (!bondedTuner) { - if ((frontendType == SYS_DVBS || frontendType == SYS_DVBS2) && (Tuner->frontendType == SYS_DVBS || Tuner->frontendType == SYS_DVBS2)) { - ResetToneAndVoltage(); - bondedMaster = false; // makes sure we don't disturb an existing master - bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner; - Tuner->bondedTuner = this; - dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend); - return true; - } - else - esyslog("ERROR: can't bond tuner %d/%d with tuner %d/%d (only DVB-S(2) tuners can be bonded)", adapter, frontend, Tuner->adapter, Tuner->frontend); + ResetToneAndVoltage(); + bondedMaster = false; // makes sure we don't disturb an existing master + bondedTuner = Tuner->bondedTuner ? Tuner->bondedTuner : Tuner; + Tuner->bondedTuner = this; + dsyslog("tuner %d/%d bonded with tuner %d/%d", adapter, frontend, bondedTuner->adapter, bondedTuner->frontend); + return true; } else 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); @@ -634,6 +638,10 @@ static unsigned int FrequencyToHz(unsigned int f) void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency) { + if (!lnbPowerTurnedOn) { + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power + lnbPowerTurnedOn = true; + } struct dvb_diseqc_master_cmd cmd; const char *CurrentAction = NULL; for (;;) { @@ -662,6 +670,22 @@ void cDvbTuner::ResetToneAndVoltage(void) CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); } +static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTransponderParameters *Dtp) +{ + int ds = SYS_UNDEFINED; + if (Channel->IsAtsc()) + ds = SYS_ATSC; + else if (Channel->IsCable()) + ds = SYS_DVBC_ANNEX_AC; + else if (Channel->IsSat()) + ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBS : SYS_DVBS2; + else if (Channel->IsTerr()) + ds = Dtp->System() == DVB_SYSTEM_1 ? SYS_DVBT : SYS_DVBT2; + else + esyslog("ERROR: can't determine frontend type for channel %d", Channel->Number()); + return ds; +} + bool cDvbTuner::SetFrontend(void) { #define MAXFRONTENDCMDS 16 @@ -686,6 +710,12 @@ bool cDvbTuner::SetFrontend(void) cDvbTransponderParameters dtp(channel.Parameters()); + // Determine the required frontend type: + int frontendType = GetRequiredDeliverySystem(&channel, &dtp); + if (frontendType == SYS_UNDEFINED) + return false; + + SETCMD(DTV_DELIVERY_SYSTEM, frontendType); if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) { unsigned int frequency = channel.Frequency(); if (Setup.DiSEqC) { @@ -728,22 +758,15 @@ bool cDvbTuner::SetFrontend(void) frequency = abs(frequency); // Allow for C-band, where the frequency is less than the LOF // DVB-S/DVB-S2 (common parts) - SETCMD(DTV_DELIVERY_SYSTEM, dtp.System()); SETCMD(DTV_FREQUENCY, frequency * 1000UL); SETCMD(DTV_MODULATION, dtp.Modulation()); SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL); SETCMD(DTV_INNER_FEC, dtp.CoderateH()); SETCMD(DTV_INVERSION, dtp.Inversion()); - if (dtp.System() == SYS_DVBS2) { - if (frontendType == SYS_DVBS2) { - // DVB-S2 - SETCMD(DTV_PILOT, PILOT_AUTO); - SETCMD(DTV_ROLLOFF, dtp.RollOff()); - } - else { - esyslog("ERROR: frontend %d/%d doesn't provide DVB-S2", adapter, frontend); - return false; - } + if (frontendType == SYS_DVBS2) { + // DVB-S2 + SETCMD(DTV_PILOT, PILOT_AUTO); + SETCMD(DTV_ROLLOFF, dtp.RollOff()); } else { // DVB-S @@ -755,7 +778,6 @@ bool cDvbTuner::SetFrontend(void) } else if (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) { // DVB-C - SETCMD(DTV_DELIVERY_SYSTEM, frontendType); SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); SETCMD(DTV_INVERSION, dtp.Inversion()); SETCMD(DTV_SYMBOL_RATE, channel.Srate() * 1000UL); @@ -767,7 +789,6 @@ bool cDvbTuner::SetFrontend(void) } else if (frontendType == SYS_DVBT) { // DVB-T - SETCMD(DTV_DELIVERY_SYSTEM, frontendType); SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); SETCMD(DTV_INVERSION, dtp.Inversion()); SETCMD(DTV_BANDWIDTH_HZ, dtp.Bandwidth()); @@ -783,7 +804,6 @@ bool cDvbTuner::SetFrontend(void) } else if (frontendType == SYS_ATSC) { // ATSC - SETCMD(DTV_DELIVERY_SYSTEM, frontendType); SETCMD(DTV_FREQUENCY, FrequencyToHz(channel.Frequency())); SETCMD(DTV_INVERSION, dtp.Inversion()); SETCMD(DTV_MODULATION, dtp.Modulation()); @@ -903,6 +923,7 @@ void cDvbSourceParam::GetData(cChannel *Channel) cOsdItem *cDvbSourceParam::GetOsdItem(void) { char type = Source(); + const tDvbParameterMap *SystemValues = type == 'S' ? SystemValuesSat : SystemValuesTerr; #undef ST #define ST(s) if (strchr(s, type)) switch (param++) { @@ -928,7 +949,7 @@ cOsdItem *cDvbSourceParam::GetOsdItem(void) int cDvbDevice::setTransferModeForDolbyDigital = 1; cMutex cDvbDevice::bondMutex; -const char *DeliverySystems[] = { +const char *DeliverySystemNames[] = { "UNDEFINED", "DVB-C", "DVB-C", @@ -945,6 +966,8 @@ const char *DeliverySystems[] = { "DMBTH", "CMMB", "DAB", + "DVB-T2", + "TURBO", NULL }; @@ -954,8 +977,8 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend) frontend = Frontend; ciAdapter = NULL; dvbTuner = NULL; - frontendType = SYS_UNDEFINED; - numProvidedSystems = 0; + numDeliverySystems = 0; + numModulations = 0; bondedDevice = NULL; needsDetachBondedReceivers = false; @@ -976,39 +999,8 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend) // We only check the devices that must be present - the others will be checked before accessing them://XXX if (fd_frontend >= 0) { - if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) >= 0) { - switch (frontendInfo.type) { - case FE_QPSK: frontendType = (frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break; - case FE_OFDM: frontendType = SYS_DVBT; break; - case FE_QAM: frontendType = SYS_DVBC_ANNEX_AC; break; - case FE_ATSC: frontendType = SYS_ATSC; break; - default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend); - } - } - else - LOG_ERROR; - if (frontendType != SYS_UNDEFINED) { - numProvidedSystems++; - if (frontendType == SYS_DVBS2) - numProvidedSystems++; - char Modulations[64]; - char *p = Modulations; - if (frontendInfo.caps & FE_CAN_QPSK) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QPSK, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_QAM_16) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_16, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_QAM_32) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_32, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_QAM_64) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_64, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_QAM_128) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_128, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_QAM_256) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_256, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_8VSB) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_8, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_16VSB) { numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_16, ModulationValues)); } - if (frontendInfo.caps & FE_CAN_TURBO_FEC){numProvidedSystems++; p += sprintf(p, ",%s", "TURBO_FEC"); } - if (p != Modulations) - p = Modulations + 1; // skips first ',' - else - p = (char *)"unknown modulations"; - isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], p, frontendInfo.name); - dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend, frontendType); - } + if (QueryDeliverySystems(fd_frontend)) + dvbTuner = new cDvbTuner(this, fd_frontend, adapter, frontend); } else esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend); @@ -1106,6 +1098,71 @@ LastAdapter: return Found > 0; } +bool cDvbDevice::QueryDeliverySystems(int fd_frontend) +{ + numDeliverySystems = 0; + if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) < 0) { + LOG_ERROR; + return false; + } +#if DVB_API_VERSION > 5 || DVB_API_VERSION_MINOR >= 5 + dtv_property Frontend[1]; + memset(&Frontend, 0, sizeof(Frontend)); + dtv_properties CmdSeq; + memset(&CmdSeq, 0, sizeof(CmdSeq)); + CmdSeq.props = Frontend; + SETCMD(DTV_ENUM_DELSYS, 0); + int Result = ioctl(fd_frontend, FE_GET_PROPERTY, &CmdSeq); + if (Result == 0) { + for (uint i = 0; i < Frontend[0].u.buffer.len; i++) { + if (numDeliverySystems >= MAXDELIVERYSYSTEMS) { + esyslog("ERROR: too many delivery systems on frontend %d/%d", adapter, frontend); + break; + } + deliverySystems[numDeliverySystems++] = Frontend[0].u.buffer.data[i]; + } + } + else { + esyslog("ERROR: can't query delivery systems on frontend %d/%d - falling back to legacy mode", adapter, frontend); +#else + { +#endif + // Legacy mode (DVB-API < 5.5): + switch (frontendInfo.type) { + case FE_QPSK: deliverySystems[numDeliverySystems++] = SYS_DVBS; + if (frontendInfo.caps & FE_CAN_2G_MODULATION) + deliverySystems[numDeliverySystems++] = SYS_DVBS2; + break; + case FE_OFDM: deliverySystems[numDeliverySystems++] = SYS_DVBT; break; + case FE_QAM: deliverySystems[numDeliverySystems++] = SYS_DVBC_ANNEX_AC; break; + case FE_ATSC: deliverySystems[numDeliverySystems++] = SYS_ATSC; break; + default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend); + } + } + if (numDeliverySystems > 0) { + cString ds(""); + for (int i = 0; i < numDeliverySystems; i++) + ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", DeliverySystemNames[deliverySystems[i]]); + cString ms(""); + if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_QAM_32) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_32, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_QAM_64) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_64, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_QAM_128) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_128, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_QAM_256) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_256, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_8VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_8, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_16VSB) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(VSB_16, ModulationValues)); } + if (frontendInfo.caps & FE_CAN_TURBO_FEC) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", "TURBO_FEC"); } + if (!**ms) + ms = "unknown modulations"; + isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, *ds, *ms, frontendInfo.name); + return true; + } + else + esyslog("ERROR: frontend %d/%d doesn't provide any delivery systems", adapter, frontend); + return false; +} + bool cDvbDevice::Ready(void) { if (ciAdapter) @@ -1167,7 +1224,7 @@ bool cDvbDevice::Bond(cDvbDevice *Device) cMutexLock MutexLock(&bondMutex); if (!bondedDevice) { if (Device != this) { - if ((frontendType == SYS_DVBS || frontendType == SYS_DVBS2) && (Device->frontendType == SYS_DVBS || Device->frontendType == SYS_DVBS2)) { + if ((ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) && (Device->ProvidesDeliverySystem(SYS_DVBS) || Device->ProvidesDeliverySystem(SYS_DVBS2))) { if (dvbTuner && Device->dvbTuner && dvbTuner->Bond(Device->dvbTuner)) { bondedDevice = Device->bondedDevice ? Device->bondedDevice : Device; Device->bondedDevice = this; @@ -1285,14 +1342,23 @@ void cDvbDevice::CloseFilter(int Handle) close(Handle); } +bool cDvbDevice::ProvidesDeliverySystem(int DeliverySystem) const +{ + for (int i = 0; i < numDeliverySystems; i++) { + if (deliverySystems[i] == DeliverySystem) + return true; + } + return false; +} + bool cDvbDevice::ProvidesSource(int Source) const { int type = Source & cSource::st_Mask; return type == cSource::stNone - || type == cSource::stAtsc && (frontendType == SYS_ATSC) - || type == cSource::stCable && (frontendType == SYS_DVBC_ANNEX_AC || frontendType == SYS_DVBC_ANNEX_B) - || type == cSource::stSat && (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) - || type == cSource::stTerr && (frontendType == SYS_DVBT); + || type == cSource::stAtsc && ProvidesDeliverySystem(SYS_ATSC) + || type == cSource::stCable && (ProvidesDeliverySystem(SYS_DVBC_ANNEX_AC) || ProvidesDeliverySystem(SYS_DVBC_ANNEX_B)) + || type == cSource::stSat && (ProvidesDeliverySystem(SYS_DVBS) || ProvidesDeliverySystem(SYS_DVBS2)) + || type == cSource::stTerr && ProvidesDeliverySystem(SYS_DVBT); } bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const @@ -1300,7 +1366,7 @@ bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const if (!ProvidesSource(Channel->Source())) return false; // doesn't provide source cDvbTransponderParameters dtp(Channel->Parameters()); - if (dtp.System() == SYS_DVBS2 && frontendType == SYS_DVBS || + if (!ProvidesDeliverySystem(GetRequiredDeliverySystem(Channel, &dtp)) || dtp.Modulation() == QPSK && !(frontendInfo.caps & FE_CAN_QPSK) || dtp.Modulation() == QAM_16 && !(frontendInfo.caps & FE_CAN_QAM_16) || dtp.Modulation() == QAM_32 && !(frontendInfo.caps & FE_CAN_QAM_32) || @@ -1375,7 +1441,7 @@ bool cDvbDevice::ProvidesEIT(void) const int cDvbDevice::NumProvidedSystems(void) const { - return numProvidedSystems; + return numDeliverySystems + numModulations; } int cDvbDevice::SignalStrength(void) const |