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