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