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#ifndef __CLOCK_RECOVERY_H__
186c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#define __CLOCK_RECOVERY_H__
196c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
206c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <stdint.h>
216c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <common_time/ICommonClock.h>
226c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <utils/LinearTransform.h>
236c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include <utils/threads.h>
246c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
256c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG
266c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#include "diag_thread.h"
276c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif
286c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
29c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman#include "utils.h"
30c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman
316c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chennamespace android {
326c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
336c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenclass CommonClock;
346c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenclass LocalClock;
356c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
366c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chenclass ClockRecoveryLoop {
376c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen  public:
386c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen     ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock);
396c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    ~ClockRecoveryLoop();
406c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
416c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    void reset(bool position, bool frequency);
426c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    bool pushDisciplineEvent(int64_t local_time,
436c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen                             int64_t nominal_common_time,
446c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen                             int64_t data_point_rtt);
456c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    int32_t getLastErrorEstimate();
466c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
47c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // Applies the next step in any ongoing slew change operation.  Returns a
48c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // timeout suitable for use with poll/select indicating the number of mSec
49c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // until the next change should be applied.
50c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    int applyRateLimitedSlew();
51c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman
526c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen  private:
5311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
5411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Tuned using the "Good Gain" method.
5511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // See:
5611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf
5711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
5811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Controller period (1Hz for now).
5911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float dT;
6011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
6111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Controller gain, positive and unitless. Larger values converge faster,
6211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // but can cause instability.
6311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float Kc;
6411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
6511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Integral reset time. Smaller values cause loop to track faster, but can
6611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // also cause instability.
6711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float Ti;
6811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
6911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Controller output filter time constant. Range (0-1). Smaller values make
7011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // output smoother, but slow convergence.
7111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float Tf;
7211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
7311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Low-pass filter for bias tracker.
7411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float bias_Fc; // HZ
7511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float bias_RC; // Computed in constructor.
7611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float bias_Alpha; // Computed inconstructor.
7711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
7811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // The maximum allowed error (as indicated by a  pushDisciplineEvent) before
7911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // we panic.
8011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const int64_t panic_thresh_;
8111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
8211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // The maximum allowed error rtt time for packets to be used for control
8311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // feedback, unless the packet is the best in recent memory.
8411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const int64_t control_thresh_;
856c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
866c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    typedef struct {
876c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen        int64_t local_time;
886c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen        int64_t observed_common_time;
896c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen        int64_t nominal_common_time;
906c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen        int64_t rtt;
916c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen        bool point_used;
926c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    } DisciplineDataPoint;
936c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
946c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count);
956c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
966c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    void reset_l(bool position, bool frequency);
97c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    void setTargetCorrection_l(int32_t tgt);
98c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    bool applySlew_l();
996c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1006c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // The local clock HW abstraction we use as the basis for common time.
1016c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    LocalClock* local_clock_;
1026c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    bool local_clock_can_slew_;
1036c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1046c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // The common clock we end up controlling along with the lock used to
1056c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // serialize operations.
1066c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    CommonClock* common_clock_;
1076c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    Mutex lock_;
1086c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1096c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // parameters maintained while running and reset during a reset
1106c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // of the frequency correction.
11179489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman    bool    last_error_est_valid_;
11279489c4c65d3c8e628991995b4a18f2a81802ee6John Grossman    int32_t last_error_est_usec_;
11311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    float last_delta_f_;
1146c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    int32_t integrated_error_;
115c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    int32_t tgt_correction_;
116c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    int32_t cur_correction_;
117c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    LinearTransform time_to_cur_slew_;
118c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    int64_t slew_change_end_time_;
119c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    Timeout next_slew_change_timeout_;
1206c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
12111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Contoller Output.
12211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    float CO;
12311bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
12411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Bias tracking for trajectory estimation.
12511bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    float CObias;
12611bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    float lastCObias;
12711bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
12811bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // Controller output bounds. The controller will not try to
12911bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    // slew faster that +/-100ppm offset from center per interation.
13011bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float COmin;
13111bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const float COmax;
13211bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk
1336c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    // State kept for filtering the discipline data.
13411bc45fcba96cf7ccc5f67b3c47088c2c89c8e7aKent Ryhorchuk    static const uint32_t kFilterSize = 16;
1356c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    DisciplineDataPoint filter_data_[kFilterSize];
1366c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    uint32_t filter_wr_;
1376c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    bool filter_full_;
1386c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1396c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    static const uint32_t kStartupFilterSize = 4;
1406c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    DisciplineDataPoint startup_filter_data_[kStartupFilterSize];
1416c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    uint32_t startup_filter_wr_;
1426c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
143c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // Minimum number of milliseconds over which we allow a full range change
144c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // (from rail to rail) of the VCXO control signal.  This is the rate
145c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // limiting factor which keeps us from changing the clock rate so fast that
146c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // we get in trouble with certain HDMI sinks.
147c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    static const uint32_t kMinFullRangeSlewChange_mSec;
148c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman
149c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    // How much time (in msec) to wait
150c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman    static const int kSlewChangeStepPeriod_mSec;
151c7f57c6f9289d0e3aaecc0bca4ae7b6eed1c93d7John Grossman
1526c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#ifdef TIME_SERVICE_DEBUG
1536c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen    sp<DiagThread> diag_thread_;
1546c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif
1556c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen};
1566c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1576c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen}  // namespace android
1586c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen
1596c929510474caa14dc9d56826b2c65552861d6b3Mike J. Chen#endif  // __CLOCK_RECOVERY_H__
160