rtc: export RTC_Linux_SwitchInterrupt and RTC_Linux_CheckInterrupt
We have code to enable and disable the RTC's UIE interrupt, as well as check whether it occurred and skip the first interrupt as it may be bogus. This is currently used 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 functions and give them descriptive names appropriate for globally visible functions.
This commit is contained in:
parent
c6e81f25a5
commit
d1b7878781
2 changed files with 65 additions and 54 deletions
116
rtc_linux.c
116
rtc_linux.c
|
@ -497,8 +497,8 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
int
|
||||||
switch_interrupts(int on_off)
|
RTC_Linux_SwitchInterrupt(int fd, int on_off)
|
||||||
{
|
{
|
||||||
if (ioctl(fd, on_off ? RTC_UIE_ON : RTC_UIE_OFF, 0) < 0) {
|
if (ioctl(fd, on_off ? RTC_UIE_ON : RTC_UIE_OFF, 0) < 0) {
|
||||||
LOG(LOGS_ERR, "Could not %s RTC interrupt : %s",
|
LOG(LOGS_ERR, "Could not %s RTC interrupt : %s",
|
||||||
|
@ -529,7 +529,7 @@ RTC_Linux_Initialise(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the RTC supports interrupts */
|
/* Make sure the RTC supports interrupts */
|
||||||
if (!switch_interrupts(1) || !switch_interrupts(0)) {
|
if (!RTC_Linux_SwitchInterrupt(fd, 1) || !RTC_Linux_SwitchInterrupt(fd, 0)) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -578,7 +578,7 @@ RTC_Linux_Finalise(void)
|
||||||
/* Remove input file handler */
|
/* Remove input file handler */
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
SCH_RemoveFileHandler(fd);
|
SCH_RemoveFileHandler(fd);
|
||||||
switch_interrupts(0);
|
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
/* Save the RTC data */
|
/* Save the RTC data */
|
||||||
|
@ -599,7 +599,7 @@ static void
|
||||||
measurement_timeout(void *any)
|
measurement_timeout(void *any)
|
||||||
{
|
{
|
||||||
timeout_id = 0;
|
timeout_id = 0;
|
||||||
switch_interrupts(1);
|
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -760,15 +760,11 @@ process_reading(time_t rtc_time, struct timespec *system_time)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static void
|
int
|
||||||
read_from_device(int fd_, int event, void *any)
|
RTC_Linux_CheckInterrupt(int fd)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
unsigned long data;
|
unsigned long data;
|
||||||
struct timespec sys_time;
|
|
||||||
struct rtc_time rtc_raw;
|
|
||||||
time_t rtc_t;
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
status = read(fd, &data, sizeof(data));
|
status = read(fd, &data, sizeof(data));
|
||||||
|
|
||||||
|
@ -776,56 +772,68 @@ read_from_device(int fd_, int event, void *any)
|
||||||
/* This looks like a bad error : the file descriptor was indicating it was
|
/* This looks like a bad error : the file descriptor was indicating it was
|
||||||
* ready to read but we couldn't read anything. Give up. */
|
* ready to read but we couldn't read anything. Give up. */
|
||||||
LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
||||||
SCH_RemoveFileHandler(fd);
|
return -1;
|
||||||
switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
|
}
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skip_interrupts > 0) {
|
if (skip_interrupts > 0) {
|
||||||
/* Wait for the next interrupt, this one may be bogus */
|
/* Wait for the next interrupt, this one may be bogus */
|
||||||
skip_interrupts--;
|
skip_interrupts--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update interrupt detected? */
|
||||||
|
return (data & RTC_UF) == RTC_UF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_from_device(int fd_, int event, void *any)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
struct timespec sys_time;
|
||||||
|
struct rtc_time rtc_raw;
|
||||||
|
time_t rtc_t;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
status = RTC_Linux_CheckInterrupt(fd);
|
||||||
|
if (status < 0) {
|
||||||
|
SCH_RemoveFileHandler(fd);
|
||||||
|
RTC_Linux_SwitchInterrupt(fd, 0); /* Likely to raise error too, but just to be sure... */
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return;
|
||||||
|
} else if (status == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((data & RTC_UF) == RTC_UF) {
|
SCH_GetLastEventTime(&sys_time, NULL, NULL);
|
||||||
/* Update interrupt detected */
|
|
||||||
|
|
||||||
/* Read RTC time, sandwiched between two polls of the system clock
|
|
||||||
so we can bound any error. */
|
|
||||||
|
|
||||||
SCH_GetLastEventTime(&sys_time, NULL, NULL);
|
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
||||||
|
if (status < 0) {
|
||||||
|
LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
||||||
|
error = 1;
|
||||||
|
goto turn_off_interrupt;
|
||||||
|
}
|
||||||
|
|
||||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
/* Convert RTC time into a struct timespec */
|
||||||
if (status < 0) {
|
rtc_t = t_from_rtc(&rtc_raw, rtc_on_utc);
|
||||||
LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
|
||||||
error = 1;
|
|
||||||
goto turn_off_interrupt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert RTC time into a struct timespec */
|
if (rtc_t == (time_t)(-1)) {
|
||||||
rtc_t = t_from_rtc(&rtc_raw, rtc_on_utc);
|
error = 1;
|
||||||
|
goto turn_off_interrupt;
|
||||||
|
}
|
||||||
|
|
||||||
if (rtc_t == (time_t)(-1)) {
|
process_reading(rtc_t, &sys_time);
|
||||||
error = 1;
|
|
||||||
goto turn_off_interrupt;
|
|
||||||
}
|
|
||||||
|
|
||||||
process_reading(rtc_t, &sys_time);
|
|
||||||
|
|
||||||
if (n_samples < 4) {
|
|
||||||
measurement_period = LOWEST_MEASUREMENT_PERIOD;
|
|
||||||
} else if (n_samples < 6) {
|
|
||||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 1;
|
|
||||||
} else if (n_samples < 10) {
|
|
||||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 2;
|
|
||||||
} else if (n_samples < 14) {
|
|
||||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 3;
|
|
||||||
} else {
|
|
||||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (n_samples < 4) {
|
||||||
|
measurement_period = LOWEST_MEASUREMENT_PERIOD;
|
||||||
|
} else if (n_samples < 6) {
|
||||||
|
measurement_period = LOWEST_MEASUREMENT_PERIOD << 1;
|
||||||
|
} else if (n_samples < 10) {
|
||||||
|
measurement_period = LOWEST_MEASUREMENT_PERIOD << 2;
|
||||||
|
} else if (n_samples < 14) {
|
||||||
|
measurement_period = LOWEST_MEASUREMENT_PERIOD << 3;
|
||||||
|
} else {
|
||||||
|
measurement_period = LOWEST_MEASUREMENT_PERIOD << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
turn_off_interrupt:
|
turn_off_interrupt:
|
||||||
|
@ -837,7 +845,7 @@ turn_off_interrupt:
|
||||||
operating_mode = OM_NORMAL;
|
operating_mode = OM_NORMAL;
|
||||||
(after_init_hook)(after_init_hook_arg);
|
(after_init_hook)(after_init_hook_arg);
|
||||||
|
|
||||||
switch_interrupts(0);
|
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||||
|
|
||||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||||
}
|
}
|
||||||
|
@ -849,7 +857,7 @@ turn_off_interrupt:
|
||||||
DEBUG_LOG("Could not complete after trim relock due to errors");
|
DEBUG_LOG("Could not complete after trim relock due to errors");
|
||||||
operating_mode = OM_NORMAL;
|
operating_mode = OM_NORMAL;
|
||||||
|
|
||||||
switch_interrupts(0);
|
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||||
|
|
||||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||||
}
|
}
|
||||||
|
@ -857,7 +865,7 @@ turn_off_interrupt:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OM_NORMAL:
|
case OM_NORMAL:
|
||||||
switch_interrupts(0);
|
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||||
|
|
||||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||||
|
|
||||||
|
@ -879,7 +887,7 @@ RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything)
|
||||||
|
|
||||||
operating_mode = OM_INITIAL;
|
operating_mode = OM_INITIAL;
|
||||||
timeout_id = 0;
|
timeout_id = 0;
|
||||||
switch_interrupts(1);
|
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
@ -1058,7 +1066,7 @@ RTC_Linux_Trim(void)
|
||||||
/* And start rapid sampling, interrupts on now */
|
/* And start rapid sampling, interrupts on now */
|
||||||
SCH_RemoveTimeout(timeout_id);
|
SCH_RemoveTimeout(timeout_id);
|
||||||
timeout_id = 0;
|
timeout_id = 0;
|
||||||
switch_interrupts(1);
|
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -42,4 +42,7 @@ extern int RTC_Linux_Trim(void);
|
||||||
|
|
||||||
extern void RTC_Linux_CycleLogFile(void);
|
extern void RTC_Linux_CycleLogFile(void);
|
||||||
|
|
||||||
|
extern int RTC_Linux_SwitchInterrupt(int fd, int on_off);
|
||||||
|
extern int RTC_Linux_CheckInterrupt(int fd);
|
||||||
|
|
||||||
#endif /* _GOT_RTC_LINUX_H */
|
#endif /* _GOT_RTC_LINUX_H */
|
||||||
|
|
Loading…
Reference in a new issue