~increscent/sxmo-utils

de7ce704add5f27512651d51bb4de96f2162c21b — Robert Williams 4 months ago 6eaa356
still working
2 files changed, 267 insertions(+), 343 deletions(-)

M .gitignore
M programs/sxmo_suspend.c
M .gitignore => .gitignore +1 -0
@@ 5,3 5,4 @@ programs/sxmo_screenlock
programs/sxmo_setpinebacklight
programs/sxmo_vibratepine
programs/sxmo_ring
programs/sxmo_suspend

M programs/sxmo_suspend.c => programs/sxmo_suspend.c +266 -343
@@ 18,15 18,14 @@

const int WAKE_INTERVAL = 60; // wake every 60 seconds
const char *POWER_STATE_FILE = "/sys/power/state";
//const char *BRIGHTNESS_FILE = "/sys/devices/platform/backlight/backlight/backlight/brightness";

// Types
enum Color {
	Red,
	Blue,
	Purple,
    Red,
    Blue,
    Purple,
    Green,
	Off
    Off
};

struct fbuf {


@@ 37,11 36,11 @@ struct fbuf {
// Fn declarations
time_t  convert_rtc_time(struct rtc_time *rtc);
void    die(const char *err, ...);
//struct fbuf get_brightness();
void    hook_post_suspend();
int     hook_pre_suspend();
int     hook_rtc_wake(time_t waketime);
void    lock_touch(Display *dpy, int screen);
int     rtc_check_wake(time_t waketime);
void    rtc_close();
int     rtc_init();
time_t  rtc_set_alarm();


@@ 51,6 50,8 @@ void    set_pine_led(enum Color c);
void    set_wakeup_sources();
int     setup_rtc_wakeup();
void    suspend();
void    suspend_init();
void    suspend_reset();
void    writefile(char *filepath, char *str);

// Variables


@@ 82,172 83,147 @@ int rtc_fd = 0;
//time_t waketime = 0; //next wakeup time according to the RTC clock
//int blanked = 0; //indicated whether the display blanked or not

#define RTC_DEVICE	  "/dev/rtc0"
#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);
    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);
}

time_t rtc_set_alarm() {
	//(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);
	time_t waketime = now + WAKE_INTERVAL;

	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;
    //(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);
    time_t waketime = now + WAKE_INTERVAL;

    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 set_wakeup_sources() {
	// Disable all wakeup sources
	struct dirent *wakeupsource;
	char wakeuppath[1024];

	DIR *wakeupsources = opendir("/sys/class/wakeup");
	if (wakeupsources == NULL)
		die("Couldn't open directory /sys/class/wakeup\n");

	while ((wakeupsource = readdir(wakeupsources)) != NULL) {
		sprintf(
			wakeuppath,
			"/sys/class/wakeup/%.50s/device/power/wakeup",
			wakeupsource->d_name
		);
		fprintf(stderr, "Disabling wakeup source: %s", wakeupsource->d_name);
		writefile(wakeuppath, "disabled");
		fprintf(stderr, ".. ok\n");
	}
	closedir(wakeupsources);

	// Enable powerbutton wakeup source
	fprintf(stderr, "Enable powerbutton wakeup source\n");
	writefile(
		"/sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp221-pek/power/wakeup",
		"enabled"
	);

	// Enable IRQ wakeup source (incoming call) 5.8
	fprintf(stderr, "Enable 5.8 IRQ wakeup source\n");
	writefile(
		"/sys/devices/platform/gpio-keys/power/wakeup",
		"enabled"
	 );

	 // Enable IRQ wakeup source (incoming call) 5.9
	fprintf(stderr, "Enable 5.9 IRQ wakeup source\n");
	writefile(
		"/sys/devices/platform/soc/1c28c00.serial/serial1/serial1-0/power/wakeup",
		"enabled"
	 );

	// Enable rtc wakeup source
	fprintf(stderr, "Enable rtc wakeup source\n");
	writefile(
		"/sys/devices/platform/soc/1f00000.rtc/power/wakeup",
		"enabled"
	);

	// E.g. make sure we're using CRUST
	fprintf(stderr, "Flip mem_sleep setting to use crust\n");
	writefile("/sys/power/mem_sleep", "deep");
    // None of the following files can be opened right now
//    // Disable all wakeup sources
//    struct dirent *wakeupsource;
//    char wakeuppath[1024];
//
//    DIR *wakeupsources = opendir("/sys/class/wakeup");
//    if (wakeupsources == NULL)
//        die("Couldn't open directory /sys/class/wakeup\n");
//
//    while ((wakeupsource = readdir(wakeupsources)) != NULL) {
//        sprintf(
//            wakeuppath,
//            "/sys/class/wakeup/%.50s/device/power/wakeup",
//            wakeupsource->d_name
//        );
//        fprintf(stderr, "Disabling wakeup source: %s", wakeupsource->d_name);
//        writefile(wakeuppath, "disabled");
//        fprintf(stderr, ".. ok\n");
//    }
//    closedir(wakeupsources);
//
//    // Enable powerbutton wakeup source
//    fprintf(stderr, "Enable powerbutton wakeup source\n");
//    writefile(
//        "/sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp221-pek/power/wakeup",
//        "enabled"
//    );
//
//    // Enable IRQ wakeup source (incoming call) 5.8
//    fprintf(stderr, "Enable 5.8 IRQ wakeup source\n");
//    writefile(
//        "/sys/devices/platform/gpio-keys/power/wakeup",
//        "enabled"
//     );
//
//     // Enable IRQ wakeup source (incoming call) 5.9
//    fprintf(stderr, "Enable 5.9 IRQ wakeup source\n");
//    writefile(
//        "/sys/devices/platform/soc/1c28c00.serial/serial1/serial1-0/power/wakeup",
//        "enabled"
//     );

    // Enable rtc wakeup source
    fprintf(stderr, "Enable rtc wakeup source\n");
    writefile(
        "/sys/devices/platform/soc/1f00000.rtc/power/wakeup",
        "enabled"
    );

    // E.g. make sure we're using CRUST
    fprintf(stderr, "Flip mem_sleep setting to use crust\n");
    writefile("/sys/power/mem_sleep", "deep");
}

void die(const char *err, ...) {
	fprintf(stderr, "Suspend error: %s\n", err);
    rtc_close(rtc_fd);
    set_pine_led(Off);
    screen_on();
	exit(1);
    fprintf(stderr, "Suspend error: %s\n", err);
    suspend_reset();
    exit(1);
}

void sigterm() {
    die("closed by signal");
}

//struct fbuf get_brightness() {
//    struct fbuf buf = {NULL, 0};
//
//	FILE *f = fopen(BRIGHTNESS_FILE, "r");
//    if (!f)
//        die("failed to read brightness");
//
//    fseek(f, 0, SEEK_END);
//
//    if ((buf.len = ftell(f)) <= 0)
//        die("failed to read brightness");
//
//    fseek(f, 0, SEEK_SET);
//
//    buf.buf = malloc(buf.len);
//    if (fread(buf.buf, 1, buf.len, f) < buf.len)
//        die("failed to read brightness");
//
//    fclose(f);
//
//    return buf;
//}


void lock_touch(Display *dpy, int screen) {
	// Loosely derived from suckless' slock's lockscreen binding logic but
	// alot more coarse, intentionally so can be triggered while grab_key
	// for dwm multikey path already holding..
	int i, ptgrab, kbgrab;
	Window root = RootWindow(dpy, screen);
	for (i = 0, ptgrab = kbgrab = -1; i < 9999999; i++) {
		if (ptgrab != GrabSuccess) {
			ptgrab = XGrabPointer(dpy, root, False,
				ButtonPressMask | ButtonReleaseMask |
				PointerMotionMask, GrabModeAsync,
				GrabModeAsync, None, None, CurrentTime);
		}
		if (kbgrab != GrabSuccess) {
			kbgrab = XGrabKeyboard(dpy, root, True,
				GrabModeAsync, GrabModeAsync, CurrentTime);
		}
		if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
			XSelectInput(dpy, root, SubstructureNotifyMask);
			return;
		}
		usleep(100000);
	}
    // Loosely derived from suckless' slock's lockscreen binding logic but
    // alot more coarse, intentionally so can be triggered while grab_key
    // for dwm multikey path already holding..
    int i, ptgrab, kbgrab;
    Window root = RootWindow(dpy, screen);
    for (i = 0, ptgrab = kbgrab = -1; i < 9999999; i++) {
        if (ptgrab != GrabSuccess) {
            ptgrab = XGrabPointer(dpy, root, False,
                ButtonPressMask | ButtonReleaseMask |
                PointerMotionMask, GrabModeAsync,
                GrabModeAsync, None, None, CurrentTime);
        }
        if (kbgrab != GrabSuccess) {
            kbgrab = XGrabKeyboard(dpy, root, True,
                GrabModeAsync, GrabModeAsync, CurrentTime);
        }
        if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
            XSelectInput(dpy, root, SubstructureNotifyMask);
            return;
        }
        usleep(100000);
    }
}

void screen_off() {


@@ 259,70 235,70 @@ void screen_on() {
}

//void readinputloop(Display *dpy, int screen) {
//	KeySym keysym;
//	XEvent ev;
//	char buf[32];
//	fd_set fdset;
//	int xfd;
//	int selectresult;
//	struct timeval xeventtimeout = {1, 0};
//	xfd = ConnectionNumber(dpy);
//    KeySym keysym;
//    XEvent ev;
//    char buf[32];
//    fd_set fdset;
//    int xfd;
//    int selectresult;
//    struct timeval xeventtimeout = {1, 0};
//    xfd = ConnectionNumber(dpy);
//
//	for (;;) {
//		FD_ZERO(&fdset);
//		FD_SET(xfd, &fdset);
//		if (state == StateSuspendPending)
//			selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, &xeventtimeout);
//		else
//			selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, NULL);
//    for (;;) {
//        FD_ZERO(&fdset);
//        FD_SET(xfd, &fdset);
//        if (state == StateSuspendPending)
//            selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, &xeventtimeout);
//        else
//            selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, NULL);
//
//		if (FD_ISSET(xfd, &fdset) && XPending(dpy)) {
//			XNextEvent(dpy, &ev);
//			if (ev.type == KeyRelease) {
//				XLookupString(&ev.xkey, buf, sizeof(buf), &keysym, 0);
//				if (lastkeysym == keysym) {
//					lastkeyn++;
//				} else {
//					lastkeysym = keysym;
//					lastkeyn = 1;
//				}
//        if (FD_ISSET(xfd, &fdset) && XPending(dpy)) {
//            XNextEvent(dpy, &ev);
//            if (ev.type == KeyRelease) {
//                XLookupString(&ev.xkey, buf, sizeof(buf), &keysym, 0);
//                if (lastkeysym == keysym) {
//                    lastkeyn++;
//                } else {
//                    lastkeysym = keysym;
//                    lastkeyn = 1;
//                }
//
//// Commented out because I want the phone to wake immediately
////				if (lastkeyn < 3)
////					continue;
////                if (lastkeyn < 3)
////                    continue;
//
//				lastkeyn = 0;
//				lastkeysym = XK_Cancel;
//				if (slept) postwake();
//				switch (keysym) {
//					case XF86XK_AudioRaiseVolume:
//						suspendpendingsceenon = state == StateNoInput;
//						suspendpendingtimeouts = 0;
//						state = StateSuspend;
//						break;
//					case XF86XK_AudioLowerVolume:
//						if (state == StateNoInput) state = StateNoInputNoScreen;
//						else if (state == StateNoInputNoScreen) state = StateNoInput;
//						else if (state == StateSuspendPending && suspendpendingsceenon) state = StateNoInputNoScreen;
//						else state = StateNoInput;
//						break;
//					case XF86XK_PowerOff:
//						waketime = 0;
//						state = StateDead;
//						break;
//				}
//				syncstate();
//			}
//		} else if (state == StateSuspendPending) {
//			suspendpendingtimeouts++;
//			// # E.g. after suspendtimeouts seconds kick back into suspend
//			if (suspendpendingtimeouts > suspendtimeouts) state = StateSuspend;
//			syncstate();
//		}
//                lastkeyn = 0;
//                lastkeysym = XK_Cancel;
//                if (slept) postwake();
//                switch (keysym) {
//                    case XF86XK_AudioRaiseVolume:
//                        suspendpendingsceenon = state == StateNoInput;
//                        suspendpendingtimeouts = 0;
//                        state = StateSuspend;
//                        break;
//                    case XF86XK_AudioLowerVolume:
//                        if (state == StateNoInput) state = StateNoInputNoScreen;
//                        else if (state == StateNoInputNoScreen) state = StateNoInput;
//                        else if (state == StateSuspendPending && suspendpendingsceenon) state = StateNoInputNoScreen;
//                        else state = StateNoInput;
//                        break;
//                    case XF86XK_PowerOff:
//                        waketime = 0;
//                        state = StateDead;
//                        break;
//                }
//                syncstate();
//            }
//        } else if (state == StateSuspendPending) {
//            suspendpendingtimeouts++;
//            // # E.g. after suspendtimeouts seconds kick back into suspend
//            if (suspendpendingtimeouts > suspendtimeouts) state = StateSuspend;
//            syncstate();
//        }
//
//
//		if (state == StateDead) break;
//	}
//        if (state == StateDead) break;
//    }
//}

void set_pine_led(enum Color c) {


@@ 330,61 306,60 @@ void set_pine_led(enum Color c) {
    writefile("/sys/class/leds/blue:indicator/brightness", "0");
    writefile("/sys/class/leds/green:indicator/brightness", "0");

	if (c == Red) {
		writefile("/sys/class/leds/red:indicator/brightness", "1");
	} else if (c == Blue) {
		writefile("/sys/class/leds/blue:indicator/brightness", "1");
	} else if (c == Purple) {
		writefile("/sys/class/leds/red:indicator/brightness", "1");
		writefile("/sys/class/leds/blue:indicator/brightness", "1");
	} else if (c == Green) {
		writefile("/sys/class/leds/green:indicator/brightness", "1");
	}
    if (c == Red) {
        writefile("/sys/class/leds/red:indicator/brightness", "1");
    } else if (c == Blue) {
        writefile("/sys/class/leds/blue:indicator/brightness", "1");
    } else if (c == Purple) {
        writefile("/sys/class/leds/red:indicator/brightness", "1");
        writefile("/sys/class/leds/blue:indicator/brightness", "1");
    } else if (c == Green) {
        writefile("/sys/class/leds/green:indicator/brightness", "1");
    }
}

int hook_pre_suspend() {
	//called prior to suspension, a non-zero return value cancels suspension
	return system("sxmo_presuspend.sh");
    //called prior to suspension, a non-zero return value cancels suspension
    return system("sxmo_presuspend.sh");
}

void hook_post_suspend() {
	//called after fully waking up (not used for temporary rtc wakeups)
	system("sxmo_postwake.sh");
    //called after fully waking up (not used for temporary rtc wakeups)
    system("sxmo_postwake.sh");
}

// Returns 0 for rtc wake and 1 for everything else
int rtc_check_wake(time_t waketime) {
    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);
    return !(timediff >= 0 && timediff <= 3);
}

int hook_rtc_wake(time_t waketime) {
	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");
		set_pine_led(Blue);
		return system("sxmo_rtcwake.sh");
	}
	return 0;
    fprintf(stderr, "Calling RTC wake script\n");
    set_pine_led(Blue);
    return system("sxmo_rtcwake.sh");
}

void suspend() {
    fprintf(stderr, "Screenlock entering suspend state (pred mode)\n");

    screen_off();

    set_pine_led(Green);
    fprintf(stderr, "Suspend entering suspend state (pred mode)\n");

    set_wakeup_sources();

	time_t waketime = rtc_set_alarm();
    time_t waketime = rtc_set_alarm();

    die("don't sleep :)");
    writefile((char *)POWER_STATE_FILE, "mem");

    //---- program blocks here due to sleep ----- //
    // Just woke up again
    fprintf(stderr, "Screenlock woke up\n");
    fprintf(stderr, "Suspend woke up\n");
    fprintf(stderr, "Resetting usb connection to the modem\n");
    writefile("/sys/bus/usb/drivers/usb/unbind", "3-1");
    writefile("/sys/bus/usb/drivers/usb/bind", "3-1");


@@ 393,90 368,22 @@ void suspend() {
    //^-- this will be undone again by a networkmanager hook after connection has been established
    //    or by a delayed script if no connection can be established after a while (to conserve battery)

    hook_rtc_wake(waketime);
    if (rtc_check_wake)
        hook_rtc_wake(waketime);

    set_pine_led(Off);

    screen_on();

    fprintf(stderr, "Screenlock exiting suspend state (pred mode)\n");
    fprintf(stderr, "Suspend exiting suspend state (pred mode)\n");
}

//void
//syncstate()
//{
//	int rtcresult;
//	if (state == StateSuspend) {
//		if (presuspend() != 0) {
//			state = StateDead;
//		} else {
//			fprintf(stderr, "Screenlock entering suspend state (pred mode)\n");
//			writefile(brightnessfile, "0");
//			blankscreen();
//			slept = 1;
//			setpineled(Red);
//			configuresuspendsettingsandwakeupsources();
//			writefile(powerstatefile, "mem");
//			//---- program blocks here due to sleep ----- //
//			// Just woke up again
//			fprintf(stderr, "Screenlock woke up\n");
//			fprintf(stderr, "Resetting usb connection to the modem\n");
//			writefile("/sys/bus/usb/drivers/usb/unbind", "3-1");
//			writefile("/sys/bus/usb/drivers/usb/bind", "3-1");
//			fprintf(stderr, "Lower scan interval for quicker reconnection to wireless network\n");
//			writefile("/sys/module/8723cs/parameters/rtw_scan_interval_thr", "1200"); //ms
//			//^-- this will be undone again by a networkmanager hook after connection has been established
//			//    or by a delayed script if no connection can be established after a while (to conserve battery)
//            
//
//			if (waketime > 0) {
//				rtcresult = checkrtcwake();
//			} else {
//				rtcresult = 0;
//			}
//			if (rtcresult == 0) {
//				state = StateSuspendPending;
//				suspendpendingtimeouts = 0;
//			} else {
//				postwake();
//				state = StateDead;
//			}
//		}
//		syncstate();
//	} else if (state == StateNoInput) {
//		fprintf(stderr, "Screenlock in no Input state (blue mode)\n");
//		setpineled(Blue);
//		unblankscreen();
//		writefile(brightnessfile, oldbrightness);
//	} else if (state == StateNoInputNoScreen) {
//		fprintf(stderr, "Screenlock in no screen state (purple mode)\n");
//		setpineled(Purple);
//		writefile(brightnessfile, "0");
//		blankscreen();
//	} else if (state == StateSuspendPending) {
//		fprintf(stderr, "Screenlock is pending suspension\n");
//		if (suspendpendingsceenon) unblankscreen();
//		writefile(brightnessfile, suspendpendingsceenon ? oldbrightness : "0");
//		if (!suspendpendingsceenon) blankscreen();
//		setpineled(Off);
//		usleep(1000 * 100);
//		setpineled(suspendpendingsceenon ? Blue : Purple);
//	} else if (state == StateDead) {
//		unblankscreen();
//		writefile(brightnessfile, oldbrightness);
//		setpineled(Off);
//	}
//}

void writefile(char *filepath, char *str) {
	int f;
	f = open(filepath, O_WRONLY);
	if (f != -1) {
		write(f, str, strlen(str));
		close(f);
	} else {
		fprintf(stderr, "Couldn't open filepath <%s>\n", filepath);
	}
    int f;
    f = open(filepath, O_WRONLY);
    if (f != -1) {
        write(f, str, strlen(str));
        close(f);
    } else {
        fprintf(stderr, "Couldn't open filepath <%s>\n", filepath);
        perror("failed to open file");
    }
}

void rtc_close(int rtc_fd) {


@@ 485,34 392,50 @@ void rtc_close(int rtc_fd) {
}

int rtc_init() {
	rtc_fd = open(RTC_DEVICE, O_RDONLY);
	if (rtc_fd < 0)
		die("Unable to open rtc device");
    rtc_fd = open(RTC_DEVICE, O_RDONLY);
    if (rtc_fd < 0)
        die("Unable to open rtc device");

    return rtc_fd;
}

void suspend_init() {
    rtc_fd = rtc_init();
    screen_off();
    set_pine_led(Green);
}

void suspend_reset() {
    set_pine_led(Off);
    screen_on();
    rtc_close(rtc_fd);
}

int main(int argc, char **argv) {
	signal(SIGTERM, sigterm);
    signal(SIGTERM, sigterm);

    Display *dpy;
	if (!(dpy = XOpenDisplay(NULL)))
		die("Cannot open display");

	rtc_fd = rtc_init();
    if (!(dpy = XOpenDisplay(NULL)))
        die("Cannot open display");

	fprintf(stderr, "Suspend starting\n");
    fprintf(stderr, "Suspend starting\n");

	XkbSetDetectableAutoRepeat(dpy, True, NULL);
	int screen = XDefaultScreen(dpy);
	XSync(dpy, 0);
//	struct fbuf prev_brightness = get_brightness();
    XkbSetDetectableAutoRepeat(dpy, True, NULL);
    int screen = XDefaultScreen(dpy);
    XSync(dpy, 0);
    lock_touch(dpy, screen);

    hook_pre_suspend();

    suspend_init();

    suspend();
//	readinputloop(dpy, screen);
//    readinputloop(dpy, screen);

    suspend_reset();

    hook_post_suspend();
    rtc_close(rtc_fd);
	fprintf(stderr, "Screenlock terminating normally\n");
	return 0;

    fprintf(stderr, "Suspend terminating normally\n");
    return 0;
}