Ejemplo n.º 1
0
static void
handle_initial_trim(void)
{
  double rate;
  long delta_time;
  double rtc_error_now, sys_error_now;

    /* The idea is to accumulate some number of samples at 1 second
       intervals, then do a robust regression fit to this.  This
       should give a good fix on the intercept (=system clock error
       rel to RTC) at a particular time, removing risk of any
       particular sample being an outlier.  We can then look at the
       elapsed interval since the epoch recorded in the RTC file,
       and correct the system time accordingly. */
    
  run_regression(1, &coefs_valid, &coef_ref_time, &coef_seconds_fast, &coef_gain_rate);

  n_samples_since_regression = 0;

  /* Set sample number to -1 so the next sample is not used, as it will not yet be corrected for System Trim*/

  n_samples = -1;


  read_coefs_from_file();

  if (valid_coefs_from_file) {
    /* Can process data */
    delta_time = coef_ref_time - file_ref_time;
    rate = 1.0e-6 * file_rate_ppm;
    rtc_error_now = file_ref_offset + rate * (double) delta_time;
          
    /* sys_error_now is positive if the system clock is fast */
    sys_error_now = rtc_error_now - coef_seconds_fast;
          
    LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
    LCL_AccumulateOffset(sys_error_now, 0.0);
  } else {
    LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
  }
  
  coefs_valid = 0;
  
  (after_init_hook)(after_init_hook_arg);
  
  operating_mode = OM_NORMAL;

  return;
}
Ejemplo n.º 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;
}
Ejemplo n.º 3
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);
}