MythTV master
mythpower.cpp
Go to the documentation of this file.
1// MythTV
2#include "mythconfig.h"
3
4#include "mythcorecontext.h"
5#include "mythlogging.h"
6#include "mythpower.h"
7
8#if CONFIG_QTDBUS
10#endif
11
12#ifdef Q_OS_DARWIN
14#endif
15
16#define LOC QString("Power: ")
17
18QRecursiveMutex MythPower::s_lock;
19
74MythPower* MythPower::AcquireRelease(void *Reference, bool Acquire, std::chrono::seconds MinimumDelay)
75{
76 static MythPower* s_instance = nullptr;
77 static QHash<void*,std::chrono::seconds> s_delays;
78
79 QMutexLocker locker(&s_lock);
80 if (Acquire)
81 {
82 // Upref or create
83 if (s_instance)
84 {
85 s_instance->IncrRef();
86 }
87 else
88 {
89#ifdef Q_OS_DARWIN
90 // NB OSX may have DBUS but it won't help here
91 s_instance = new MythPowerOSX();
92#elif CONFIG_QTDBUS
94 s_instance = new MythPowerDBus();
95#endif
96 // default no functionality
97 if (!s_instance)
98 s_instance = new MythPower();
99 }
100 // Append additional feature delay request
101 s_delays.insert(Reference, MinimumDelay);
102 }
103 else
104 {
105 // Remove requested delay
106 s_delays.remove(Reference);
107
108 // Decref and ensure nulled on last use
109 if (s_instance)
110 if (s_instance->DecrRef() == 0)
111 s_instance = nullptr;
112 }
113
114 if (s_instance)
115 {
116 // Update the maximum requested delay
117 std::chrono::seconds max = std::max_element(s_delays.cbegin(), s_delays.cend()).value();
118 s_instance->SetRequestedDelay(max);
119 }
120 return s_instance;
121}
122
124 : ReferenceCounter("Power")
125{
126 m_featureTimer.setSingleShot(true);
128}
129
131{
132 QStringList supported = GetFeatureList();
133 if (supported.isEmpty())
134 supported << "None";
135 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Supported actions: %1").arg(supported.join(",")));
136}
137
138void MythPower::SetRequestedDelay(std::chrono::seconds Delay)
139{
140 m_maxRequestedDelay = Delay;
141}
142
143MythPower::Features MythPower::GetFeatures(void)
144{
145 Features result = FeatureNone;
146 s_lock.lock();
147 result = m_features;
148 s_lock.unlock();
149 return result;
150}
151
153{
154 QStringList supported;
155 MythPower::Features features = GetFeatures();
156 if (features.testFlag(FeatureSuspend)) supported << FeatureToString(FeatureSuspend);
157 if (features.testFlag(FeatureHibernate)) supported << FeatureToString(FeatureHibernate);
158 if (features.testFlag(FeatureRestart)) supported << FeatureToString(FeatureRestart);
159 if (features.testFlag(FeatureShutdown)) supported << FeatureToString(FeatureShutdown);
160 if (features.testFlag(FeatureHybridSleep)) supported << FeatureToString(FeatureHybridSleep);
161 return supported;
162}
163
165{
166 bool result = false;
167 s_lock.lock();
168 result = ((m_features & Supported) != 0U);
169 s_lock.unlock();
170 return result;
171}
172
174{
175 int result = UnknownPower;
176 s_lock.lock();
177 result = m_powerLevel;
178 s_lock.unlock();
179 return result;
180}
181
183{
184 QMutexLocker locker(&s_lock);
185
186 if ((Request == FeatureNone) || !(m_features & Request))
187 return false;
188
189 // N.B Always check for a new user delay value as this class is persistent.
190 // Default is user preference, limited by the maximum supported system value
191 // and possibly overriden by the maximum delay requested by other Myth classes.
192 auto user = gCoreContext->GetDurSetting<std::chrono::seconds>("EXIT_SHUTDOWN_DELAY", 3s);
194
195 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Delay: %1 User: %2 Requested: %3 Supported: %4")
196 .arg(Delay).arg(user.count()).arg(m_maxRequestedDelay.count())
197 .arg(m_maxSupportedDelay.count()));
198
199 if (!Delay || delay < 1s)
200 {
202 DoFeature();
203 }
204
205 if (!ScheduleFeature(Request, delay))
206 return false;
207
208 auto remaining = m_featureTimer.remainingTimeAsDuration();
209 switch (Request)
210 {
211 case FeatureSuspend: emit WillSuspend(remaining); break;
212 case FeatureShutdown: emit WillShutDown(remaining); break;
213 case FeatureRestart: emit WillRestart(remaining); break;
214 case FeatureHibernate: emit WillHibernate(remaining); break;
215 case FeatureHybridSleep: emit WillHybridSleep(remaining); break;
216 default: break;
217 }
218 return true;
219}
220
223{
224 QMutexLocker locker(&s_lock);
225
226 if (!m_featureTimer.isActive() || !m_scheduledFeature)
227 LOG(VB_GENERAL, LOG_WARNING, LOC + "No power request to cancel");
228 else
229 {
230 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Cancelling %1 request with %2 seconds remaining")
231 .arg(FeatureToString(m_scheduledFeature)).arg(m_featureTimer.remainingTime() / 1000));
232 DidWakeUp();
233 }
235 m_featureTimer.stop();
236}
237
239{
240 DoFeature();
241}
242
244{
245 switch (Type)
246 {
247 case FeatureRestart: return tr("Restart");
248 case FeatureSuspend: return tr("Suspend");
249 case FeatureShutdown: return tr("Shutdown");
250 case FeatureHibernate: return tr("Hibernate");
251 case FeatureHybridSleep: return tr("HybridSleep");
252 case FeatureNone: break;
253 }
254 return "Unknown";
255}
256
258{
259 bool suspend = Second == FeatureSuspend || Second == FeatureHibernate ||
260 Second == FeatureHybridSleep;
261 bool poweroff = Second == FeatureRestart || Second == FeatureShutdown;
262 switch (First)
263 {
264 case FeatureNone: return Second == FeatureNone;
265 case FeatureSuspend:
266 case FeatureHibernate:
267 case FeatureHybridSleep: return suspend;
268 case FeatureRestart:
269 case FeatureShutdown: return poweroff;
270 }
271 return false;
272}
273
274bool MythPower::ScheduleFeature(enum Feature Type, std::chrono::seconds Delay)
275{
276 if (Type == FeatureNone || Delay > MAXIMUM_SHUTDOWN_WAIT)
277 return false;
278
279 if (m_featureTimer.isActive() || m_scheduledFeature)
280 {
281 LOG(VB_GENERAL, LOG_ERR, LOC +
282 QString("Ignoring %1 request: %2 pending in %3 seconds")
284 .arg(m_featureTimer.remainingTime() / 1000));
285 return false;
286 }
287
288 m_scheduledFeature = Type;
289 m_featureTimer.start(Delay);
290 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Will %1 in %2 seconds")
291 .arg(FeatureToString(Type)).arg(Delay.count()));
292 return true;
293}
294
302{
303 if (FeatureNone != Spontaneous)
304 {
305 m_scheduledFeature = Spontaneous;
306 m_isSpontaneous = true;
307 }
308
310 return;
311
312 m_sleepTime = QDateTime::currentDateTime();
313 LOG(VB_GENERAL, LOG_INFO, LOC + QString("About to: %1 %2")
315 m_isSpontaneous ? QString("(System notification)") : ""));
316
317 switch (m_scheduledFeature)
318 {
319 case FeatureSuspend: emit Suspending(); break;
320 case FeatureShutdown: emit ShuttingDown(); break;
321 case FeatureRestart: emit Restarting(); break;
322 case FeatureHibernate: emit Hibernating(); break;
323 case FeatureHybridSleep: emit HybridSleeping(); break;
324 case FeatureNone: break;
325 }
326}
327
329{
330 QMutexLocker locker(&s_lock);
331
333 m_isSpontaneous = false;
334 m_featureTimer.stop();
335 static constexpr qint64 kSecsInDay { 24LL * 60 * 60 };
336 QDateTime now = QDateTime::currentDateTime();
337 qint64 secs = m_sleepTime.secsTo(now);
338 qint64 days = secs / kSecsInDay;
339 QTime time = QTime(0, 0).addSecs(secs % kSecsInDay);
340 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Woke up after %1days %2hours %3minutes and %4seconds")
341 .arg(days).arg(time.hour()).arg(time.minute()).arg(time.second()));
342 emit WokeUp(std::chrono::seconds(m_sleepTime.secsTo(now)));
343}
344
346{
347 if (Level == m_powerLevel)
348 return;
349
350 if (Level == ACPower)
351 {
352 m_warnForLowBattery = true;
353 LOG(VB_GENERAL, LOG_INFO, LOC + "On AC power");
354 }
355 else if (Level == UPS)
356 {
357 m_warnForLowBattery = true;
358 LOG(VB_GENERAL, LOG_INFO, LOC + "On UPS");
359 }
360 else if (Level < UnknownPower)
361 {
362 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Battery at %1%").arg(Level));
363 if (Level <= BatteryLow)
364 {
366 {
367 m_warnForLowBattery = false;
368 LOG(VB_GENERAL, LOG_INFO, LOC + "Low battery!");
369 emit LowBattery();
370 }
371 }
372 else
373 {
374 m_warnForLowBattery = true;
375 }
376 }
377 else
378 {
379 LOG(VB_GENERAL, LOG_INFO, LOC + "Unknown power source");
380 }
381
382 m_powerLevel = Level;
383}
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
static bool IsAvailable(void)
Static check for DBus interfaces that support some form of power management.
virtual bool DoFeature(bool=false)
Definition: mythpower.h:82
@ BatteryLow
Definition: mythpower.h:29
@ UnknownPower
Definition: mythpower.h:31
std::chrono::seconds m_maxRequestedDelay
Definition: mythpower.h:94
void WokeUp(std::chrono::seconds SecondsAsleep)
void FeatureTimeout(void)
Definition: mythpower.cpp:238
int m_powerLevel
Definition: mythpower.h:98
static QRecursiveMutex s_lock
Definition: mythpower.h:76
void Suspending(void)
void WillSuspend(std::chrono::milliseconds MilliSeconds=0ms)
void ShuttingDown(void)
@ FeatureRestart
Definition: mythpower.h:41
@ FeatureShutdown
Definition: mythpower.h:38
@ FeatureSuspend
Definition: mythpower.h:39
@ FeatureNone
Definition: mythpower.h:37
@ FeatureHibernate
Definition: mythpower.h:40
@ FeatureHybridSleep
Definition: mythpower.h:42
Features m_features
Definition: mythpower.h:91
virtual bool RequestFeature(Feature Request, bool Delay=true)
Definition: mythpower.cpp:182
virtual void FeatureHappening(Feature Spontaneous=FeatureNone)
Signal to the rest of MythTV that the given feature will happen now.
Definition: mythpower.cpp:301
void HybridSleeping(void)
virtual void DidWakeUp(void)
Definition: mythpower.cpp:328
Feature m_scheduledFeature
Definition: mythpower.h:92
QTimer m_featureTimer
Definition: mythpower.h:96
void LowBattery(void)
static bool FeatureIsEquivalent(Feature First, Feature Second)
Definition: mythpower.cpp:257
void PowerLevelChanged(int Level)
Definition: mythpower.cpp:345
Features GetFeatures(void)
Definition: mythpower.cpp:143
bool IsFeatureSupported(Feature Supported)
Definition: mythpower.cpp:164
bool m_warnForLowBattery
Definition: mythpower.h:99
void WillHybridSleep(std::chrono::milliseconds MilliSeconds=0ms)
void SetRequestedDelay(std::chrono::seconds Delay)
Definition: mythpower.cpp:138
static MythPower * AcquireRelease(void *Reference, bool Acquire, std::chrono::seconds MinimumDelay=0s)
Definition: mythpower.cpp:74
QDateTime m_sleepTime
Definition: mythpower.h:97
virtual void Init(void)
Definition: mythpower.cpp:130
static QString FeatureToString(enum Feature Type)
Definition: mythpower.cpp:243
virtual void CancelFeature(void)
This is untested as it is currently not clear whether it is useful.
Definition: mythpower.cpp:222
std::chrono::seconds m_maxSupportedDelay
Definition: mythpower.h:95
void WillShutDown(std::chrono::milliseconds MilliSeconds=0ms)
void Restarting(void)
QStringList GetFeatureList(void)
Definition: mythpower.cpp:152
int GetPowerLevel(void) const
Definition: mythpower.cpp:173
bool m_isSpontaneous
Definition: mythpower.h:93
void Hibernating(void)
void WillRestart(std::chrono::milliseconds MilliSeconds=0ms)
virtual bool ScheduleFeature(enum Feature Type, std::chrono::seconds Delay)
Definition: mythpower.cpp:274
void WillHibernate(std::chrono::milliseconds MilliSeconds=0ms)
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
Definition: mythpower.cpp:16
static constexpr std::chrono::seconds MAXIMUM_SHUTDOWN_WAIT
Definition: mythpower.h:17
duration< CHRONO_TYPE, ratio< 86400 > > days
Definition: mythchrono.h:25
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206