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>
master
Maarten van Gompel 4 years ago
parent 5f5cc6e675
commit 642bf1cc27
  1. 174
      programs/sxmo_screenlock.c
  2. 9
      scripts/core/sxmo_postwake.sh
  3. 10
      scripts/core/sxmo_presuspend.sh
  4. 11
      scripts/core/sxmo_rtcwake.sh

@ -5,19 +5,24 @@
#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 {
StateNoInput, // Screen on / input lock StateNoInput, // Screen on / input lock
StateNoInputNoScreen, // Screen off / input lock StateNoInputNoScreen, // Screen off / input lock
StateSuspend, // Deep sleep StateSuspend, // Deep sleep
StateSuspendPending, // Suspend 'woken up', must leave state in <5s, or kicks to StateSuspend StateSuspendPending, // Suspend 'woken up', must leave state in <5s, or kicks to StateSuspend
StateDead // Exit the appliation StateDead // Exit the appliation
}; };
enum Color { enum Color {
Red, Red,
@ -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()
@ -59,7 +128,7 @@ configuresuspendsettingsandwakeupsources()
die("Couldn't open directory /sys/class/wakeup\n"); die("Couldn't open directory /sys/class/wakeup\n");
while ((wakeupsource = readdir(wakeupsources)) != NULL) { while ((wakeupsource = readdir(wakeupsources)) != NULL) {
sprintf( sprintf(
wakeuppath, wakeuppath,
"/sys/class/wakeup/%.50s/device/power/wakeup", "/sys/class/wakeup/%.50s/device/power/wakeup",
wakeupsource->d_name wakeupsource->d_name
); );
@ -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) {
setpineled(Red); if (presuspend() != 0) {
configuresuspendsettingsandwakeupsources(); state = StateDead;
writefile(powerstatefile, "mem"); } else {
// Just woke up setpineled(Red);
updatestatusbar(); configuresuspendsettingsandwakeupsources();
state = StateSuspendPending; writefile(powerstatefile, "mem");
suspendpendingtimeouts = 0; //---- program blocks here due to sleep ----- //
// Just woke up again
fprintf(stderr, "Woke up\n");
if (waketime > 0) {
rtcresult = checkrtcwake();
} else {
rtcresult = 0;
}
if (rtcresult == 0) {
state = StateSuspendPending;
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;
} }

@ -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

@ -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

@ -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…
Cancel
Save