Implementing optional rtc wakeup at regular intervals, added presuspend, rtcwake and postwake scripts (with hooks)
(includes missing return 0 statement caught by Serge Hallyn) Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
This commit is contained in:
parent
5f5cc6e675
commit
642bf1cc27
4 changed files with 187 additions and 17 deletions
|
@ -5,11 +5,16 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XF86keysym.h>
|
#include <X11/XF86keysym.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
enum State {
|
enum State {
|
||||||
|
@ -27,14 +32,21 @@ enum Color {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fn declarations
|
// Fn declarations
|
||||||
|
int checkrtcwake();
|
||||||
void configuresuspendsettingsandwakeupsources();
|
void configuresuspendsettingsandwakeupsources();
|
||||||
|
time_t convert_rtc_time(struct rtc_time * rtc);
|
||||||
void die(const char *err, ...);
|
void die(const char *err, ...);
|
||||||
int getoldbrightness();
|
int getoldbrightness();
|
||||||
|
void init_rtc();
|
||||||
void lockscreen(Display *dpy, int screen);
|
void lockscreen(Display *dpy, int screen);
|
||||||
void readinputloop(Display *dpy, int screen);
|
void readinputloop(Display *dpy, int screen);
|
||||||
|
int presuspend();
|
||||||
|
void postwake();
|
||||||
void setpineled(enum Color c);
|
void setpineled(enum Color c);
|
||||||
|
int setup_rtc_wakeup();
|
||||||
|
void sigterm();
|
||||||
void syncstate();
|
void syncstate();
|
||||||
void updatestatusbar();
|
void usage();
|
||||||
void writefile(char *filepath, char *str);
|
void writefile(char *filepath, char *str);
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
|
@ -47,6 +59,63 @@ int lastkeyn = 0;
|
||||||
char oldbrightness[10] = "200";
|
char oldbrightness[10] = "200";
|
||||||
char * brightnessfile = "/sys/devices/platform/backlight/backlight/backlight/brightness";
|
char * brightnessfile = "/sys/devices/platform/backlight/backlight/backlight/brightness";
|
||||||
char * powerstatefile = "/sys/power/state";
|
char * powerstatefile = "/sys/power/state";
|
||||||
|
int rtc_fd = 0; //file descriptor
|
||||||
|
time_t wakeinterval = 0; //wake every x seconds
|
||||||
|
time_t waketime = 0; //next wakeup time according to the RTC clock
|
||||||
|
|
||||||
|
#define RTC_DEVICE "/dev/rtc0"
|
||||||
|
|
||||||
|
time_t
|
||||||
|
convert_rtc_time(struct rtc_time * rtc) {
|
||||||
|
struct tm tm;
|
||||||
|
memset(&tm, 0, sizeof tm);
|
||||||
|
tm.tm_sec = rtc->tm_sec;
|
||||||
|
tm.tm_min = rtc->tm_min;
|
||||||
|
tm.tm_hour = rtc->tm_hour;
|
||||||
|
tm.tm_mday = rtc->tm_mday;
|
||||||
|
tm.tm_mon = rtc->tm_mon;
|
||||||
|
tm.tm_year = rtc->tm_year;
|
||||||
|
tm.tm_isdst = -1; /* assume the system knows better than the RTC */
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup_rtc_wakeup() {
|
||||||
|
//(code adapted from util-linux's rtcwake)
|
||||||
|
struct tm *tm;
|
||||||
|
struct rtc_wkalrm wake;
|
||||||
|
struct rtc_time now_rtc;
|
||||||
|
|
||||||
|
if (ioctl(rtc_fd, RTC_RD_TIME, &now_rtc) < 0) {
|
||||||
|
fprintf(stderr, "Error reading rtc time\n");
|
||||||
|
}
|
||||||
|
const time_t now = convert_rtc_time(&now_rtc);
|
||||||
|
waketime = now + wakeinterval;
|
||||||
|
|
||||||
|
tm = localtime(&waketime);
|
||||||
|
|
||||||
|
wake.time.tm_sec = tm->tm_sec;
|
||||||
|
wake.time.tm_min = tm->tm_min;
|
||||||
|
wake.time.tm_hour = tm->tm_hour;
|
||||||
|
wake.time.tm_mday = tm->tm_mday;
|
||||||
|
wake.time.tm_mon = tm->tm_mon;
|
||||||
|
wake.time.tm_year = tm->tm_year;
|
||||||
|
/* wday, yday, and isdst fields are unused by Linux */
|
||||||
|
wake.time.tm_wday = -1;
|
||||||
|
wake.time.tm_yday = -1;
|
||||||
|
wake.time.tm_isdst = -1;
|
||||||
|
|
||||||
|
fprintf(stderr, "Setting RTC wakeup to %ld: (UTC) %s", waketime, asctime(tm));
|
||||||
|
|
||||||
|
if (ioctl(rtc_fd, RTC_ALM_SET, &wake.time) < 0) {
|
||||||
|
fprintf(stderr, "error setting rtc alarm\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ioctl(rtc_fd, RTC_AIE_ON, 0) < 0) {
|
||||||
|
fprintf(stderr, "error enabling rtc alarm\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
configuresuspendsettingsandwakeupsources()
|
configuresuspendsettingsandwakeupsources()
|
||||||
|
@ -90,6 +159,9 @@ configuresuspendsettingsandwakeupsources()
|
||||||
"enabled"
|
"enabled"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//set RTC wake
|
||||||
|
if (wakeinterval > 0) setup_rtc_wakeup();
|
||||||
|
|
||||||
// Temporary hack to disable USB driver that doesn't suspend
|
// Temporary hack to disable USB driver that doesn't suspend
|
||||||
fprintf(stderr, "Disabling buggy USB driver\n");
|
fprintf(stderr, "Disabling buggy USB driver\n");
|
||||||
writefile(
|
writefile(
|
||||||
|
@ -107,6 +179,7 @@ configuresuspendsettingsandwakeupsources()
|
||||||
// E.g. make sure we're using CRUST
|
// E.g. make sure we're using CRUST
|
||||||
fprintf(stderr, "Flip mem_sleep setting to use crust\n");
|
fprintf(stderr, "Flip mem_sleep setting to use crust\n");
|
||||||
writefile("/sys/power/mem_sleep", "deep");
|
writefile("/sys/power/mem_sleep", "deep");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -123,6 +196,7 @@ sigterm()
|
||||||
{
|
{
|
||||||
state = StateDead;
|
state = StateDead;
|
||||||
syncstate();
|
syncstate();
|
||||||
|
if (wakeinterval) close(rtc_fd);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +297,7 @@ readinputloop(Display *dpy, int screen) {
|
||||||
else state = StateNoInput;
|
else state = StateNoInput;
|
||||||
break;
|
break;
|
||||||
case XF86XK_PowerOff:
|
case XF86XK_PowerOff:
|
||||||
|
waketime = 0;
|
||||||
state = StateDead;
|
state = StateDead;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +310,7 @@ readinputloop(Display *dpy, int screen) {
|
||||||
syncstate();
|
syncstate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (state == StateDead) break;
|
if (state == StateDead) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,17 +333,64 @@ setpineled(enum Color c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
presuspend() {
|
||||||
|
//called prior to suspension, a non-zero return value cancels suspension
|
||||||
|
return system("sxmo_presuspend.sh");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
postwake() {
|
||||||
|
//called after fully waking up (not used for temporary rtc wakeups)
|
||||||
|
system("sxmo_postwake.sh");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
checkrtcwake()
|
||||||
|
{
|
||||||
|
struct rtc_time now;
|
||||||
|
if (ioctl(rtc_fd, RTC_RD_TIME, &now) < 0) {
|
||||||
|
fprintf(stderr, "Error reading rtc time\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const long int timediff = convert_rtc_time(&now) - waketime;
|
||||||
|
fprintf(stderr, "Checking rtc wake? timediff=%ld\n", timediff);
|
||||||
|
if (timediff >= 0 && timediff <= 3) {
|
||||||
|
fprintf(stderr, "Calling RTC wake script\n");
|
||||||
|
setpineled(Blue);
|
||||||
|
return system("sxmo_rtcwake.sh");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
syncstate()
|
syncstate()
|
||||||
{
|
{
|
||||||
|
int rtcresult;
|
||||||
if (state == StateSuspend) {
|
if (state == StateSuspend) {
|
||||||
|
if (presuspend() != 0) {
|
||||||
|
state = StateDead;
|
||||||
|
} else {
|
||||||
setpineled(Red);
|
setpineled(Red);
|
||||||
configuresuspendsettingsandwakeupsources();
|
configuresuspendsettingsandwakeupsources();
|
||||||
writefile(powerstatefile, "mem");
|
writefile(powerstatefile, "mem");
|
||||||
// Just woke up
|
//---- program blocks here due to sleep ----- //
|
||||||
updatestatusbar();
|
// Just woke up again
|
||||||
|
fprintf(stderr, "Woke up\n");
|
||||||
|
if (waketime > 0) {
|
||||||
|
rtcresult = checkrtcwake();
|
||||||
|
} else {
|
||||||
|
rtcresult = 0;
|
||||||
|
}
|
||||||
|
if (rtcresult == 0) {
|
||||||
state = StateSuspendPending;
|
state = StateSuspendPending;
|
||||||
suspendpendingtimeouts = 0;
|
suspendpendingtimeouts = 0;
|
||||||
|
} else {
|
||||||
|
postwake();
|
||||||
|
state = StateDead;
|
||||||
|
}
|
||||||
|
}
|
||||||
syncstate();
|
syncstate();
|
||||||
} else if (state == StateNoInput) {
|
} else if (state == StateNoInput) {
|
||||||
setpineled(Blue);
|
setpineled(Blue);
|
||||||
|
@ -286,11 +409,8 @@ syncstate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
updatestatusbar()
|
|
||||||
{
|
|
||||||
system("sxmo_statusbarupdate.sh");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
writefile(char *filepath, char *str)
|
writefile(char *filepath, char *str)
|
||||||
|
@ -309,6 +429,15 @@ void usage() {
|
||||||
fprintf(stderr, "Usage: sxmo_screenlock [--screen-off] [--suspend]\n");
|
fprintf(stderr, "Usage: sxmo_screenlock [--screen-off] [--suspend]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void init_rtc() {
|
||||||
|
rtc_fd = open(RTC_DEVICE, O_RDONLY);
|
||||||
|
if (rtc_fd < 0) {
|
||||||
|
die("Unable to open rtc device");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
int screen;
|
int screen;
|
||||||
|
@ -317,6 +446,9 @@ main(int argc, char **argv) {
|
||||||
|
|
||||||
signal(SIGTERM, sigterm);
|
signal(SIGTERM, sigterm);
|
||||||
|
|
||||||
|
const char* rtcwakeinterval = getenv("SXMO_RTCWAKEINTERVAL");
|
||||||
|
if (rtcwakeinterval != NULL) wakeinterval = atoi(rtcwakeinterval);
|
||||||
|
|
||||||
//parse command line arguments
|
//parse command line arguments
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
if(!strcmp(argv[i], "-h")) {
|
if(!strcmp(argv[i], "-h")) {
|
||||||
|
@ -326,6 +458,8 @@ main(int argc, char **argv) {
|
||||||
target = StateNoInputNoScreen;
|
target = StateNoInputNoScreen;
|
||||||
} else if(!strcmp(argv[i], "--suspend")) {
|
} else if(!strcmp(argv[i], "--suspend")) {
|
||||||
target = StateSuspend;
|
target = StateSuspend;
|
||||||
|
} else if(!strcmp(argv[i], "--wake-interval")) {
|
||||||
|
wakeinterval = (time_t) atoi(argv[++i]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid argument: %s\n", argv[i]);
|
fprintf(stderr, "Invalid argument: %s\n", argv[i]);
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -337,6 +471,8 @@ main(int argc, char **argv) {
|
||||||
if (!(dpy = XOpenDisplay(NULL)))
|
if (!(dpy = XOpenDisplay(NULL)))
|
||||||
die("Cannot open display\n");
|
die("Cannot open display\n");
|
||||||
|
|
||||||
|
if (wakeinterval) init_rtc();
|
||||||
|
|
||||||
XkbSetDetectableAutoRepeat(dpy, True, NULL);
|
XkbSetDetectableAutoRepeat(dpy, True, NULL);
|
||||||
screen = XDefaultScreen(dpy);
|
screen = XDefaultScreen(dpy);
|
||||||
XSync(dpy, 0);
|
XSync(dpy, 0);
|
||||||
|
@ -352,5 +488,9 @@ main(int argc, char **argv) {
|
||||||
syncstate();
|
syncstate();
|
||||||
}
|
}
|
||||||
readinputloop(dpy, screen);
|
readinputloop(dpy, screen);
|
||||||
|
if (wakeinterval) {
|
||||||
|
ioctl(rtc_fd, RTC_AIE_OFF, 0);
|
||||||
|
close(rtc_fd);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
9
scripts/core/sxmo_postwake.sh
Executable file
9
scripts/core/sxmo_postwake.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# This script is called when the system has successfully woken up after sleep
|
||||||
|
|
||||||
|
sxmo_statusbarupdate.sh
|
||||||
|
|
||||||
|
if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/postwake" ]; then
|
||||||
|
"$XDG_CONFIG_HOME/sxmo/hooks/postwake"
|
||||||
|
fi
|
10
scripts/core/sxmo_presuspend.sh
Executable file
10
scripts/core/sxmo_presuspend.sh
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# This script is called prior to suspending
|
||||||
|
|
||||||
|
# If this script returns a non-zero exit code, suspension will be cancelled
|
||||||
|
|
||||||
|
if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/presuspend" ]; then
|
||||||
|
"$XDG_CONFIG_HOME/sxmo/hooks/presuspend"
|
||||||
|
exit $?
|
||||||
|
fi
|
11
scripts/core/sxmo_rtcwake.sh
Executable file
11
scripts/core/sxmo_rtcwake.sh
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# This script (and anything it calls) should return as quickly as possible
|
||||||
|
# as it blocks the system from suspending (and processing input) until done
|
||||||
|
|
||||||
|
# If this script returns a non-zero exit code, the system will wake up
|
||||||
|
|
||||||
|
if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/rtcwake" ]; then
|
||||||
|
"$XDG_CONFIG_HOME/sxmo/hooks/rtcwake"
|
||||||
|
exit $?
|
||||||
|
fi
|
Loading…
Add table
Add a link
Reference in a new issue