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; }
static int apply_step_offset(double offset) { struct timespec old_time, new_time; struct timeval new_time_tv; double err; LCL_ReadRawTime(&old_time); UTI_AddDoubleToTimespec(&old_time, -offset, &new_time); UTI_TimespecToTimeval(&new_time, &new_time_tv); if (PRV_SetTime(&new_time_tv, NULL) < 0) { DEBUG_LOG("settimeofday() failed"); return 0; } LCL_ReadRawTime(&old_time); err = UTI_DiffTimespecsToDouble(&old_time, &new_time); lcl_InvokeDispersionNotifyHandlers(fabs(err)); return 1; }
static void update_slew(void) { struct timespec 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 */ duration = UTI_DiffTimespecsToDouble(&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_AddDoubleToTimespec(&now, duration, &end_of_slew); slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL); slew_start = now; DEBUG_LOG("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); }