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