Edit online

Demo

26 Nov 2024
Read time: 4 minute(s)
本次 Demo 是通过 ioctl 接口来访问设备节点 /dev/rtc0
#include "base.h"
#include <sys/time.h>
#include <linux/rtc.h>

/* Global macro and variables */

#define ALARM_MAX_DELAY     (60 * 60)
#define ALARM_MIN_DELAY     1

static const char sopts[] = "d:u";
static const struct option lopts[] = {
    {"delay",     required_argument, NULL, 'd'},
    {"usage",       no_argument, NULL, 'u'},
    {0, 0, 0, 0}
};

/* Functions */

void usage(char *program)
{
    printf("Usage: %s will start a timer of given seconds, and wait it\n",
        program);
    printf("\t -d, --delay\trange: [%d, %d]\n", ALARM_MIN_DELAY,
        ALARM_MAX_DELAY);
    printf("\t -u, --usage \n");
    printf("\n");
    printf("Example: %s -d 12\n\n", program);
}

/* Open a device file to be needed. */
int device_open(char *_fname, int _flag)
{
    s32 fd = -1;

    fd = open(_fname, _flag);
    if (fd < 0) {
        ERR("Failed to open %s errno: %d[%s]\n",
            _fname, errno, strerror(errno));
        exit(0);
    }
    return fd;
}

int main(int argc, char **argv)
{
    int c, ret;
    int delay = 0;
    int rtc_fd = -1;
    time_t tmp = 0;
    struct rtc_time start = {0};
    struct rtc_time end = {0};
    struct rtc_wkalrm alrm_set = {0};
    struct rtc_wkalrm alrm_get = {0};

    DBG("Compile time: %s\n", __TIME__);
    while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
        switch (c) {
        case 'd':
            delay = str2int(optarg);
            continue;
        case 'u':
            usage(argv[0]);
            return 0;
        default:
            break;
        }
    }

    if ((delay < ALARM_MIN_DELAY) || (delay > ALARM_MAX_DELAY)) {
        ERR("Invalid delay: %d\n", delay);
        return -1;
    }

    rtc_fd = open("/dev/rtc0", O_RDWR);
    if (rtc_fd < 0) {
        ERR("Failed to open RTC device!\n");
        return -1;
    }

    DBG("ioctl(%#x)\n", RTC_RD_TIME);
    ret = ioctl(rtc_fd, RTC_RD_TIME, &start);
    if (ret < 0) {
        ERR("Failed to read RTC time!\n");
        goto err;
    }
    DBG("Current time: %04d-%02d-%02d %02d:%02d:%02d\n",
        start.tm_year, start.tm_mon, start.tm_mday,
        start.tm_hour, start.tm_min, start.tm_sec);

    alrm_set.enabled = 1;
    tmp = mktime((struct tm *)&start) + delay;
    memcpy(&alrm_set.time, gmtime(&tmp), sizeof(struct rtc_time));
    DBG("ioctl(%#x)\n", RTC_WKALM_SET);
    ret = ioctl(rtc_fd, RTC_WKALM_SET, &alrm_set);
    if (ret < 0) {
        ERR("Failed to set alarm! [%d]: %s\n", errno, strerror(errno));
        goto err;
    }
    DBG("Set a alarm to: %04d-%02d-%02d %02d:%02d:%02d\n",
        alrm_set.time.tm_year, alrm_set.time.tm_mon,
        alrm_set.time.tm_mday, alrm_set.time.tm_hour,
        alrm_set.time.tm_min, alrm_set.time.tm_sec);

    do {
        memset(&alrm_get, 0, sizeof(struct rtc_wkalrm));
        DBG("ioctl(%#x)\n", RTC_WKALM_RD);
        ret = ioctl(rtc_fd, RTC_WKALM_RD, &alrm_get);
        if (ret < 0) {
            ERR("Failed to read alarm!\n");
            goto err;
        }
        if (alrm_get.pending)
            break;

        printf("Waiting ...\n");
        usleep(200000); // 200ms
    } while (1);

    DBG("ioctl(%#x)\n", RTC_RD_TIME);
    ret = ioctl(rtc_fd, RTC_RD_TIME, &end);
    if (ret < 0) {
        ERR("Failed to read RTC time!\n");
        goto err;
    }
    DBG("Current time: %04d-%02d-%02d %02d:%02d:%02d\n",
        end.tm_year, end.tm_mon, end.tm_mday,
        end.tm_hour, end.tm_min, end.tm_sec);

    tmp = mktime((struct tm *)&end) - mktime((struct tm *)&start);
    DBG("Start a timer of %d, actualy is %ld ...\n", delay, tmp);
    if (ret != delay) {
        ERR("The timer is not accurate!\n");
        ret = -1;
    }
    else {
        DBG("The timer is good!\n");
        ret = 0;
    }

err:
    if (rtc_fd > 0)
        close(rtc_fd);
    return ret;
}