Ejemplo n.º 1
0
static void
handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
            double doffset, LCL_ChangeType change_type, void *anything)
{
  if (change_type == LCL_ChangeUnknownStep) {
    /* Reset offset and slewing */
    slew_start = *raw;
    offset_register = 0.0;
    update_slew();
  } else if (change_type == LCL_ChangeStep) {
    UTI_AddDoubleToTimeval(&slew_start, -doffset, &slew_start);
  }
}
Ejemplo n.º 2
0
static void
apply_step_offset(double offset)
{
  struct timeval old_time, new_time, T1;
  
  stop_adjust();

  if (gettimeofday(&old_time, NULL) < 0) {
    LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
  }

  UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);

  if (settimeofday(&new_time, NULL) < 0) {
    LOG_FATAL(LOGF_SysNetBSD, "settimeofday() failed");
  }

  UTI_AddDoubleToTimeval(&T0, offset, &T1);
  T0 = T1;

  start_adjust();

}
Ejemplo n.º 3
0
static int
apply_step_offset(double offset)
{
  struct timeval old_time, new_time;
  double err;

  LCL_ReadRawTime(&old_time);
  UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);

  if (PRV_SetTime(&new_time, NULL) < 0) {
    DEBUG_LOG(LOGF_SysGeneric, "settimeofday() failed");
    return 0;
  }

  LCL_ReadRawTime(&old_time);
  UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);

  lcl_InvokeDispersionNotifyHandlers(fabs(err));

  return 1;
}
Ejemplo n.º 4
0
static void
update_slew(void)
{
  struct timeval now, end_of_slew;
  double old_slew_freq, total_freq, corr_freq, duration;

  /* Remove currently running timeout */
  SCH_RemoveTimeout(slew_timeout_id);

  LCL_ReadRawTime(&now);

  /* Adjust the offset register by achieved slew */
  UTI_DiffTimevalsToDouble(&duration, &now, &slew_start);
  offset_register -= slew_freq * duration;

  stop_fastslew(&now);

  /* Estimate how long should the next slew take */
  if (fabs(offset_register) < MIN_OFFSET_CORRECTION) {
    duration = MAX_SLEW_TIMEOUT;
  } else {
    duration = correction_rate / fabs(offset_register);
    if (duration < MIN_SLEW_TIMEOUT)
      duration = MIN_SLEW_TIMEOUT;
  }

  /* Get frequency offset needed to slew the offset in the duration
     and clamp it to the allowed maximum */
  corr_freq = offset_register / duration;
  if (corr_freq < -max_corr_freq)
    corr_freq = -max_corr_freq;
  else if (corr_freq > max_corr_freq)
    corr_freq = max_corr_freq;

  /* Let the system driver perform the slew if the requested frequency
     offset is too large for the frequency driver */
  if (drv_accrue_offset && fabs(corr_freq) >= fastslew_max_rate &&
      fabs(offset_register) > fastslew_min_offset) {
    start_fastslew();
    corr_freq = 0.0;
  }

  /* Get the new real frequency and clamp it */
  total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));

  /* Set the new frequency (the actual frequency returned by the call may be
     slightly different from the requested frequency due to rounding) */
  total_freq = (*drv_set_freq)(total_freq);

  /* Compute the new slewing frequency, it's relative to the real frequency to
     make the calculation in offset_convert() cheaper */
  old_slew_freq = slew_freq;
  slew_freq = (total_freq - base_freq) / (1.0e6 - total_freq);

  /* Compute the dispersion introduced by changing frequency and add it
     to all statistics held at higher levels in the system */
  slew_error = fabs((old_slew_freq - slew_freq) * max_freq_change_delay);
  if (slew_error >= MIN_OFFSET_CORRECTION)
    lcl_InvokeDispersionNotifyHandlers(slew_error);

  /* Compute the duration of the slew and clamp it.  If the slewing frequency
     is zero or has wrong sign (e.g. due to rounding in the frequency driver or
     when base_freq is larger than max_freq, or fast slew is active), use the
     maximum timeout and try again on the next update. */
  if (fabs(offset_register) < MIN_OFFSET_CORRECTION ||
      offset_register * slew_freq <= 0.0) {
    duration = MAX_SLEW_TIMEOUT;
  } else {
    duration = offset_register / slew_freq;
    if (duration < MIN_SLEW_TIMEOUT)
      duration = MIN_SLEW_TIMEOUT;
    else if (duration > MAX_SLEW_TIMEOUT)
      duration = MAX_SLEW_TIMEOUT;
  }

  /* Restart timer for the next update */
  UTI_AddDoubleToTimeval(&now, duration, &end_of_slew);
  slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
  slew_start = now;

  DEBUG_LOG(LOGF_SysGeneric, "slew offset=%e corr_rate=%e base_freq=%f total_freq=%f slew_freq=%e duration=%f slew_error=%e",
      offset_register, correction_rate, base_freq, total_freq, slew_freq,
      duration, slew_error);
}
Ejemplo n.º 5
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;
}