16c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen/* 26c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * Copyright (C) 2011 The Android Open Source Project 36c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * 46c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * Licensed under the Apache License, Version 2.0 (the "License"); 56c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * you may not use this file except in compliance with the License. 66c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * You may obtain a copy of the License at 76c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * 86c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * http://www.apache.org/licenses/LICENSE-2.0 96c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * 106c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * Unless required by applicable law or agreed to in writing, software 116c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * distributed under the License is distributed on an "AS IS" BASIS, 126c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * See the License for the specific language governing permissions and 146c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * limitations under the License. 156c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen */ 166c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 176c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen/* 186c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * A service that exchanges time synchronization information between 196c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen * a master that defines a timeline and clients that follow the timeline. 206c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen */ 216c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 226c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#define __STDC_LIMIT_MACROS 236c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#define LOG_TAG "common_time" 246c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <utils/Log.h> 254c57eda9f4c87bb22eb0acdd2dab4d1757d4280bAndreas Gampe#include <inttypes.h> 266c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <stdint.h> 276c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 286c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <common_time/local_clock.h> 296c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <assert.h> 306c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 316c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include "clock_recovery.h" 326c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include "common_clock.h" 336c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG 346c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include "diag_thread.h" 356c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif 366c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 3711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk// Define log macro so we can make LOGV into LOGE when we are exclusively 3811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk// debugging this code. 3911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#ifdef TIME_SERVICE_DEBUG 4011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#define LOG_TS ALOGE 4111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#else 4211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#define LOG_TS ALOGV 4311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#endif 4411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 456c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chennamespace android { 466c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 476c929510474caa14dc9d56826b2c65552861d6b3Mike J. ChenClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock, 486c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen CommonClock* common_clock) { 496c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen assert(NULL != local_clock); 506c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen assert(NULL != common_clock); 516c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 526c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen local_clock_ = local_clock; 536c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen common_clock_ = common_clock; 546c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 556c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen local_clock_can_slew_ = local_clock_->initCheck() && 566c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen (local_clock_->setLocalSlew(0) == OK); 57c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman tgt_correction_ = 0; 58c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = 0; 59c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 60c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // Precompute the max rate at which we are allowed to change the VCXO 61c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // control. 62c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman uint64_t N = 0x10000ull * 1000ull; 63c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman uint64_t D = local_clock_->getLocalFreq() * kMinFullRangeSlewChange_mSec; 64c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman LinearTransform::reduce(&N, &D); 65c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman while ((N > INT32_MAX) || (D > UINT32_MAX)) { 66c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman N >>= 1; 67c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman D >>= 1; 68c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman LinearTransform::reduce(&N, &D); 69c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } 70c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.a_to_b_numer = static_cast<int32_t>(N); 71c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.a_to_b_denom = static_cast<uint32_t>(D); 726c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 736c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen reset(true, true); 746c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 756c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG 766c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen diag_thread_ = new DiagThread(common_clock_, local_clock_); 776c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (diag_thread_ != NULL) { 786c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen status_t res = diag_thread_->startWorkThread(); 796c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (res != OK) 806c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen ALOGW("Failed to start A@H clock recovery diagnostic thread."); 816c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } else 826c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen ALOGW("Failed to allocate diagnostic thread."); 836c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif 846c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 856c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 866c929510474caa14dc9d56826b2c65552861d6b3Mike J. ChenClockRecoveryLoop::~ClockRecoveryLoop() { 876c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG 886c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen diag_thread_->stopWorkThread(); 896c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif 906c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 916c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 9211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk// Constants. 9311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::dT = 1.0; 9411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::Kc = 1.0f; 9511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::Ti = 15.0f; 9611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::Tf = 0.05; 9711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::bias_Fc = 0.01; 9811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc)); 9911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT)); 10011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst int64_t ClockRecoveryLoop::panic_thresh_ = 50000; 10111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst int64_t ClockRecoveryLoop::control_thresh_ = 10000; 10211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::COmin = -100.0f; 10311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchukconst float ClockRecoveryLoop::COmax = 100.0f; 104c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanconst uint32_t ClockRecoveryLoop::kMinFullRangeSlewChange_mSec = 300; 105c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanconst int ClockRecoveryLoop::kSlewChangeStepPeriod_mSec = 10; 106c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 10711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 1086c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenvoid ClockRecoveryLoop::reset(bool position, bool frequency) { 1096c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen Mutex::Autolock lock(&lock_); 1106c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen reset_l(position, frequency); 1116c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 1126c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1136c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenuint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data, 1146c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen uint32_t count) { 1156c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen uint32_t min_rtt = 0; 1166c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen for (uint32_t i = 1; i < count; ++i) 1176c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (data[min_rtt].rtt > data[i].rtt) 1186c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen min_rtt = i; 1196c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1206c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen return min_rtt; 1216c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 1226c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1236c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenbool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time, 1246c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen int64_t nominal_common_time, 1256c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen int64_t rtt) { 1266c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen Mutex::Autolock lock(&lock_); 1276c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 12811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk int64_t local_common_time = 0; 12911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk common_clock_->localToCommon(local_time, &local_common_time); 13011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk int64_t raw_delta = nominal_common_time - local_common_time; 13111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 13211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#ifdef TIME_SERVICE_DEBUG 13311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n", 13411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk local_common_time, nominal_common_time, 13511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk raw_delta, rtt); 13611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk#endif 13711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 1386c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // If we have not defined a basis for common time, then we need to use these 1396c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // initial points to do so. In order to avoid significant initial error 1406c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // from a particularly bad startup data point, we collect the first N data 1416c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // points and choose the best of them before moving on. 1426c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (!common_clock_->isValid()) { 1436c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (startup_filter_wr_ < kStartupFilterSize) { 1446c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen DisciplineDataPoint& d = startup_filter_data_[startup_filter_wr_]; 1456c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen d.local_time = local_time; 1466c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen d.nominal_common_time = nominal_common_time; 1476c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen d.rtt = rtt; 1486c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen startup_filter_wr_++; 1496c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 1506c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1516c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (startup_filter_wr_ == kStartupFilterSize) { 1526c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen uint32_t min_rtt = findMinRTTNdx(startup_filter_data_, 1536c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen kStartupFilterSize); 1546c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1556c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen common_clock_->setBasis( 1566c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen startup_filter_data_[min_rtt].local_time, 1576c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen startup_filter_data_[min_rtt].nominal_common_time); 1586c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 1596c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1606c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen return true; 1616c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 1626c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1636c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen int64_t observed_common; 1646c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen int64_t delta; 16511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk float delta_f, dCO; 166c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman int32_t tgt_correction; 1676c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1686c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (OK != common_clock_->localToCommon(local_time, &observed_common)) { 1696c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // Since we just checked to make certain that this conversion was valid, 1706c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // and no one else in the system should be messing with it, if this 1716c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // conversion is suddenly invalid, it is a good reason to panic. 1726c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen ALOGE("Failed to convert local time to common time in %s:%d", 1736c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen __PRETTY_FUNCTION__, __LINE__); 1746c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen return false; 1756c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 1766c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1776c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // Implement a filter which should match NTP filtering behavior when a 1786c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // client is associated with only one peer of lower stratum. Basically, 1796c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // always use the best of the N last data points, where best is defined as 1806c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // lowest round trip time. NTP uses an N of 8; we use a value of 6. 1816c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // 1826c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // TODO(johngro) : experiment with other filter strategies. The goal here 1836c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // is to mitigate the effects of high RTT data points which typically have 1846c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // large asymmetries in the TX/RX legs. Downside of the existing NTP 1856c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // approach (particularly because of the PID controller we are using to 1866c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // produce the control signal from the filtered data) are that the rate at 1876c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // which discipline events are actually acted upon becomes irregular and can 1886c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // become drawn out (the time between actionable event can go way up). If 1896c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // the system receives a strong high quality data point, the proportional 1906c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // component of the controller can produce a strong correction which is left 1916c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // in place for too long causing overshoot. In addition, the integral 1926c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // component of the system currently is an approximation based on the 1936c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // assumption of a more or less homogeneous sampling of the error. Its 1946c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // unclear what the effect of undermining this assumption would be right 1956c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // now. 1966c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 1976c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // Two ideas which come to mind immediately would be to... 1986c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // 1) Keep a history of more data points (32 or so) and ignore data points 1996c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // whose RTT is more than a certain number of standard deviations outside 2006c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // of the norm. 2016c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // 2) Eliminate the PID controller portion of this system entirely. 2026c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // Instead, move to a system which uses a very wide filter (128 data 2036c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // points or more) with a sum-of-least-squares line fitting approach to 2046c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // tracking the long term drift. This would take the place of the I 2056c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // component in the current PID controller. Also use a much more narrow 2066c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // outlier-rejector filter (as described in #1) to drive a short term 2076c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // correction factor similar to the P component of the PID controller. 2086c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen assert(filter_wr_ < kFilterSize); 2096c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_data_[filter_wr_].local_time = local_time; 2106c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_data_[filter_wr_].observed_common_time = observed_common; 2116c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_data_[filter_wr_].nominal_common_time = nominal_common_time; 2126c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_data_[filter_wr_].rtt = rtt; 2136c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_data_[filter_wr_].point_used = false; 21411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk uint32_t current_point = filter_wr_; 2156c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_wr_ = (filter_wr_ + 1) % kFilterSize; 2166c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (!filter_wr_) 2176c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_full_ = true; 2186c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2196c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_; 2206c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end); 22111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // We only use packets with low RTTs for control. If the packet RTT 22211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // is less than the panic threshold, we can probably eat the jitter with the 22311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // control loop. Otherwise, take the packet only if it better than all 22411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // of the packets we have in the history. That way we try to track 22511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // something, even if it is noisy. 22611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk if (current_point == min_rtt || rtt < control_thresh_) { 22711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk delta_f = delta = nominal_common_time - observed_common; 22811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 22979489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman last_error_est_valid_ = true; 23079489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman last_error_est_usec_ = delta; 23179489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman 23211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Compute the error then clamp to the panic threshold. If we ever 23311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // exceed this amt of error, its time to panic and reset the system. 23411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Given that the error in the measurement of the error could be as 23511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // high as the RTT of the data point, we don't actually panic until 23611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // the implied error (delta) is greater than the absolute panic 23711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // threashold plus the RTT. IOW - we don't panic until we are 23811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // absoluely sure that our best case sync is worse than the absolute 23911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // panic threshold. 24011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk int64_t effective_panic_thresh = panic_thresh_ + rtt; 24111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk if ((delta > effective_panic_thresh) || 24211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk (delta < -effective_panic_thresh)) { 24311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // PANIC!!! 24411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk reset_l(false, true); 24511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk return false; 24611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk } 2476c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 24811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk } else { 24911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // We do not have a good packet to look at, but we also do not want to 25011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // free-run the clock at some crazy slew rate. So we guess the 25111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // trajectory of the clock based on the last controller output and the 25211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // estimated bias of our clock against the master. 25311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // The net effect of this is that CO == CObias after some extended 25411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // period of no feedback. 25511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk delta_f = last_delta_f_ - dT*(CO - CObias); 25611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk delta = delta_f; 25711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk } 25811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 25911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Velocity form PI control equation. 26011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_; 26111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk CO += dCO * Tf; // Filter CO by applying gain <1 here. 26211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 26311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Save error terms for later. 26411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk last_delta_f_ = delta_f; 26511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 26611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Clamp CO to +/- 100ppm. 26711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk if (CO < COmin) 26811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk CO = COmin; 26911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk else if (CO > COmax) 27011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk CO = COmax; 27111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 27211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Update the controller bias. 27311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias; 27411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk lastCObias = CObias; 27511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk 27611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we 27711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // don't get fp weirdness. 278c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman tgt_correction = CO * 327.66; 2796c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2806c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // If there was a change in the amt of correction to use, update the 2816c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // system. 282c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman setTargetCorrection_l(tgt_correction); 2836c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2844c57eda9f4c87bb22eb0acdd2dab4d1757d4280bAndreas Gampe LOG_TS("clock_loop %" PRId64 " %f %f %f %d\n", raw_delta, delta_f, CO, CObias, tgt_correction); 2856c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2866c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG 2876c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen diag_thread_->pushDisciplineEvent( 2886c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen local_time, 2896c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen observed_common, 2906c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen nominal_common_time, 291c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman tgt_correction, 29211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk rtt); 2936c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif 2946c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2956c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen return true; 2966c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 2976c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 2986c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenint32_t ClockRecoveryLoop::getLastErrorEstimate() { 2996c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen Mutex::Autolock lock(&lock_); 3006c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 30179489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman if (last_error_est_valid_) 30279489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman return last_error_est_usec_; 3036c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen else 3046c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen return ICommonClock::kErrorEstimateUnknown; 3056c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 3066c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 3076c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenvoid ClockRecoveryLoop::reset_l(bool position, bool frequency) { 3086c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen assert(NULL != common_clock_); 3096c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 3106c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (position) { 3116c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen common_clock_->resetBasis(); 3126c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen startup_filter_wr_ = 0; 3136c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 3146c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 3156c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (frequency) { 31679489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman last_error_est_valid_ = false; 31779489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman last_error_est_usec_ = 0; 31811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk last_delta_f_ = 0.0; 31911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk CO = 0.0f; 32011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk lastCObias = CObias = 0.0f; 321c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman setTargetCorrection_l(0); 322c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman applySlew_l(); 3236c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 3246c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 3256c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_wr_ = 0; 3266c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen filter_full_ = false; 3276c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 3286c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 329c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanvoid ClockRecoveryLoop::setTargetCorrection_l(int32_t tgt) { 330c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // When we make a change to the slew rate, we need to be careful to not 331c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // change it too quickly as it can anger some HDMI sinks out there, notably 332c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // some Sony panels from the 2010-2011 timeframe. From experimenting with 333c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // some of these sinks, it seems like swinging from one end of the range to 334c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // another in less that 190mSec or so can start to cause trouble. Adding in 335c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // a hefty margin, we limit the system to a full range sweep in no less than 336c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // 300mSec. 337c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (tgt_correction_ != tgt) { 338c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman int64_t now = local_clock_->getLocalTime(); 339c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 340c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman tgt_correction_ = tgt; 341c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 342c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // Set up the transformation to figure out what the slew should be at 343c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // any given point in time in the future. 344c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.a_zero = now; 345c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.b_zero = cur_correction_; 346c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 347c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // Make sure the sign of the slope is headed in the proper direction. 348c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman bool needs_increase = (cur_correction_ < tgt_correction_); 349c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman bool is_increasing = (time_to_cur_slew_.a_to_b_numer > 0); 350c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (( needs_increase && !is_increasing) || 351c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman (!needs_increase && is_increasing)) { 352c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.a_to_b_numer = -time_to_cur_slew_.a_to_b_numer; 353c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } 354c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 355c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // Finally, figure out when the change will be finished and start the 356c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // slew operation. 357c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.doReverseTransform(tgt_correction_, 358c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman &slew_change_end_time_); 359c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 360c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman applySlew_l(); 361c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } 362c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman} 363c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 364c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanbool ClockRecoveryLoop::applySlew_l() { 365c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman bool ret = true; 366c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 367c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // If cur == tgt, there is no ongoing sleq rate change and we are already 368c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // finished. 369c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (cur_correction_ == tgt_correction_) 370c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman goto bailout; 371c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 3726c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen if (local_clock_can_slew_) { 373c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman int64_t now = local_clock_->getLocalTime(); 374c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman int64_t tmp; 375c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 376c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (now >= slew_change_end_time_) { 377c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = tgt_correction_; 378c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman next_slew_change_timeout_.setTimeout(-1); 379c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } else { 380c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman time_to_cur_slew_.doForwardTransform(now, &tmp); 381c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 382c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (tmp > INT16_MAX) 383c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = INT16_MAX; 384c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman else if (tmp < INT16_MIN) 385c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = INT16_MIN; 386c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman else 387c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = static_cast<int16_t>(tmp); 388c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 389c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman next_slew_change_timeout_.setTimeout(kSlewChangeStepPeriod_mSec); 390c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman ret = false; 391c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } 392c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 393c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman local_clock_->setLocalSlew(cur_correction_); 3946c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } else { 395c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // Since we are not actually changing the rate of a HW clock, we don't 396c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // need to worry to much about changing the slew rate so fast that we 397c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman // anger any downstream HDMI devices. 398c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman cur_correction_ = tgt_correction_; 399c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman next_slew_change_timeout_.setTimeout(-1); 400c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 4016c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen // The SW clock recovery implemented by the common clock class expects 40211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk // values expressed in PPM. CO is in ppm. 40311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk common_clock_->setSlew(local_clock_->getLocalTime(), CO); 4046c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen } 405c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 406c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanbailout: 407c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman return ret; 408c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman} 409c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 410c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossmanint ClockRecoveryLoop::applyRateLimitedSlew() { 411c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman Mutex::Autolock lock(&lock_); 412c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 413c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman int ret = next_slew_change_timeout_.msecTillTimeout(); 414c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (!ret) { 415c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman if (applySlew_l()) 416c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman next_slew_change_timeout_.setTimeout(-1); 417c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman ret = next_slew_change_timeout_.msecTillTimeout(); 418c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman } 419c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman 420c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman return ret; 4216c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} 4226c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen 4236c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen} // namespace android 424