summaryrefslogtreecommitdiffstats
path: root/libs/common_time/clock_recovery.h
blob: 278a75ef2b0518c78d0ba2bbee2129640bba2db8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __CLOCK_RECOVERY_H__
#define __CLOCK_RECOVERY_H__

#include <stdint.h>
#include <common_time/ICommonClock.h>
#include <utils/LinearTransform.h>
#include <utils/threads.h>

#ifdef TIME_SERVICE_DEBUG
#include "diag_thread.h"
#endif

#include "utils.h"

namespace android {

class CommonClock;
class LocalClock;

class ClockRecoveryLoop {
  public:
     ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock);
    ~ClockRecoveryLoop();

    void reset(bool position, bool frequency);
    bool pushDisciplineEvent(int64_t local_time,
                             int64_t nominal_common_time,
                             int64_t data_point_rtt);
    int32_t getLastErrorEstimate();

    // Applies the next step in any ongoing slew change operation.  Returns a
    // timeout suitable for use with poll/select indicating the number of mSec
    // until the next change should be applied.
    int applyRateLimitedSlew();

  private:

    // Tuned using the "Good Gain" method.
    // See:
    // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf

    // Controller period (1Hz for now).
    static const float dT;

    // Controller gain, positive and unitless. Larger values converge faster,
    // but can cause instability.
    static const float Kc;

    // Integral reset time. Smaller values cause loop to track faster, but can
    // also cause instability.
    static const float Ti;

    // Controller output filter time constant. Range (0-1). Smaller values make
    // output smoother, but slow convergence.
    static const float Tf;

    // Low-pass filter for bias tracker.
    static const float bias_Fc; // HZ
    static const float bias_RC; // Computed in constructor.
    static const float bias_Alpha; // Computed inconstructor.

    // The maximum allowed error (as indicated by a  pushDisciplineEvent) before
    // we panic.
    static const int64_t panic_thresh_;

    // The maximum allowed error rtt time for packets to be used for control
    // feedback, unless the packet is the best in recent memory.
    static const int64_t control_thresh_;

    typedef struct {
        int64_t local_time;
        int64_t observed_common_time;
        int64_t nominal_common_time;
        int64_t rtt;
        bool point_used;
    } DisciplineDataPoint;

    static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count);

    void reset_l(bool position, bool frequency);
    void setTargetCorrection_l(int32_t tgt);
    bool applySlew_l();

    // The local clock HW abstraction we use as the basis for common time.
    LocalClock* local_clock_;
    bool local_clock_can_slew_;

    // The common clock we end up controlling along with the lock used to
    // serialize operations.
    CommonClock* common_clock_;
    Mutex lock_;

    // parameters maintained while running and reset during a reset
    // of the frequency correction.
    bool    last_error_est_valid_;
    int32_t last_error_est_usec_;
    float last_delta_f_;
    int32_t tgt_correction_;
    int32_t cur_correction_;
    LinearTransform time_to_cur_slew_;
    int64_t slew_change_end_time_;
    Timeout next_slew_change_timeout_;

    // Contoller Output.
    float CO;

    // Bias tracking for trajectory estimation.
    float CObias;
    float lastCObias;

    // Controller output bounds. The controller will not try to
    // slew faster that +/-100ppm offset from center per interation.
    static const float COmin;
    static const float COmax;

    // State kept for filtering the discipline data.
    static const uint32_t kFilterSize = 16;
    DisciplineDataPoint filter_data_[kFilterSize];
    uint32_t filter_wr_;
    bool filter_full_;

    static const uint32_t kStartupFilterSize = 4;
    DisciplineDataPoint startup_filter_data_[kStartupFilterSize];
    uint32_t startup_filter_wr_;

    // Minimum number of milliseconds over which we allow a full range change
    // (from rail to rail) of the VCXO control signal.  This is the rate
    // limiting factor which keeps us from changing the clock rate so fast that
    // we get in trouble with certain HDMI sinks.
    static const uint32_t kMinFullRangeSlewChange_mSec;

    // How much time (in msec) to wait 
    static const int kSlewChangeStepPeriod_mSec;

#ifdef TIME_SERVICE_DEBUG
    sp<DiagThread> diag_thread_;
#endif
};

}  // namespace android

#endif  // __CLOCK_RECOVERY_H__