From patchwork Mon Oct 15 19:37:07 2007 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jdobry@centrum.cz X-Patchwork-Id: 12532 Received: from mail1011.centrum.cz ([213.29.7.122]) by www.linuxtv.org with esmtp (Exim 4.63) (envelope-from ) id 1IhVkW-0003q2-7b for vdr@linuxtv.org; Mon, 15 Oct 2007 21:37:12 +0200 Received: by mail1011.centrum.cz id S537204817AbXJOThH (ORCPT ); Mon, 15 Oct 2007 21:37:07 +0200 Received: from 194.228.39.89 (X-Forwarded-For: 192.168.62.2) by mail1011.centrum.cz (Centrum Mail) with HTTP Date: Mon, 15 Oct 2007 21:37:07 +0200 From: To: X-Mailer: Centrum Mail 1.0 MIME-Version: 1.0 X-Priority: 3 Message-ID: <200710152137.6456@centrum.cz> References: In-Reply-To: Subject: Re: [vdr] Concurrent LNB-patch for 1.5? X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.9 Precedence: list Reply-To: VDR Mailing List List-Id: VDR Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Oct 2007 20:10:47 -0000 Status: O X-Status: X-Keywords: X-UID: 14249 Hi, Patch you can find in attachment. Please confirm functionality and write about this into maillist. Regards, Jiri PS: I am not author. I just modify it for vdr 1.5.10 diff -u4 old/config.c vdr-1.5.10/config.c --- old/config.c 2007-10-06 16:28:58.000000000 +0200 +++ vdr-1.5.10/config.c 2007-10-15 20:51:14.000000000 +0200 @@ -288,8 +288,12 @@ CurrentVolume = MAXVOLUME; CurrentDolby = 0; InitialChannel = 0; InitialVolume = -1; +#ifdef USE_LNBSHARE + VerboseLNBlog = 0; + for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; +#endif /* LNBSHARE */ } cSetup& cSetup::operator= (const cSetup &s) { @@ -464,9 +468,25 @@ else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); else +#ifdef USE_LNBSHARE + if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); + else { + char tmp[20]; + bool result = false; + for (int i = 1; i <= MAXDEVICES; i++) { + sprintf(tmp, "Card%dusesLNBnr", i); + if (!strcasecmp(Name, tmp)) { + CardUsesLNBnr[i - 1] = atoi(Value); + result = true; + } + } + return result; + } +#else return false; +#endif /* LNBSHARE */ return true; } bool cSetup::Save(void) @@ -545,8 +565,18 @@ Store("CurrentVolume", CurrentVolume); Store("CurrentDolby", CurrentDolby); Store("InitialChannel", InitialChannel); Store("InitialVolume", InitialVolume); +#ifdef USE_LNBSHARE + Store("VerboseLNBlog", VerboseLNBlog); + char tmp[20]; + if (cDevice::NumDevices() > 1) { + for (int i = 1; i <= cDevice::NumDevices(); i++) { + sprintf(tmp, "Card%dusesLNBnr", i); + Store(tmp, CardUsesLNBnr[i - 1]); + } + } +#endif /* LNBSHARE */ Sort(); if (cConfig::Save()) { diff -u4 old/config.h vdr-1.5.10/config.h --- old/config.h 2007-10-06 16:27:18.000000000 +0200 +++ vdr-1.5.10/config.h 2007-10-15 20:51:14.000000000 +0200 @@ -43,8 +43,14 @@ #define MAXOSDWIDTH 672 #define MINOSDHEIGHT 324 #define MAXOSDHEIGHT 567 +#ifdef USE_LNBSHARE +#ifndef MAXDEVICES +#define MAXDEVICES 16 // the maximum number of devices in the system +#endif +#endif /* LNBSHARE */ + #define MaxFileName 256 #define MaxSkinName 16 #define MaxThemeName 16 @@ -265,8 +271,12 @@ int CurrentVolume; int CurrentDolby; int InitialChannel; int InitialVolume; +#ifdef USE_LNBSHARE + int VerboseLNBlog; + int CardUsesLNBnr[MAXDEVICES]; +#endif /* LNBSHARE */ int __EndData__; cSetup(void); cSetup& operator= (const cSetup &s); bool Load(const char *FileName); diff -u4 old/device.c vdr-1.5.10/device.c --- old/device.c 2007-10-14 15:09:19.000000000 +0200 +++ vdr-1.5.10/device.c 2007-10-15 20:51:14.000000000 +0200 @@ -87,8 +87,12 @@ } } } +#ifdef USE_LNBSHARE +#include "diseqc.h" +#endif /* LNBSHARE */ + // --- cPesAssembler --------------------------------------------------------- class cPesAssembler { private: @@ -223,8 +227,14 @@ SetDescription("receiver on device %d", CardIndex() + 1); SetVideoFormat(Setup.VideoFormat); +#ifdef USE_LNBSHARE + LNBstate = -1; + LNBnr = Setup.CardUsesLNBnr[cardIndex]; + LNBsource = NULL; +#endif /* LNBSHARE */ + mute = false; volume = Setup.CurrentVolume; sectionHandler = NULL; @@ -290,8 +300,18 @@ if (n < MAXDEVICES) useDevice |= (1 << n); } +#ifdef USE_LNBSHARE +void cDevice::SetLNBnr(void) +{ + for (int i = 0; i < numDevices; i++) { + device[i]->LNBnr = Setup.CardUsesLNBnr[i]; + isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); + } +} +#endif /* LNBSHARE */ + int cDevice::NextCardIndex(int n) { if (n > 0) { nextCardIndex += n; @@ -350,8 +370,100 @@ d = PrimaryDevice(); return d; } +#ifdef USE_LNBSHARE +cDevice *cDevice::GetBadDevice(const cChannel *Channel) +{ + if (!cSource::IsSat(Channel->Source())) return NULL; + if (Setup.DiSEqC) { + cDiseqc *diseqc; + diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); + } + return device[i]; + } + } + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); + } + } else { + char requiredState; + if (Channel->Frequency() >= Setup.LnbSLOF) { + requiredState = 1 ; + } else { + requiredState = 0; + } + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); + } + return device[i]; + } + } + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); + } + } + return NULL; +} + +int cDevice::GetMaxBadPriority(const cChannel *Channel) +{ + if (!cSource::IsSat(Channel->Source())) return -2; + bool PrimaryIsBad = false; + int maxBadPriority = -2; + if (Setup.DiSEqC) { + cDiseqc *diseqc; + diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { + if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) { + maxBadPriority = device[i]->Priority(); + } + if (device[i]->IsPrimaryDevice()) { + PrimaryIsBad = true; + } + } + } + } else { + char requiredState; + if (Channel->Frequency() >= Setup.LnbSLOF) { + requiredState = 1 ; + } else { + requiredState = 0; + } + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { + if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) { + maxBadPriority = device[i]->Priority(); + } + if (device[i]->IsPrimaryDevice()) { + PrimaryIsBad = true; + } + } + } + } + if (PrimaryIsBad && maxBadPriority == -2) { + maxBadPriority = -1; + } + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); + } + return maxBadPriority; +} +#endif /* LNBSHARE */ + cDevice *cDevice::GetDevice(int Index) { return (0 <= Index && Index < numDevices) ? device[Index] : NULL; } @@ -382,8 +494,12 @@ cDevice *d = NULL; cCamSlot *s = NULL; uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact +#ifdef USE_LNBSHARE + int badPriority; + uint imp2; +#endif /* LNBSHARE */ for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) continue; // there is no CAM available in this slot for (int i = 0; i < numDevices; i++) { @@ -412,9 +528,32 @@ imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel +#ifdef USE_LNBSHARE + badPriority = device[i]->GetMaxBadPriority(Channel); + if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { + // channel is not available for the requested prioity + imp = 0xFFFFFFFF; + } else { + switch (badPriority) { + case -2: // not affected by LNB-sharing + imp2 = 0; + break; + case -1: // the primary device would need a channel switch + imp += 1 << 17; + imp2 = 0xFFFFFFFF | 1 << 17; + break; + default: // a device receiving with lower priority would need to be stopped + imp += badPriority << 8; + imp2 = 0xFFFFFFFF | badPriority << 8; + break; + } + } + if (imp < Impact && imp2 < Impact) { +#else if (imp < Impact) { +#endif /* LNBSHARE */ // This device has less impact than any previous one, so we take it. Impact = imp; d = device[i]; NeedsDetachReceivers = ndr; @@ -681,9 +820,13 @@ bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const { for (int i = 0; i < numDevices; i++) { +#ifdef USE_LNBSHARE + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) +#else if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) +#endif /* LNBSHARE */ return false; } return true; } @@ -704,8 +847,26 @@ } bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) { +#ifdef USE_LNBSHARE + cDevice *tmpDevice; + if (this->GetMaxBadPriority(Channel) >= 0) { + Skins.Message(mtInfo, tr("Channel locked by LNB!")); + return false; + } + while ((tmpDevice = GetBadDevice(Channel)) != NULL) { + if (tmpDevice->IsPrimaryDevice() && LiveView) + tmpDevice->SwitchChannelForced(Channel, true); + else + tmpDevice->SwitchChannelForced(Channel, false); + } + return SwitchChannelForced(Channel, LiveView); +} + +bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) +{ +#endif /* LNBSHARE */ if (LiveView) { isyslog("switching to channel %d", Channel->Number()); cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer } @@ -733,9 +894,13 @@ int first = n; cChannel *channel; while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { // try only channels which are currently available +#ifdef USE_LNBSHARE + if (PrimaryDevice()->GetMaxBadPriority(channel) < 0 && (GetDevice(channel, 0, true))) +#else if (GetDevice(channel, 0, true)) +#endif /* LNBSHARE */ break; n = channel->Number() + Direction; } if (channel) { @@ -766,13 +931,39 @@ bool NeedsTransferMode = Device != this; eSetChannelResult Result = scrOk; +#ifdef USE_LNBSHARE + char requiredState; + if (Channel->Frequency() >= Setup.LnbSLOF) { + requiredState = 1; + } else { + requiredState = 0; + } + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') requiredState += 2; + if (Setup.VerboseLNBlog) { + isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); + } +#endif /* LNBSHARE */ + // If this DVB card can't receive this channel, let's see if we can // use the card that actually can receive it and transfer data from there: if (NeedsTransferMode) { if (Device && CanReplay()) { +#ifdef USE_LNBSHARE + if (Device->GetLNBnr() == LNBnr) { + if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { + if (IsPrimaryDevice()) { + SetChannelDevice(Channel, true); + } else { + SetChannelDevice(Channel, false); + } + LNBstate = requiredState; + LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + } + } +#endif /* LNBSHARE */ cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! cControl::Launch(new cTransferControl(Device, Channel->GetChannelID(), Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); else @@ -788,8 +979,12 @@ if (sectionHandler) { sectionHandler->SetStatus(false); sectionHandler->SetChannel(NULL); } +#ifdef USE_LNBSHARE + LNBstate = requiredState; + LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); +#endif /* LNBSHARE */ // Tell the camSlot about the channel switch and add all PIDs of this // channel to it, for possible later decryption: if (camSlot) camSlot->AddChannel(Channel); diff -u4 old/device.h vdr-1.5.10/device.h --- old/device.h 2007-10-14 15:09:12.000000000 +0200 +++ vdr-1.5.10/device.h 2007-10-15 20:51:14.000000000 +0200 @@ -144,8 +144,33 @@ ///< after detaching any receivers because the channel can't be decrypted, ///< this device/CAM combination will be skipped in the next call to ///< GetDevice(). ///< See also ProvidesChannel(). +#ifdef USE_LNBSHARE +private: + char LNBstate; // Current frequency band and polarization of the DVB-tuner +// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: + int *LNBsource; // [DiSEqC] DiSEqC-Source + int LNBnr; // Number of LNB used +public: + char GetLNBconf(void) { return LNBstate; } + int *GetLNBsource(void) { return LNBsource; } + int GetLNBnr(void) { return LNBnr; } + static void SetLNBnr(void); + cDevice *GetBadDevice(const cChannel *Channel); + ///< Returns NULL if there is no device which uses the same LNB or if + ///< all of those devices are tuned to the same frequency band and + ///< polarization as of the requested channel. + ///< Otherwise returns the first device found. + int GetMaxBadPriority(const cChannel *Channel); + ///< Returns the highest priority of all receiving devices which use + ///< the same LNB and are tuned to a different frequency band or + ///< polarization as of the requested channel. + ///< Returns -1 if there are no such devices, but the primary device + ///< would be affected by switching to the requested channel. + ///< Returns -2 if there are no such devices and the primary device + ///< would not be affected by switching to the requested channel. +#endif /* LNBSHARE */ static void Shutdown(void); ///< Closes down all devices. ///< Must be called at the end of the program. private: @@ -232,8 +257,15 @@ ///< without disturbing any other activities. bool SwitchChannel(const cChannel *Channel, bool LiveView); ///< Switches the device to the given Channel, initiating transfer mode ///< if necessary. + +#ifdef USE_LNBSHARE + bool SwitchChannelForced(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given channel, initiating transfer mode + ///< if necessary. Forces the switch without taking care of the LNB configuration. +#endif /* LNBSHARE */ + static bool SwitchChannel(int Direction); ///< Switches the primary device to the next available channel in the given ///< Direction (only the sign of Direction is evaluated, positive values ///< switch to higher channel numbers). diff -u4 old/eitscan.c vdr-1.5.10/eitscan.c --- old/eitscan.c 2006-01-07 15:10:17.000000000 +0100 +++ vdr-1.5.10/eitscan.c 2007-10-15 20:51:14.000000000 +0200 @@ -150,11 +150,19 @@ if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) { if (Device->ProvidesTransponder(Channel)) { if (!Device->Receiving()) { bool MaySwitchTransponder = Device->MaySwitchTransponder(); +#ifdef USE_LNBSHARE + if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { +#else if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { +#endif /* LNBSHARE */ if (!MaySwitchTransponder) { +#ifdef USE_LNBSHARE + if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { +#else if (Device == cDevice::ActualDevice() && !currentChannel) { +#endif /* LNBSHARE */ cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode currentChannel = Device->CurrentChannel(); Skins.Message(mtInfo, tr("Starting EPG scan")); } diff -u4 old/Make.config.template vdr-1.5.10/Make.config.template --- old/Make.config.template 2007-08-25 10:53:45.000000000 +0200 +++ vdr-1.5.10/Make.config.template 2007-10-15 20:51:14.000000000 +0200 @@ -40,9 +40,15 @@ ## Define if you want vdr to not run as root #VDR_USER = vdr +LNBSHARE = 1 + ### You don't need to touch the following: ifdef DVBDIR INCLUDES += -I$(DVBDIR)/include endif +ifdef LNBSHARE +DEFINES += -DUSE_LNBSHARE +endif + diff -u4 old/menu.c vdr-1.5.10/menu.c --- old/menu.c 2007-10-13 12:10:20.000000000 +0200 +++ vdr-1.5.10/menu.c 2007-10-15 20:51:14.000000000 +0200 @@ -2554,8 +2554,25 @@ int current = Current(); Clear(); +#ifdef USE_LNBSHARE + int numSatDevices = 0; + for (int i = 0; i < cDevice::NumDevices(); i++) { + if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; + } + if (numSatDevices > 1) { + char tmp[30]; + for (int i = 1; i <= cDevice::NumDevices(); i++) { + if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { + sprintf( tmp, tr("Setup.LNB$DVB device %d uses LNB No."), i); + Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); + } + } + } + Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); +#endif /* LNBSHARE */ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); if (!data.DiSEqC) { Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); @@ -2570,8 +2587,12 @@ { int oldDiSEqC = data.DiSEqC; eOSState state = cMenuSetupBase::ProcessKey(Key); +#ifdef USE_LNBSHARE + if (Key == kOk) cDevice::SetLNBnr(); +#endif /* LNBSHARE */ + if (Key != kNone && data.DiSEqC != oldDiSEqC) Setup(); return state; } @@ -3271,9 +3292,13 @@ { if (Direction) { while (Channel) { Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); +#ifdef USE_LNBSHARE + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true) && cDevice::PrimaryDevice()->GetMaxBadPriority(Channel) < 0) +#else if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) +#endif /* LNBSHARE */ return Channel; } } return NULL; @@ -3893,8 +3918,21 @@ if (channel) { int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; cDevice *device = cDevice::GetDevice(channel, Priority, false); if (device) { +#ifdef USE_LNBSHARE + cDevice *tmpDevice; + while ((tmpDevice = device->GetBadDevice(channel))) { + if (tmpDevice->Replaying() == false) { +// Stop(tmpDevice); + if (tmpDevice->IsPrimaryDevice() ) + tmpDevice->SwitchChannelForced(channel, true); + else + tmpDevice->SwitchChannelForced(channel, false); + } else + tmpDevice->SwitchChannelForced(channel, false); + } +#endif /* LNBSHARE */ dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); if (!device->SwitchChannel(channel, false)) { ShutdownHandler.RequestEmergencyExit(); return false;