Device power saving feature
Commit Message
Hi folks.
This patch introduces a feature which allows an idle device (a device
which is not currently recording or streaming) to enter a power-down
mode after some period of time. Given two timeout values,
PowerdownTimeoutM and PowerdownWakeupH, it works like this: when a
device becomes idle, it is kept powered up for PowerdownTimeoutM minutes
doing, for instance, an EPG scan before it is powered down. If the
device is still idle and has been powered down for PowerdownWakeupH
hours it is powered up for PowerdownTimeoutM minutes and so on. When
recording, streaming or a forced EPG scan starts, the device is powered
up and it's idle timer is disabled. This implies that PowerdownTimeoutM
should be enough for a full round of EPG scanning (20 seconds *
number_of_transponders). Another option is to run EPG scans from cron
(at night) and use SVDRP SCAN command.
Actual implementation of power saving facilities is left to a derived
device class. In the case of a DVB device it is implemented by closing
it's frontend device. For a DVB-S/S2 tuner this usually means powering
the LNB off. My measurements show 3-4W power consumption drops per tuner
for various DVB-S/S2 tuners. So, this feature (together with HDD
spin-down) is especially valuable while running a headless 24/7 VDR
server and/or using several tuners. A SATIP device can also implement
power saving if it is supported by a server.
I know about the dynamite plugin, but 1) it does much more then this, 2)
still requires a VDR patch, which is bigger, 3) doesn't work reliably
for me and 4) I think this functionality should be part of the VDR
core.
A copy of the patch is here:
http://pastebin.com/FRi0kTjf
Please review,
Sergey Chernyavskiy.
---
config.c | 9 ++++++
config.h | 3 ++
device.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
device.h | 29 +++++++++++++++++++
dvbdevice.c | 39 +++++++++++++++++++++++++
dvbdevice.h | 7 +++++
eitscan.c | 7 ++++-
menu.c | 9 +++++-
vdr.c | 6 ++++
9 files changed, 201 insertions(+), 4 deletions(-)
Comments
Interesting.
How long have you been running it / testing it?
Have you tested with VPS timers enabled ?
Thanks
Richard
On 26/05/2016 16:36, glenvt18 wrote:
> Hi folks.
>
> This patch introduces a feature which allows an idle device (a device
> which is not currently recording or streaming) to enter a power-down
> mode after some period of time. Given two timeout values,
> PowerdownTimeoutM and PowerdownWakeupH, it works like this: when a
> device becomes idle, it is kept powered up for PowerdownTimeoutM minutes
> doing, for instance, an EPG scan before it is powered down. If the
> device is still idle and has been powered down for PowerdownWakeupH
> hours it is powered up for PowerdownTimeoutM minutes and so on. When
> recording, streaming or a forced EPG scan starts, the device is powered
> up and it's idle timer is disabled. This implies that PowerdownTimeoutM
> should be enough for a full round of EPG scanning (20 seconds *
> number_of_transponders). Another option is to run EPG scans from cron
> (at night) and use SVDRP SCAN command.
For about a month now. Tested with 3 different DVB-S/S2 tuners with
VDR 2.3.1 and VDR 2.2.0 (requires minor changes to the patch) - rock
solid.
I don't have VPS, so I can't test it. The same is about DVB-T/C
tuners. After all, if something doesn't work this feature can be
disabled (and it is disabled by default),
Best,
Sergey Chernyavskiy.
2016-05-26 20:15 GMT+03:00 Richard F <lists@keynet-technology.com>:
> Interesting.
> How long have you been running it / testing it?
> Have you tested with VPS timers enabled ?
>
> Thanks
> Richard
>
> On 26/05/2016 16:36, glenvt18 wrote:
>> Hi folks.
>>
>> This patch introduces a feature which allows an idle device (a device
>> which is not currently recording or streaming) to enter a power-down
>> mode after some period of time. Given two timeout values,
>> PowerdownTimeoutM and PowerdownWakeupH, it works like this: when a
>> device becomes idle, it is kept powered up for PowerdownTimeoutM minutes
>> doing, for instance, an EPG scan before it is powered down. If the
>> device is still idle and has been powered down for PowerdownWakeupH
>> hours it is powered up for PowerdownTimeoutM minutes and so on. When
>> recording, streaming or a forced EPG scan starts, the device is powered
>> up and it's idle timer is disabled. This implies that PowerdownTimeoutM
>> should be enough for a full round of EPG scanning (20 seconds *
>> number_of_transponders). Another option is to run EPG scans from cron
>> (at night) and use SVDRP SCAN command.
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
I'd like to give it a go on DVB & DVBT-2 tuners (1 PCI, 1 USB)
Would you be kind enough to post a version for VDR2.20 or advise changes
necessary?
Thanks
Richard
On 26/05/2016 18:44, glenvt18 wrote:
> For about a month now. Tested with 3 different DVB-S/S2 tuners with
> VDR 2.3.1 and VDR 2.2.0 (requires minor changes to the patch) - rock
> solid.
> I don't have VPS, so I can't test it. The same is about DVB-T/C
> tuners. After all, if something doesn't work this feature can be
> disabled (and it is disabled by default),
>
Yes, sure. The patch against VDR-2.2.0:
http://pastebin.com/D4VQd1rG
While testing set VDR log level to 3 (--log=3) and use this helper
script to monitor your frontends:
http://pastebin.com/uW4NW0rZ
Don't forget to enable power saving in the Setup->LNB menu.
If you don't have sudo (you're not on Debian or Ubuntu), remove it and
run the script as root. It would be great if you could measure the
power consumption of you tuners (at least the USB one).
Best,
Sergey Chernyavskiy.
On Fri, May 27, 2016 at 09:59:06AM +0100, Richard F wrote:
> I'd like to give it a go on DVB & DVBT-2 tuners (1 PCI, 1 USB)
> Would you be kind enough to post a version for VDR2.20 or advise changes
> necessary?
>
> Thanks
> Richard
>
>
> On 26/05/2016 18:44, glenvt18 wrote:
> > For about a month now. Tested with 3 different DVB-S/S2 tuners with
> > VDR 2.3.1 and VDR 2.2.0 (requires minor changes to the patch) - rock
> > solid.
> > I don't have VPS, so I can't test it. The same is about DVB-T/C
> > tuners. After all, if something doesn't work this feature can be
> > disabled (and it is disabled by default),
> >
>
>
> _______________________________________________
> vdr mailing list
> vdr@linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
Thanks - I built it and and have had it running for about 24 hours:
A couple of observations:
I'm seeing this about every 30 - 60 mins as expected, but the timeout
seems to be short - not the PowerdownTimeoutM (I assume minutes?) set at
15 in the config file
May 30 08:51:02 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 1/0
May 30 08:51:46 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 1/0
So during the start of recordings and other programme changes, I see
quite a lot of activity - e.g
May 29 15:32:32 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 1/0
May 29 15:32:36 ha-server vdr: [2306] channel 41 (Channel 4 HD) event Sun 29.05.2016 15:25-16:30 (VPS: 29.05. 15:25) 'Location, Location, Location' status 4
May 29 15:32:37 ha-server vdr: [2306] channel 4 (BBC TWO HD) event Sun 29.05.2016 15:30-18:00 (VPS: 29.05. 15:30) 'Gymnastics' status 4
May 29 15:33:17 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 1/0
May 29 15:33:38 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 1/0
May 29 15:33:41 ha-server vdr: [2306] channel 45 (Film4) event Sun 29.05.2016 15:05-16:50 (VPS: 29.05. 15:05) 'Catch That Kid' status 4
May 29 15:33:42 ha-server vdr: [2306] channel 40 (Channel 4) event Sun 29.05.2016 15:25-16:30 (VPS: 29.05. 15:25) 'Location, Location, Location' status 4
May 29 15:34:23 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 1/0
Start of (VPS) recording:
May 29 19:50:07 ha-server vdr: [2296] timer 2 (3 2000-2100 VPS 'Top Gear~2016.05.29-20:00-Sun') entered VPS margin
May 29 19:50:07 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:50:08 ha-server vdr: [2303] channel 3 (BBC TWO) event Sun 29.05.2016 19:00-20:00 (VPS: 29.05. 19:00) 'Rugby Union' status 4
May 29 19:50:09 ha-server vdr: [2303] channel 7 (BBC NEWS) event Sun 29.05.2016 19:45-20:00 (VPS: 29.05. 19:45) 'Meet The Author' status 4
May 29 19:50:46 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:50:51 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:51:30 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:51:35 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:52:14 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:52:19 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:52:58 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:53:03 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:53:42 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:53:47 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:54:26 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:54:31 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:55:10 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:55:15 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:55:54 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:55:59 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:56:38 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:56:43 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:57:22 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:57:27 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:58:06 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:58:11 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:58:50 ha-server vdr: [2296] dvb tuner: power-down - closing frontend 0/0
May 29 19:58:55 ha-server vdr: [2296] dvb tuner: power-up - opening frontend 0/0
May 29 19:59:10 ha-server vdr: [2306] channel 61 (Channel 5 HD) event Sun 29.05.2016 20:00-21:00 (VPS: 29.05. 20:00) 'Secrets of Egypt' status 4
May 29 19:59:11 ha-server vdr: [2296] timer 1 (61 1900-2000 VPS 'Cricket on 5~England v Sri Lanka: Second Test Day Thr') stop
I haven't had a chance to take the server down to insert the power
monitor yet, but will do so at convenient time in the next few days
Thanks
Richard
On 27/05/2016 14:51, glenvt18 wrote:
> Yes, sure. The patch against VDR-2.2.0:
> http://pastebin.com/D4VQd1rG
>
> While testing set VDR log level to 3 (--log=3) and use this helper
> script to monitor your frontends:
> http://pastebin.com/uW4NW0rZ
>
> Don't forget to enable power saving in the Setup->LNB menu.
>
> If you don't have sudo (you're not on Debian or Ubuntu), remove it and
> run the script as root. It would be great if you could measure the
> power consumption of you tuners (at least the USB one).
>
> Best,
> Sergey Chernyavskiy.
>
> On Fri, May 27, 2016 at 09:59:06AM +0100, Richard F wrote:
>> I'd like to give it a go on DVB & DVBT-2 tuners (1 PCI, 1 USB)
>> Would you be kind enough to post a version for VDR2.20 or advise changes
>> necessary?
>>
>> Thanks
>> Richard
>>
>>
>> On 26/05/2016 18:44, glenvt18 wrote:
>>> For about a month now. Tested with 3 different DVB-S/S2 tuners with
>>> VDR 2.3.1 and VDR 2.2.0 (requires minor changes to the patch) - rock
>>> solid.
>>> I don't have VPS, so I can't test it. The same is about DVB-T/C
>>> tuners. After all, if something doesn't work this feature can be
>>> disabled (and it is disabled by default),
>>>
>>
>> _______________________________________________
>> vdr mailing list
>> vdr@linuxtv.org
>> http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
>
Hi,
Am 26.05.2016 um 17:36 schrieb glenvt18:
> I know about the dynamite plugin, but 1) it does much more then this, 2)
> still requires a VDR patch, which is bigger, 3) doesn't work reliably
> for me and 4) I think this functionality should be part of the VDR
> core.
I agree with you. I hope, dynamite was a little inspiration for you. :)
I plan (for several years now, sadly) to break out the udev-part of dynamite to make the vdr more dynamic in device
management. The idle-part is a good first step in that direction.
> + virtual void PowerDown(bool On) {};
> + ///< Actually powers the device down/up.
I think the name of the parameter is a bit misleading. With On == true you mean, that the device is powered down.
Either rename the parameter to "Down" or the function to something like "PowerSaveMode".
Lars.
> I agree with you. I hope, dynamite was a little inspiration for you. :)
Yes, I used it for some time. Thanks a lot for your work, Lars!
> I plan (for several years now, sadly) to break out the udev-part of dynamite to make the vdr more dynamic in device
> management. The idle-part is a good first step in that direction.
I remember I've read somewhere (may be at vdr-portal.de) that you had
plans to re-work the dynamite plugin and implement the idle part
separately.
> > + virtual void PowerDown(bool On) {}; + ///< Actually powers
> > the device down/up.
>
> I think the name of the parameter is a bit misleading. With On ==
> true you mean, that the device is powered down. Either rename the
> parameter to "Down" or the function to something like
> "PowerSaveMode".
Well, it's a matter of style. "On" is a typical VDR name for such
arguments. "Down" looks good as well as "PowerSaveMode" or
"PowerDownMode". I'll consider this change. Thanks.
Best,
Sergey Chernyavskiy.
@@ -395,6 +395,9 @@ cSetup::cSetup(void)
PositionerSpeed = 15;
PositionerSwing = 650;
PositionerLastLon = 0;
+ PowerdownEnabled = 0;
+ PowerdownTimeoutM = 15;
+ PowerdownWakeupH = 4;
SetSystemTime = 0;
TimeSource = 0;
TimeTransponder = 0;
@@ -622,6 +625,9 @@ bool cSetup::Parse(const char *Name, const char *Value)
else if (!strcasecmp(Name, "PositionerSpeed")) PositionerSpeed
= atoi(Value);
else if (!strcasecmp(Name, "PositionerSwing")) PositionerSwing
= atoi(Value);
else if (!strcasecmp(Name, "PositionerLastLon"))
PositionerLastLon = atoi(Value);
+ else if (!strcasecmp(Name, "PowerdownEnabled")) PowerdownEnabled
= atoi(Value);
+ else if (!strcasecmp(Name, "PowerdownTimeoutM"))
PowerdownTimeoutM = atoi(Value);
+ else if (!strcasecmp(Name, "PowerdownWakeupH")) PowerdownWakeupH
= atoi(Value);
else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime
= atoi(Value);
else if (!strcasecmp(Name, "TimeSource")) TimeSource
= cSource::FromString(Value);
else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder
= atoi(Value);
@@ -753,6 +759,9 @@ bool cSetup::Save(void)
Store("PositionerSpeed", PositionerSpeed);
Store("PositionerSwing", PositionerSwing);
Store("PositionerLastLon", PositionerLastLon);
+ Store("PowerdownEnabled", PowerdownEnabled);
+ Store("PowerdownTimeoutM", PowerdownTimeoutM);
+ Store("PowerdownWakeupH", PowerdownWakeupH);
Store("SetSystemTime", SetSystemTime);
Store("TimeSource", cSource::ToString(TimeSource));
Store("TimeTransponder", TimeTransponder);
@@ -273,6 +273,9 @@ public:
int PositionerSpeed;
int PositionerSwing;
int PositionerLastLon;
+ int PowerdownEnabled;
+ int PowerdownTimeoutM;
+ int PowerdownWakeupH;
int SetSystemTime;
int TimeSource;
int TimeTransponder;
@@ -104,6 +104,9 @@ cDevice::cDevice(void)
dvbSubtitleConverter = NULL;
autoSelectPreferredSubtitleLanguage = true;
+ idleTimerExpires = time(NULL) + Setup.PowerdownTimeoutM * 60;
+ wakeupTimerExpires = 0;
+
for (int i = 0; i < MAXRECEIVERS; i++)
receiver[i] = NULL;
@@ -745,6 +748,11 @@ bool cDevice::SwitchChannel(int Direction)
return result;
}
+// While switching to a channel, the device will be kept powered up
+// for at least this number of seconds before a receiver is attached.
+// Must be less than cEITScanner::ScanTimeout.
+#define CHANNEL_SWITCH_POWERUP_TIMEOUT 10
+
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
{
cStatus::MsgChannelSwitch(this, 0, LiveView);
@@ -778,6 +786,8 @@ eSetChannelResult cDevice::SetChannel(const
cChannel *Channel, bool LiveView)
Result = scrNotAvailable;
}
else {
+ // Power up the device
+ PowerUp(CHANNEL_SWITCH_POWERUP_TIMEOUT);
// Stop section handling:
if (sectionHandler) {
sectionHandler->SetStatus(false);
@@ -843,8 +853,11 @@ int cDevice::Occupied(void) const
void cDevice::SetOccupied(int Seconds)
{
- if (Seconds >= 0)
+ if (Seconds >= 0) {
occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT);
+ // avoid short power-down/power-up cycles
+ SetIdleTimer(true, Seconds + 30);
+ }
}
bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
@@ -1675,6 +1688,7 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
startScrambleDetection = time(NULL);
}
Start();
+ SetIdleTimer(false);
return true;
}
}
@@ -1708,8 +1722,10 @@ void cDevice::Detach(cReceiver *Receiver)
camSlot->Assign(NULL);
}
}
- if (!receiversLeft)
+ if (!receiversLeft) {
Cancel(-1);
+ SetIdleTimer(true);
+ }
}
void cDevice::DetachAll(int Pid)
@@ -1731,6 +1747,82 @@ void cDevice::DetachAllReceivers(void)
Detach(receiver[i]);
}
+void cDevice::CheckIdle(void)
+{
+ if (!SupportsPowerDown() || !Setup.PowerdownEnabled)
+ return;
+ cMutexLock MutexLock(&mutexPowerSaving);
+ if (idleTimerExpires != 0 && time(NULL) > idleTimerExpires) {
+ // idle, powered up
+ dsyslog("power saving: device %d idle timer expired", CardIndex() + 1);
+ SetIdleTimer(false);
+ if (Setup.PowerdownWakeupH != 0)
+ wakeupTimerExpires = time(NULL) + Setup.PowerdownWakeupH * 3600;
+ else
+ dsyslog("power saving: waking up is disabled");
+ if (!IsPoweredDown()) {
+ dsyslog("power saving: powering device %d down", CardIndex() + 1);
+ if (sectionHandler) {
+ sectionHandler->SetStatus(false);
+ sectionHandler->SetChannel(NULL);
+ }
+ PowerDown(true);
+ }
+ }
+ if (wakeupTimerExpires != 0 && time(NULL) > wakeupTimerExpires) {
+ // idle, powered down
+ dsyslog("power saving: device %d wakeup timer expired", CardIndex() + 1);
+ SetIdleTimer(true);
+ if (IsPoweredDown()) {
+ dsyslog("power saving: waking up device %d", CardIndex() + 1);
+ PowerDown(false);
+ }
+ }
+}
+
+void cDevice::SetIdleTimer(bool On, int ExtraTimeoutS)
+{
+ if (!SupportsPowerDown())
+ return;
+ cMutexLock MutexLock(&mutexPowerSaving);
+ if (On) {
+ int Tout = Setup.PowerdownTimeoutM * 60;
+ time_t Now = time(NULL);
+ if (ExtraTimeoutS > 0) {
+ if (idleTimerExpires >= Now + ExtraTimeoutS)
+ return;
+ Tout = ExtraTimeoutS;
+ }
+ idleTimerExpires = Now + Tout;
+ if (Setup.PowerdownEnabled)
+ dsyslog("power saving: set device %d idle timer to %d sec",
CardIndex() + 1, Tout);
+ }
+ else {
+ idleTimerExpires = 0;
+ if (Setup.PowerdownEnabled)
+ dsyslog("power saving: disable device %d idle timer", CardIndex() + 1);
+ }
+ wakeupTimerExpires = 0;
+}
+
+bool cDevice::PoweredDown(void)
+{
+ if (SupportsPowerDown() && Setup.PowerdownEnabled) {
+ cMutexLock MutexLock(&mutexPowerSaving);
+ return IsPoweredDown();
+ }
+ else
+ return false;
+}
+
+void cDevice::PowerUp(int ExtraTimeoutS)
+{
+ cMutexLock MutexLock(&mutexPowerSaving);
+ SetIdleTimer(true, ExtraTimeoutS);
+ if (SupportsPowerDown() && IsPoweredDown())
+ PowerDown(false);
+}
+
// --- cTSBuffer -------------------------------------------------------------
cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
@@ -821,6 +821,35 @@ public:
///< Detaches all receivers from this device for this pid.
virtual void DetachAllReceivers(void);
///< Detaches all receivers from this device.
+
+// Power saving facilities
+
+private:
+ cMutex mutexPowerSaving;
+ time_t idleTimerExpires, wakeupTimerExpires;
+ void PowerUp(int ExtraTimeoutS);
+ ///< If the device is powered down, powers it up and keeps it
+ ///< powered up for at least ExtraTimeoutS seconds (see
+ ///< cDevice::SetIdleTimer()).
+public:
+ void CheckIdle(void);
+ ///< Should be called periodically in the main loop.
+ bool PoweredDown(void);
+ ///< Returns true if the device is powered down "logically", that is,
+ ///< idle tasks like EPG scanning are disabled.
+ void SetIdleTimer(bool On, int ExtraTimeoutS = 0);
+ ///< Starts/disables the idle timer. This timer must be started when
+ ///< a device gets idle and must be disabled when it is receiving.
+ ///< If ExtraTimeoutS is greater than zero and On is true, a new timer
+ ///< won't be set, but the device will be kept powered up for at least
+ ///< ExtraTimeoutS seconds.
+protected:
+ virtual bool IsPoweredDown(void) {return false;}
+ ///< Returns true if the device is powered down "physically".
+ virtual void PowerDown(bool On) {};
+ ///< Actually powers the device down/up.
+ virtual bool SupportsPowerDown() {return false;}
+ ///< Returns true if a derived device supports power saving.
};
/// Derived cDevice classes that can receive channels will have to provide
@@ -348,6 +348,8 @@ public:
const cPositioner *Positioner(void) const { return positioner; }
int GetSignalStrength(void) const;
int GetSignalQuality(void) const;
+ bool IsPoweredDown(void) {return fd_frontend < 0;}
+ void PowerDown(bool On);
};
cMutex cDvbTuner::bondMutex;
@@ -544,6 +546,8 @@ void cDvbTuner::ClearEventQueue(void) const
bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
{
+ if (fd_frontend < 0)
+ return false;
ClearEventQueue();
while (1) {
if (ioctl(fd_frontend, FE_READ_STATUS, &Status) != -1)
@@ -559,6 +563,8 @@ bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
int cDvbTuner::GetSignalStrength(void) const
{
+ if (fd_frontend < 0)
+ return -1;
ClearEventQueue();
uint16_t Signal;
while (1) {
@@ -1001,6 +1007,26 @@ void cDvbTuner::Action(void)
}
}
+void cDvbTuner::PowerDown(bool On)
+{
+ cMutexLock MutexLock(&mutex);
+ if (On && fd_frontend >= 0) {
+ isyslog("dvb tuner: power-down - closing frontend %d/%d",
adapter, frontend);
+ tunerStatus = tsIdle;
+ close(fd_frontend);
+ fd_frontend = -1;
+ }
+ if (!On && fd_frontend < 0) {
+ cString Filename = cString::sprintf("%s/%s%d/%s%d",
+ DEV_DVB_BASE, DEV_DVB_ADAPTER, adapter, DEV_DVB_FRONTEND, frontend);
+ isyslog("dvb tuner: power-up - opening frontend %d/%d", adapter,
frontend);
+ fd_frontend = open(Filename, O_RDWR | O_NONBLOCK);
+ if (fd_frontend < 0)
+ esyslog("ERROR: can't open DVB device frontend %d/%d",
adapter, frontend);
+ tunerStatus = tsIdle;
+ }
+}
+
// --- cDvbSourceParam -------------------------------------------------------
class cDvbSourceParam : public cSourceParam {
@@ -1712,6 +1738,19 @@ void cDvbDevice::DetachAllReceivers(void)
needsDetachBondedReceivers = false;
}
+bool cDvbDevice::IsPoweredDown(void)
+{
+ if (dvbTuner)
+ return dvbTuner->IsPoweredDown();
+ return false;
+}
+
+void cDvbDevice::PowerDown(bool On)
+{
+ if (dvbTuner)
+ dvbTuner->PowerDown(On);
+}
+
// --- cDvbDeviceProbe -------------------------------------------------------
cList<cDvbDeviceProbe> DvbDeviceProbes;
@@ -290,6 +290,13 @@ protected:
virtual void CloseDvr(void);
virtual bool GetTSPacket(uchar *&Data);
virtual void DetachAllReceivers(void);
+
+// Power saving facilities
+
+protected:
+ virtual bool IsPoweredDown(void);
+ virtual void PowerDown(bool On);
+ virtual bool SupportsPowerDown() {return true;}
};
// A plugin that implements a DVB device derived from cDvbDevice
needs to create
@@ -144,7 +144,8 @@ void cEITScanner::Process(void)
bool AnyDeviceSwitched = false;
for (int i = 0; i < cDevice::NumDevices(); i++) {
cDevice *Device = cDevice::GetDevice(i);
- if (Device && Device->ProvidesEIT()) {
+ if (Device && Device->ProvidesEIT()
+ && (!Device->PoweredDown() || lastActivity ==
0)) { // powered up or forced scan
for (cScanData *ScanData = scanList->First();
ScanData; ScanData = scanList->Next(ScanData)) {
const cChannel *Channel = ScanData->GetChannel();
if (Channel) {
@@ -165,6 +166,10 @@ void cEITScanner::Process(void)
}
}
//dsyslog("EIT scan: device %d
source %-8s tp %5d", Device->DeviceNumber() + 1,
*cSource::ToString(Channel->Source()), Channel->Transponder());
+ if (lastActivity == 0)
+ // forced scan - set idle
timer for each channel switch;
+ // this prevents powering
down while scanning a transponder
+ Device->SetIdleTimer(true,
ScanTimeout + 5);
Device->SwitchChannel(Channel, false);
scanList->Del(ScanData);
AnyDeviceSwitched = true;
@@ -3715,6 +3715,12 @@ void cMenuSetupLNB::Setup(void)
Add(new cMenuEditIntxItem(tr("Setup.LNB$Positioner speed
(degrees/s)"), &data.PositionerSpeed, 1, 1800, 10));
}
+ Add(new cMenuEditBoolItem(tr("Setup.LNB$Enable power saving"),
&data.PowerdownEnabled));
+ if (data.PowerdownEnabled) {
+ Add(new cMenuEditIntItem(tr("Setup.LNB$Power down an idle device
after (min)"), &data.PowerdownTimeoutM));
+ Add(new cMenuEditIntItem(tr("Setup.LNB$Wake up from power-down
after (h)"), &data.PowerdownWakeupH));
+ }
+
SetCurrent(Get(current));
Display();
}
@@ -3723,6 +3729,7 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys Key)
{
int oldDiSEqC = data.DiSEqC;
int oldUsePositioner = data.UsePositioner;
+ int oldPowerdownEnabled = data.PowerdownEnabled;
bool DeviceBondingsChanged = false;
if (Key == kOk) {
cString NewDeviceBondings = satCableNumbers.ToString();
@@ -3731,7 +3738,7 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys Key)
}
eOSState state = cMenuSetupBase::ProcessKey(Key);
- if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner
!= oldUsePositioner))
+ if (Key != kNone && (data.DiSEqC != oldDiSEqC || data.UsePositioner
!= oldUsePositioner || data.PowerdownEnabled != oldPowerdownEnabled))
Setup();
else if (DeviceBondingsChanged)
cDvbDevice::BondDevices(data.DeviceBondings);
@@ -1515,6 +1515,12 @@ int main(int argc, char *argv[])
ReportEpgBugFixStats();
+ for (int i = 0; i < cDevice::NumDevices(); i++) {
+ cDevice *d = cDevice::GetDevice(i);
+ if (d)
+ d->CheckIdle();
+ }
+
// Main thread hooks of plugins:
PluginManager.MainThreadHook();
}