/* * wkalrm.c - Use the RTC alarm to wake us up * * Copyright (C) 2008 by OpenMoko, Inc. * Written by Werner Almesberger * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #define DEFAULT_RTC "/dev/rtc0" static const char *device = DEFAULT_RTC; static int fd; /* ----- Low-level wrappers ------------------------------------------------ */ static void read_alarm(struct rtc_wkalrm *alarm) { int res; res = ioctl(fd, RTC_WKALM_RD, alarm); if (res < 0) { perror("ioctl(RTC_WKALM_RD)"); exit(1); } } static void read_time(struct rtc_time *tm) { int res; res = ioctl(fd, RTC_RD_TIME, tm); if (res < 0) { perror("ioctl(RTC_RD_TIME)"); exit(1); } } static void write_alarm(const struct rtc_wkalrm *alarm) { int res; res = ioctl(fd, RTC_WKALM_SET, alarm); if (res < 0) { perror("ioctl(RTC_WKALM_SET)"); exit(1); } } /* ----- Date conversions -------------------------------------------------- */ static void show_alarm(void) { struct rtc_wkalrm alarm; read_alarm(&alarm); if (!alarm.enabled) printf("alarm disabled%s\n", alarm.pending ? " (pending)" : ""); else printf("%02d:%02d:%02d %04d-%02d-%02d%s\n", alarm.time.tm_hour, alarm.time.tm_min, alarm.time.tm_sec, alarm.time.tm_year+1900, alarm.time.tm_mon+1, alarm.time.tm_mday, alarm.pending ? " (pending)" : ""); } static void set_alarm_abs(const char *t, const char *day) { fprintf(stderr, "not yet implemented :-)\n"); exit(1); } static void set_alarm_delta(time_t delta) { struct rtc_wkalrm alarm; struct tm tm, *tmp; time_t t; read_time(&alarm.time); memset(&tm, 0, sizeof(tm)); tm.tm_sec = alarm.time.tm_sec; tm.tm_min = alarm.time.tm_min; tm.tm_hour = alarm.time.tm_hour; tm.tm_mday = alarm.time.tm_mday; tm.tm_mon = alarm.time.tm_mon; tm.tm_year = alarm.time.tm_year; t = mktime(&tm); if (t == (time_t) -1) { fprintf(stderr, "mktime: error\n"); exit(1); } t += delta; tmp = localtime(&t); if (!tmp) { fprintf(stderr, "localtime_r: error\n"); exit(1); } alarm.time.tm_sec = tmp->tm_sec; alarm.time.tm_min = tmp->tm_min; alarm.time.tm_hour = tmp->tm_hour; alarm.time.tm_mday = tmp->tm_mday; alarm.time.tm_mon = tmp->tm_mon; alarm.time.tm_year = tmp->tm_year; alarm.enabled = 1; write_alarm(&alarm); } static void set_alarm_rel(const char *delta) { unsigned long n; char *end; n = strtoul(delta, &end, 10); if (!strcmp(end, "d") || !strcmp(end, "day") || !strcmp(end, "days")) n *= 24*3600; else if (!strcmp(end, "h") || !strcmp(end, "hour") || !strcmp(end, "hours")) n *= 3600; else if (!strcmp(end, "m") || !strcmp(end, "min") || !strcmp(end, "mins")) n *= 60; else if (strcmp(end, "s") && strcmp(end, "sec") && strcmp(end, "secs")) { fprintf(stderr, "invalid delta time \"%s\"\n", delta); exit(1); } set_alarm_delta(n); } static void disable_alarm(void) { struct rtc_wkalrm alarm; read_alarm(&alarm); alarm.enabled = 0; write_alarm(&alarm); } static void set_alarm_24h(const char *t) { fprintf(stderr, "not yet implemented :-)\n"); exit(1); } static void set_alarm(const char *when) { if (*when == '+') set_alarm_rel(when+1); else set_alarm_24h(when); } /* ----- Command line parsing ---------------------------------------------- */ static void usage(const char *name) { fprintf(stderr, "usage: %s [-d device]\n" " %s [-d device] hh:mm[:ss] [[yyyy-]mm-dd]\n" " %s [-d device] +Nunit\n\n" " unit is d[ay[s]], h[our[s]] m[in[s]], or s[ec[s]]\n\n" " -d device open the specified RTC device (default: %s)\n" , name, name, name, DEFAULT_RTC); exit(1); } int main(int argc, char **argv) { int c; while ((c = getopt(argc, argv, "d:")) != EOF) switch (c) { case 'd': device = optarg; break; default: usage(*argv); } fd = open(device, O_RDWR); if (fd < 0) { perror(device); exit(1); } switch (argc-optind) { case 0: show_alarm(); break; case 1: if (!strcmp(argv[optind], "off")) disable_alarm(); else set_alarm(argv[optind]); break; case 2: set_alarm_abs(argv[optind], argv[optind+1]); break; default: usage(*argv); } return 0; }