156 lines
3.3 KiB
C
156 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2020 Unisoc Communications Inc.
|
|
*/
|
|
|
|
/*\
|
|
* [Description]
|
|
*
|
|
* RTC device set time function test.
|
|
*
|
|
* [Algorithm]
|
|
*
|
|
* - Save RTC time
|
|
* - Set RTC time
|
|
* - Read the RTC time back
|
|
* - Check if the set time and the read time are identical
|
|
* - Restore RTC time
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "tst_rtctime.h"
|
|
#include "tst_wallclock.h"
|
|
#include "tst_test.h"
|
|
|
|
static char *rtc_dev = "/dev/rtc";
|
|
|
|
static char *rtctime_to_str(struct rtc_time *tm)
|
|
{
|
|
static char rtctime_buf[128];
|
|
|
|
sprintf(rtctime_buf, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
tm->tm_year + 1900,
|
|
tm->tm_mon + 1,
|
|
tm->tm_mday,
|
|
tm->tm_hour,
|
|
tm->tm_min,
|
|
tm->tm_sec);
|
|
return rtctime_buf;
|
|
}
|
|
|
|
static int rtc_tm_cmp(struct rtc_time *set_tm, struct rtc_time *read_tm)
|
|
{
|
|
long delta, seconds1, seconds2;
|
|
|
|
if (set_tm->tm_year != read_tm->tm_year)
|
|
return 1;
|
|
|
|
if (set_tm->tm_mon != read_tm->tm_mon)
|
|
return 1;
|
|
|
|
if (set_tm->tm_mday != read_tm->tm_mday)
|
|
return 1;
|
|
|
|
/*
|
|
* Convert hour/min/sec into seconds to handle the normal
|
|
* and special situations:
|
|
* 1#
|
|
* set_tm: 2022-04-28 13:00:50
|
|
* read_tm: 2022-04-28 13:00:50
|
|
* 2#
|
|
* set_tm: 2022-04-28 13:00:50
|
|
* read_tm: 2022-04-28 13:00:51
|
|
* 3#
|
|
* set_tm: 2022-04-28 13:00:59
|
|
* read_tm: 2022-04-28 13:01:00
|
|
* 4#
|
|
* set_tm: 2022-04-28 13:59:59
|
|
* read_tm: 2022-04-28 14:00:00
|
|
*
|
|
* Note: as we have avoided testing around the zero
|
|
* clock, so it's impossible to hit situation 5#
|
|
* set_tm: 2022-04-28 23:59:59
|
|
* read_tm: 2022-04-29 00:00:00
|
|
*/
|
|
if ((set_tm->tm_hour != read_tm->tm_hour)
|
|
|| (set_tm->tm_min != read_tm->tm_min)
|
|
|| (set_tm->tm_sec != read_tm->tm_sec)) {
|
|
|
|
seconds1 = (set_tm->tm_hour * 3600) + (set_tm->tm_min * 60) + set_tm->tm_sec;
|
|
seconds2 = (read_tm->tm_hour * 3600) + (read_tm->tm_min * 60) + read_tm->tm_sec;
|
|
|
|
delta = seconds2 - seconds1;
|
|
|
|
if (delta < 0 || delta > 3) {
|
|
tst_res(TFAIL, "seconds1 is %ld, seconds2 is %ld", seconds1, seconds2);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void set_rtc_test(void)
|
|
{
|
|
struct rtc_time read_tm, set_tm;
|
|
int ret;
|
|
|
|
/* Read current RTC Time */
|
|
ret = tst_rtc_gettime(rtc_dev, &read_tm);
|
|
if (ret != 0) {
|
|
tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME");
|
|
return;
|
|
}
|
|
|
|
/* set rtc to +/-1 hour */
|
|
set_tm = read_tm;
|
|
if (set_tm.tm_hour == 0)
|
|
set_tm.tm_hour += 1;
|
|
else
|
|
set_tm.tm_hour -= 1;
|
|
|
|
tst_res(TINFO, "To set RTC date/time is: %s", rtctime_to_str(&set_tm));
|
|
|
|
ret = tst_rtc_settime(rtc_dev, &set_tm);
|
|
if (ret != 0) {
|
|
tst_res(TFAIL | TERRNO, "ioctl() RTC_SET_TIME");
|
|
return;
|
|
}
|
|
|
|
/* Read new RTC Time */
|
|
ret = tst_rtc_gettime(rtc_dev, &read_tm);
|
|
if (ret != 0) {
|
|
tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME");
|
|
return;
|
|
}
|
|
tst_res(TINFO, "read RTC date/time is: %s", rtctime_to_str(&read_tm));
|
|
|
|
if (rtc_tm_cmp(&set_tm, &read_tm)) {
|
|
tst_res(TFAIL, "RTC SET TEST");
|
|
return;
|
|
}
|
|
tst_res(TPASS, "The read RTC time is consistent with set time");
|
|
}
|
|
|
|
static void rtc_setup(void)
|
|
{
|
|
int exists = access(rtc_dev, F_OK);
|
|
|
|
if (exists < 0)
|
|
tst_brk(TCONF, "RTC device %s not available", rtc_dev);
|
|
|
|
tst_rtc_clock_save(rtc_dev);
|
|
}
|
|
|
|
static void rtc_cleanup(void)
|
|
{
|
|
tst_rtc_clock_restore(rtc_dev);
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.setup = rtc_setup,
|
|
.test_all = set_rtc_test,
|
|
.cleanup = rtc_cleanup,
|
|
.needs_root = 1,
|
|
};
|