Пример #1
0
int
RTC_Linux_Initialise(void)
{
  rtc_sec = MallocArray(time_t, MAX_SAMPLES);
  rtc_trim = MallocArray(double, MAX_SAMPLES);
  system_times = MallocArray(struct timeval, MAX_SAMPLES);

  /* Setup details depending on configuration options */
  setup_config();

  /* In case it didn't get done by pre-init */
  coefs_file_name = CNF_GetRtcFile();

  /* Try to open device */

  fd = open (CNF_GetRtcDevice(), O_RDWR);
  if (fd < 0) {
    LOG(LOGS_ERR, LOGF_RtcLinux, "Could not open RTC device %s : %s",
        CNF_GetRtcDevice(), strerror(errno));
    return 0;
  }

  /* Close on exec */
  UTI_FdSetCloexec(fd);

  n_samples = 0;
  n_samples_since_regression = 0;
  n_runs = 0;
  coefs_valid = 0;

  measurement_period = LOWEST_MEASUREMENT_PERIOD;

  operating_mode = OM_NORMAL;

  /* Register file handler */
  SCH_AddInputFileHandler(fd, read_from_device, NULL);

  /* Register slew handler */
  LCL_AddParameterChangeHandler(slew_samples, NULL);

  logfileid = CNF_GetLogRtc() ? LOG_FileOpen("rtc",
      "   Date (UTC) Time   RTC fast (s) Val   Est fast (s)   Slope (ppm)  Ns  Nr Meas")
    : -1;
  return 1;
}
Пример #2
0
int
RTC_Linux_TimePreInit(time_t driftfile_time)
{
  int fd, status;
  struct rtc_time rtc_raw, rtc_raw_retry;
  struct tm rtc_tm;
  time_t rtc_t;
  double accumulated_error, sys_offset;
  struct timeval new_sys_time, old_sys_time;

  coefs_file_name = CNF_GetRtcFile();

  setup_config();
  read_coefs_from_file();

  fd = open(CNF_GetRtcDevice(), O_RDONLY);

  if (fd < 0) {
    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);

  close(fd);

  if (status >= 0) {
    /* Convert to seconds since 1970 */
    rtc_tm.tm_sec = rtc_raw.tm_sec;
    rtc_tm.tm_min = rtc_raw.tm_min;
    rtc_tm.tm_hour = rtc_raw.tm_hour;
    rtc_tm.tm_mday = rtc_raw.tm_mday;
    rtc_tm.tm_mon = rtc_raw.tm_mon;
    rtc_tm.tm_year = rtc_raw.tm_year;
    
    rtc_t = t_from_rtc(&rtc_tm);

    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_usec = 500000;

      UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);

      if (new_sys_time.tv_sec < driftfile_time) {
        LOG(LOGS_WARN, LOGF_RtcLinux, "RTC time before last driftfile modification (ignored)");
        return 0;
      }

      UTI_DiffTimevalsToDouble(&sys_offset, &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, LOGF_RtcLinux, "System time set from RTC");
      }
    } else {
      return 0;
    }
  } else {
    return 0;
  }

  return 1;
}
Пример #3
0
static void
read_from_device(void *any)
{
  int status;
  unsigned long data;
  struct timeval sys_time;
  struct rtc_time rtc_raw;
  struct tm rtc_tm;
  time_t rtc_t;
  int error = 0;

  status = read(fd, &data, sizeof(data));

  if (status < 0) {
    /* This looks like a bad error : the file descriptor was indicating it was
     * ready to read but we couldn't read anything.  Give up. */
    LOG(LOGS_ERR, LOGF_RtcLinux, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
    SCH_RemoveInputFileHandler(fd);
    switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
    close(fd);
    fd = -1;
    return;
  }    

  if (skip_interrupts > 0) {
    /* Wait for the next interrupt, this one may be bogus */
    skip_interrupts--;
    return;
  }

  if ((data & RTC_UF) == RTC_UF) {
    /* 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, LOGF_RtcLinux, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
      error = 1;
      goto turn_off_interrupt;
    }

    /* Convert RTC time into a struct timeval */
    rtc_tm.tm_sec = rtc_raw.tm_sec;
    rtc_tm.tm_min = rtc_raw.tm_min;
    rtc_tm.tm_hour = rtc_raw.tm_hour;
    rtc_tm.tm_mday = rtc_raw.tm_mday;
    rtc_tm.tm_mon = rtc_raw.tm_mon;
    rtc_tm.tm_year = rtc_raw.tm_year;

    rtc_t = t_from_rtc(&rtc_tm);

    if (rtc_t == (time_t)(-1)) {
      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;
    }

  }

turn_off_interrupt:

  switch (operating_mode) {
    case OM_INITIAL:
      if (error) {
        DEBUG_LOG(LOGF_RtcLinux, "Could not complete initial step due to errors");
        operating_mode = OM_NORMAL;
        (after_init_hook)(after_init_hook_arg);

        switch_interrupts(0);
    
        timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
      }

      break;

    case OM_AFTERTRIM:
      if (error) {
        DEBUG_LOG(LOGF_RtcLinux, "Could not complete after trim relock due to errors");
        operating_mode = OM_NORMAL;

        switch_interrupts(0);
    
        timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
      }
      
      break;

    case OM_NORMAL:
      switch_interrupts(0);
    
      timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);

      break;
    default:
      assert(0);
      break;
  }

}
Пример #4
0
void
RTC_Linux_TimePreInit(void)
{
  int fd, status;
  struct rtc_time rtc_raw;
  struct tm rtc_tm;
  time_t rtc_t, estimated_correct_rtc_t;
  long interval;
  double accumulated_error = 0.0;
  struct timeval new_sys_time, old_sys_time;

  coefs_file_name = CNF_GetRtcFile();

  setup_config();
  read_coefs_from_file();

  fd = open(CNF_GetRtcDevice(), O_RDONLY);

  if (fd < 0) {
    return; /* Can't open it, and won't be able to later */
  }

  status = ioctl(fd, RTC_RD_TIME, &rtc_raw);

  if (status >= 0) {
    /* Convert to seconds since 1970 */
    rtc_tm.tm_sec = rtc_raw.tm_sec;
    rtc_tm.tm_min = rtc_raw.tm_min;
    rtc_tm.tm_hour = rtc_raw.tm_hour;
    rtc_tm.tm_mday = rtc_raw.tm_mday;
    rtc_tm.tm_mon = rtc_raw.tm_mon;
    rtc_tm.tm_year = rtc_raw.tm_year;
    
    rtc_t = t_from_rtc(&rtc_tm);

    if (rtc_t != (time_t)(-1)) {

      /* Work out approximatation to correct time (to about the
         nearest second) */
      if (valid_coefs_from_file) {
        interval = rtc_t - file_ref_time;
        accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;

        /* Correct time */
        estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
      } else {
        estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
      }

      new_sys_time.tv_sec = estimated_correct_rtc_t;
      new_sys_time.tv_usec = 0;

      /* Set system time only if the step is larger than 1 second */
      if (!(gettimeofday(&old_sys_time, NULL) < 0) &&
          (old_sys_time.tv_sec - new_sys_time.tv_sec > 1 ||
           old_sys_time.tv_sec - new_sys_time.tv_sec < -1)) {

        LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
            accumulated_error);

        /* Tough luck if this fails */
        if (settimeofday(&new_sys_time, NULL) < 0) {
          LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
        }
      }
    } else {
      LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
    }
  }

  close(fd);
}