rtc: factor out RTC_Linux_ReadTime_Now

We have code to read RTC time and handle the error associated with
having no UIE interrupt, which we currently use as part of maintaining
the correction file.

In a later commit, we will need the same functionality for using the RTC
as reference clock, so export the function and give it a descriptive
name appropriate for a globally visible function.
This commit is contained in:
Ahmad Fatoum 2024-07-22 17:46:44 +02:00
parent 577cf09bc5
commit 5ce34d07fb
2 changed files with 53 additions and 48 deletions

View file

@ -930,6 +930,28 @@ RTC_Linux_WriteParameters(void)
return(retval);
}
time_t
RTC_Linux_ReadTime_Now(int fd, int utc, struct timespec *old_sys_time)
{
struct rtc_time rtc_raw, rtc_raw_retry;
int status;
/* Retry reading the rtc until both read attempts give the same sec value.
This way the race condition is prevented that the RTC has updated itself
during the first read operation. */
do {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status >= 0) {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
}
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
/* Read system clock */
LCL_ReadCookedTime(old_sys_time, NULL);
return status >= 0 ? t_from_rtc(&rtc_raw, utc) : -1;
}
/* ================================================== */
/* Try to set the system clock from the RTC, in the same manner as
/sbin/hwclock -s would do. We're not as picky about OS version
@ -939,8 +961,7 @@ RTC_Linux_WriteParameters(void)
int
RTC_Linux_TimePreInit(time_t driftfile_time)
{
int fd, status;
struct rtc_time rtc_raw, rtc_raw_retry;
int fd;
time_t rtc_t;
double accumulated_error, sys_offset;
struct timespec new_sys_time, old_sys_time;
@ -956,59 +977,41 @@ RTC_Linux_TimePreInit(time_t driftfile_time)
return 0; /* Can't open it, and won't be able to later */
}
/* Retry reading the rtc until both read attempts give the same sec value.
This way the race condition is prevented that the RTC has updated itself
during the first read operation. */
do {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
if (status >= 0) {
status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
}
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
/* Read system clock */
LCL_ReadCookedTime(&old_sys_time, NULL);
rtc_t = RTC_Linux_ReadTime_Now(fd, rtc_on_utc, &old_sys_time);
close(fd);
if (status >= 0) {
/* Convert to seconds since 1970 */
rtc_t = t_from_rtc(&rtc_raw, rtc_on_utc);
if (rtc_t != (time_t)(-1)) {
if (rtc_t != (time_t)(-1)) {
/* Work out approximatation to correct time (to about the
nearest second) */
if (valid_coefs_from_file) {
accumulated_error = file_ref_offset +
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
} else {
accumulated_error = 0.0;
}
/* Correct time */
new_sys_time.tv_sec = rtc_t;
/* Average error in the RTC reading */
new_sys_time.tv_nsec = 500000000;
UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
if (new_sys_time.tv_sec < driftfile_time) {
LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
return 0;
}
sys_offset = UTI_DiffTimespecsToDouble(&old_sys_time, &new_sys_time);
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
if (LCL_ApplyStepOffset(sys_offset))
LOG(LOGS_INFO, "System time set from RTC");
}
/* Work out approximatation to correct time (to about the
nearest second) */
if (valid_coefs_from_file) {
accumulated_error = file_ref_offset +
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
} else {
accumulated_error = 0.0;
}
/* Correct time */
new_sys_time.tv_sec = rtc_t;
/* Average error in the RTC reading */
new_sys_time.tv_nsec = 500000000;
UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
if (new_sys_time.tv_sec < driftfile_time) {
LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
return 0;
}
sys_offset = UTI_DiffTimespecsToDouble(&old_sys_time, &new_sys_time);
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
if (LCL_ApplyStepOffset(sys_offset))
LOG(LOGS_INFO, "System time set from RTC");
}
} else {
return 0;
}

View file

@ -46,5 +46,7 @@ extern int RTC_Linux_SwitchInterrupt(int fd, int on_off);
extern int RTC_Linux_CheckInterrupt(int fd);
extern time_t RTC_Linux_ReadTime_AfterInterrupt(int fd, int utc,
struct timespec *sys_time_cooked);
extern time_t RTC_Linux_ReadTime_Now(int fd, int utc,
struct timespec *sys_time_cooked);
#endif /* _GOT_RTC_LINUX_H */