Skip to content

Commit 0801c9e

Browse files
committed
Add support for global sleep suppress.
1 parent 41ce339 commit 0801c9e

File tree

12 files changed

+431
-63
lines changed

12 files changed

+431
-63
lines changed

SerialPrograms/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ file(GLOB MAIN_SOURCES
305305
Source/CommonFramework/Environment/HardwareValidation_x86.tpp
306306
Source/CommonFramework/Environment/SystemSleep.cpp
307307
Source/CommonFramework/Environment/SystemSleep.h
308+
Source/CommonFramework/Environment/SystemSleep_Apple.tpp
309+
Source/CommonFramework/Environment/SystemSleep_Windows.tpp
308310
Source/CommonFramework/Exceptions/FatalProgramException.cpp
309311
Source/CommonFramework/Exceptions/FatalProgramException.h
310312
Source/CommonFramework/Exceptions/OliveActionFailedException.cpp
@@ -463,6 +465,8 @@ file(GLOB MAIN_SOURCES
463465
Source/CommonFramework/Options/Environment/ProcessPriorityOption.h
464466
Source/CommonFramework/Options/Environment/ProcessorLevelOption.cpp
465467
Source/CommonFramework/Options/Environment/ProcessorLevelOption.h
468+
Source/CommonFramework/Options/Environment/SleepSuppressOption.cpp
469+
Source/CommonFramework/Options/Environment/SleepSuppressOption.h
466470
Source/CommonFramework/Options/Environment/ThemeSelectorOption.cpp
467471
Source/CommonFramework/Options/Environment/ThemeSelectorOption.h
468472
Source/CommonFramework/Options/LabelCellOption.cpp

SerialPrograms/SerialPrograms.pro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ SOURCES += \
253253
Source/CommonFramework/OCR/OCR_TextMatcher.cpp \
254254
Source/CommonFramework/OCR/OCR_TrainingTools.cpp \
255255
Source/CommonFramework/Options/Environment/ProcessorLevelOption.cpp \
256+
Source/CommonFramework/Options/Environment/SleepSuppressOption.cpp \
256257
Source/CommonFramework/Options/Environment/ThemeSelectorOption.cpp \
257258
Source/CommonFramework/Options/LabelCellOption.cpp \
258259
Source/CommonFramework/Options/LanguageOCROption.cpp \
@@ -1247,6 +1248,8 @@ HEADERS += \
12471248
Source/CommonFramework/Environment/HardwareValidation_arm64.tpp \
12481249
Source/CommonFramework/Environment/HardwareValidation_x86.tpp \
12491250
Source/CommonFramework/Environment/SystemSleep.h \
1251+
Source/CommonFramework/Environment/SystemSleep_Apple.tpp \
1252+
Source/CommonFramework/Environment/SystemSleep_Windows.tpp \
12501253
Source/CommonFramework/Exceptions/FatalProgramException.h \
12511254
Source/CommonFramework/Exceptions/OliveActionFailedException.h \
12521255
Source/CommonFramework/Exceptions/OperationFailedException.h \
@@ -1330,6 +1333,7 @@ HEADERS += \
13301333
Source/CommonFramework/OCR/OCR_TrainingTools.h \
13311334
Source/CommonFramework/Options/Environment/ProcessPriorityOption.h \
13321335
Source/CommonFramework/Options/Environment/ProcessorLevelOption.h \
1336+
Source/CommonFramework/Options/Environment/SleepSuppressOption.h \
13331337
Source/CommonFramework/Options/LabelCellOption.h \
13341338
Source/CommonFramework/Options/LanguageOCROption.h \
13351339
Source/CommonFramework/Options/ScreenWatchOption.h \

SerialPrograms/Source/CommonFramework/Environment/SystemSleep.cpp

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,57 @@
66

77
#include "SystemSleep.h"
88

9-
#include <iostream>
9+
#if 0
10+
#elif _WIN32
11+
#include "SystemSleep_Windows.tpp"
12+
#elif __APPLE__
13+
#include "SystemSleep_Apple.tpp"
14+
#else
15+
namespace PokemonAutomation{
16+
SystemSleepController(){}
17+
~SystemSleepController(){}
18+
void push_screen_on(){}
19+
void pop_screen_on(){}
20+
void push_no_sleep(){}
21+
void pop_no_sleep(){}
22+
}
23+
#endif
1024

1125
namespace PokemonAutomation{
1226

13-
#if defined(__APPLE__)
1427

15-
// Code from https://stackoverflow.com/questions/5596319/how-to-programmatically-prevent-a-mac-from-going-to-sleep/8461182#8461182
1628

1729
SystemSleepController::SystemSleepController()
18-
: m_prevention_succeeded(kIOReturnError), m_session_id(0) {}
19-
30+
: m_data(new InternalController())
31+
{}
2032
SystemSleepController::~SystemSleepController(){
21-
enable_sleep();
33+
std::lock_guard<std::mutex> lg(m_data->lock);
34+
m_data->screen_on_requests = 0;
35+
m_data->no_sleep_requests = 0;
36+
m_data->update_state();
2237
}
23-
24-
bool SystemSleepController::prevent_sleep(bool prevent){
25-
if (prevent){
26-
return disable_sleep();
27-
}else{
28-
return enable_sleep();
29-
}
38+
void SystemSleepController::push_screen_on(){
39+
std::lock_guard<std::mutex> lg(m_data->lock);
40+
m_data->screen_on_requests++;
41+
m_data->update_state();
3042
}
31-
32-
bool SystemSleepController::disable_sleep(){
33-
if (m_prevention_succeeded == kIOReturnSuccess){
34-
return true;
35-
}
36-
std::cout << "Disabling display sleep and OS sleep" << std::endl;
37-
// kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
38-
// kIOPMAssertionTypeNoIdleSleep prevents idle sleep
39-
40-
// NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
41-
CFStringRef reasonForActivity = (CFStringRef) __builtin___CFStringMakeConstantString("SerialPrograms is running");
42-
43-
m_prevention_succeeded = kIOReturnError;
44-
m_session_id = 0;
45-
m_prevention_succeeded = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
46-
kIOPMAssertionLevelOn, reasonForActivity, &m_session_id);
47-
if (m_prevention_succeeded != kIOReturnSuccess){
48-
m_session_id = 0;
49-
std::cerr << "Cannot disable sleep. Error code " << m_prevention_succeeded << std::endl;
50-
return false;
51-
}
52-
53-
std::cout << "Disabled display sleep and OS sleep" << std::endl;
54-
return true;
43+
void SystemSleepController::pop_screen_on(){
44+
std::lock_guard<std::mutex> lg(m_data->lock);
45+
m_data->screen_on_requests--;
46+
m_data->update_state();
5547
}
56-
57-
bool SystemSleepController::enable_sleep(){
58-
if (m_prevention_succeeded == kIOReturnSuccess){
59-
IOPMAssertionRelease(m_session_id);
60-
m_session_id = 0;
61-
m_prevention_succeeded = kIOReturnError;
62-
std::cout << "Enabled display sleep and OS sleep." << std::endl;
63-
}
64-
return true;
48+
void SystemSleepController::push_no_sleep(){
49+
std::lock_guard<std::mutex> lg(m_data->lock);
50+
m_data->no_sleep_requests++;
51+
m_data->update_state();
6552
}
53+
void SystemSleepController::pop_no_sleep(){
54+
std::lock_guard<std::mutex> lg(m_data->lock);
55+
m_data->no_sleep_requests--;
56+
m_data->update_state();
57+
}
58+
6659

67-
#endif // defined(__APPLE__)
6860

6961
}
7062

SerialPrograms/Source/CommonFramework/Environment/SystemSleep.h

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,112 @@
77
#ifndef PokemonAutomation_SystemSleep_H
88
#define PokemonAutomation_SystemSleep_H
99

10-
#if defined(__APPLE__)
11-
#include <IOKit/pwr_mgt/IOPMLib.h>
10+
#include <memory>
11+
12+
13+
#if _WIN32
14+
#define PA_ENABLE_SLEEP_SUPPRESS
15+
#define PA_ENABLE_SLEEP_SUPPRESS_NO_SLEEP
16+
#endif
17+
#if __APPLE__
18+
#define PA_ENABLE_SLEEP_SUPPRESS
1219
#endif
1320

14-
namespace PokemonAutomation{
1521

22+
namespace PokemonAutomation{
1623

17-
#if defined(__APPLE__)
1824

19-
// Call OS API to prevent screen saver from running and OS from going to sleep.
20-
// Useful for running some programs like PokemonSV_VideoFastCodeEntry that require
21-
// the screen to be constantly on.
25+
// Call OS API to prevent screen saver from running and OS from going to sleep.
26+
// Useful for running some programs like PokemonSV_VideoFastCodeEntry that require
27+
// the screen to be constantly on.
2228
class SystemSleepController{
23-
public:
2429
SystemSleepController();
2530
~SystemSleepController();
2631

27-
// Disable/Enable screen saver and OS sleep.
28-
// Return whether the setting is successful.
29-
bool prevent_sleep(bool prevent);
32+
public:
33+
static SystemSleepController& instance(){
34+
static SystemSleepController controller;
35+
return controller;
36+
}
37+
38+
// Push: Add a request for this type of sleep-disable.
39+
// Pop: Remove a request for this type of sleep-disable.
40+
// The sleep-disable will be active as long as there is at least one
41+
// request is active for that type.
42+
43+
// Keep the screen on and prevent sleep.
44+
void push_screen_on();
45+
void pop_screen_on();
46+
47+
// Allow the screen to turn off, but don't sleep.
48+
void push_no_sleep();
49+
void pop_no_sleep();
50+
51+
private:
52+
struct InternalController;
53+
std::unique_ptr<InternalController> m_data;
54+
};
55+
56+
57+
58+
59+
enum class SleepSuppress{
60+
NONE,
61+
NO_SLEEP,
62+
SCREEN_ON,
63+
};
64+
65+
66+
class SleepSuppressScope{
67+
public:
68+
SleepSuppressScope(SleepSuppress mode){
69+
set(mode);
70+
}
71+
~SleepSuppressScope(){
72+
clear();
73+
}
74+
SleepSuppressScope(const SleepSuppressScope&) = delete;
75+
void operator=(const SleepSuppressScope&) = delete;
76+
77+
void clear(){
78+
switch (m_mode){
79+
case SleepSuppress::NONE:
80+
break;
81+
case SleepSuppress::NO_SLEEP:
82+
SystemSleepController::instance().pop_no_sleep();
83+
break;
84+
case SleepSuppress::SCREEN_ON:
85+
SystemSleepController::instance().pop_screen_on();
86+
break;
87+
}
88+
m_mode = SleepSuppress::NONE;
89+
}
90+
void operator=(SleepSuppress mode){
91+
clear();
92+
set(mode);
93+
}
3094

3195
private:
32-
bool disable_sleep();
33-
bool enable_sleep();
96+
void set(SleepSuppress mode){
97+
switch (mode){
98+
case SleepSuppress::NONE:
99+
break;
100+
case SleepSuppress::NO_SLEEP:
101+
SystemSleepController::instance().push_no_sleep();
102+
break;
103+
case SleepSuppress::SCREEN_ON:
104+
SystemSleepController::instance().push_screen_on();
105+
break;
106+
}
107+
m_mode = mode;
108+
}
34109

35-
IOReturn m_prevention_succeeded;
36-
IOPMAssertionID m_session_id;
110+
private:
111+
SleepSuppress m_mode;
37112
};
38113

39-
#endif
114+
115+
40116

41117
}
42118
#endif
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/* OS Sleep (Apple)
2+
*
3+
* From: https://github.com/PokemonAutomation/Arduino-Source
4+
*
5+
*/
6+
7+
#include <iostream>
8+
#include <mutex>
9+
#include <IOKit/pwr_mgt/IOPMLib.h>
10+
#include "CommonFramework/Logging/Logger.h"
11+
#include "SystemSleep.h"
12+
13+
namespace PokemonAutomation{
14+
15+
16+
17+
class SystemSleepController::InternalController{
18+
public:
19+
InternalController();
20+
~InternalController();
21+
22+
// Disable/Enable screen saver and OS sleep.
23+
// Return whether the setting is successful.
24+
bool prevent_sleep(bool prevent);
25+
26+
void update_state();
27+
28+
private:
29+
bool disable_sleep();
30+
bool enable_sleep();
31+
32+
IOReturn m_prevention_succeeded;
33+
IOPMAssertionID m_session_id;
34+
35+
36+
std::mutex lock;
37+
size_t screen_on_requests = 0;
38+
size_t no_sleep_requests = 0;
39+
};
40+
41+
42+
// Code from https://stackoverflow.com/questions/5596319/how-to-programmatically-prevent-a-mac-from-going-to-sleep/8461182#8461182
43+
44+
SystemSleepController::InternalController::InternalController()
45+
: m_prevention_succeeded(kIOReturnError), m_session_id(0) {}
46+
47+
SystemSleepController::InternalController::~InternalController(){
48+
enable_sleep();
49+
}
50+
51+
bool SystemSleepController::InternalController::prevent_sleep(bool prevent){
52+
if (prevent){
53+
return disable_sleep();
54+
}else{
55+
return enable_sleep();
56+
}
57+
}
58+
59+
bool SystemSleepController::InternalController::disable_sleep(){
60+
if (m_prevention_succeeded == kIOReturnSuccess){
61+
return true;
62+
}
63+
std::cout << "Disabling display sleep and OS sleep" << std::endl;
64+
// kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
65+
// kIOPMAssertionTypeNoIdleSleep prevents idle sleep
66+
67+
// NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
68+
CFStringRef reasonForActivity = (CFStringRef) __builtin___CFStringMakeConstantString("SerialPrograms is running");
69+
70+
m_prevention_succeeded = kIOReturnError;
71+
m_session_id = 0;
72+
m_prevention_succeeded = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
73+
kIOPMAssertionLevelOn, reasonForActivity, &m_session_id);
74+
if (m_prevention_succeeded != kIOReturnSuccess){
75+
m_session_id = 0;
76+
std::cerr << "Cannot disable sleep. Error code " << m_prevention_succeeded << std::endl;
77+
return false;
78+
}
79+
80+
std::cout << "Disabled display sleep and OS sleep" << std::endl;
81+
return true;
82+
}
83+
84+
bool SystemSleepController::InternalController::enable_sleep(){
85+
if (m_prevention_succeeded == kIOReturnSuccess){
86+
IOPMAssertionRelease(m_session_id);
87+
m_session_id = 0;
88+
m_prevention_succeeded = kIOReturnError;
89+
std::cout << "Enabled display sleep and OS sleep." << std::endl;
90+
}
91+
return true;
92+
}
93+
94+
95+
96+
void SystemSleepController::InternalController::update_state(){
97+
// Must call under lock.
98+
99+
// TODO: Distiguish these two.
100+
prevent_sleep(screen_on_requests > 0 || no_sleep_requests > 0);
101+
}
102+
103+
104+
105+
106+
107+
}

0 commit comments

Comments
 (0)