1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package android.location;
18
19import android.annotation.TestApi;
20import android.os.Parcel;
21import android.os.Parcelable;
22
23/**
24 * A class containing a GPS clock timestamp.
25 *
26 * <p>It represents a measurement of the GPS receiver's clock.
27 */
28public final class GnssClock implements Parcelable {
29    // The following enumerations must be in sync with the values declared in gps.h
30
31    private static final int HAS_NO_FLAGS = 0;
32    private static final int HAS_LEAP_SECOND = (1<<0);
33    private static final int HAS_TIME_UNCERTAINTY = (1<<1);
34    private static final int HAS_FULL_BIAS = (1<<2);
35    private static final int HAS_BIAS = (1<<3);
36    private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
37    private static final int HAS_DRIFT = (1<<5);
38    private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
39
40    // End enumerations in sync with gps.h
41
42    private int mFlags;
43    private int mLeapSecond;
44    private long mTimeNanos;
45    private double mTimeUncertaintyNanos;
46    private long mFullBiasNanos;
47    private double mBiasNanos;
48    private double mBiasUncertaintyNanos;
49    private double mDriftNanosPerSecond;
50    private double mDriftUncertaintyNanosPerSecond;
51    private int mHardwareClockDiscontinuityCount;
52
53    /**
54     * @hide
55     */
56    @TestApi
57    public GnssClock() {
58        initialize();
59    }
60
61    /**
62     * Sets all contents to the values stored in the provided object.
63     * @hide
64     */
65    @TestApi
66    public void set(GnssClock clock) {
67        mFlags = clock.mFlags;
68        mLeapSecond = clock.mLeapSecond;
69        mTimeNanos = clock.mTimeNanos;
70        mTimeUncertaintyNanos = clock.mTimeUncertaintyNanos;
71        mFullBiasNanos = clock.mFullBiasNanos;
72        mBiasNanos = clock.mBiasNanos;
73        mBiasUncertaintyNanos = clock.mBiasUncertaintyNanos;
74        mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
75        mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
76        mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
77    }
78
79    /**
80     * Resets all the contents to its original state.
81     * @hide
82     */
83    @TestApi
84    public void reset() {
85        initialize();
86    }
87
88    /**
89     * Returns {@code true} if {@link #getLeapSecond()} is available, {@code false} otherwise.
90     */
91    public boolean hasLeapSecond() {
92        return isFlagSet(HAS_LEAP_SECOND);
93    }
94
95    /**
96     * Gets the leap second associated with the clock's time.
97     *
98     * <p>The sign of the value is defined by the following equation:
99     * <pre>
100     *     UtcTimeNanos = TimeNanos - (FullBiasNanos + BiasNanos) - LeapSecond * 1,000,000,000</pre>
101     *
102     * <p>The value is only available if {@link #hasLeapSecond()} is {@code true}.
103     */
104    public int getLeapSecond() {
105        return mLeapSecond;
106    }
107
108    /**
109     * Sets the leap second associated with the clock's time.
110     * @hide
111     */
112    @TestApi
113    public void setLeapSecond(int leapSecond) {
114        setFlag(HAS_LEAP_SECOND);
115        mLeapSecond = leapSecond;
116    }
117
118    /**
119     * Resets the leap second associated with the clock's time.
120     * @hide
121     */
122    @TestApi
123    public void resetLeapSecond() {
124        resetFlag(HAS_LEAP_SECOND);
125        mLeapSecond = Integer.MIN_VALUE;
126    }
127
128    /**
129     * Gets the GNSS receiver internal hardware clock value in nanoseconds.
130     *
131     * <p>This value is expected to be monotonically increasing while the hardware clock remains
132     * powered on. For the case of a hardware clock that is not continuously on, see the
133     * {@link #getHardwareClockDiscontinuityCount} field. The GPS time can be derived by subtracting
134     * the sum of {@link #getFullBiasNanos()} and {@link #getBiasNanos()} (when they are available)
135     * from this value. Sub-nanosecond accuracy can be provided by means of {@link #getBiasNanos()}.
136     *
137     * <p>The error estimate for this value (if applicable) is {@link #getTimeUncertaintyNanos()}.
138     */
139    public long getTimeNanos() {
140        return mTimeNanos;
141    }
142
143    /**
144     * Sets the GNSS receiver internal clock in nanoseconds.
145     * @hide
146     */
147    @TestApi
148    public void setTimeNanos(long timeNanos) {
149        mTimeNanos = timeNanos;
150    }
151
152    /**
153     * Returns {@code true} if {@link #getTimeUncertaintyNanos()} is available, {@code false}
154     * otherwise.
155     */
156    public boolean hasTimeUncertaintyNanos() {
157        return isFlagSet(HAS_TIME_UNCERTAINTY);
158    }
159
160    /**
161     * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
162     *
163     * <p>The uncertainty is represented as an absolute (single sided) value.
164     *
165     * <p>The value is only available if {@link #hasTimeUncertaintyNanos()} is {@code true}.
166     *
167     * <p>This value is often effectively zero (it is the reference clock by which all other times
168     * and time uncertainties are measured), and thus this field may often be 0, or not provided.
169     */
170    public double getTimeUncertaintyNanos() {
171        return mTimeUncertaintyNanos;
172    }
173
174    /**
175     * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
176     * @hide
177     */
178    @TestApi
179    public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
180        setFlag(HAS_TIME_UNCERTAINTY);
181        mTimeUncertaintyNanos = timeUncertaintyNanos;
182    }
183
184    /**
185     * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
186     * @hide
187     */
188    @TestApi
189    public void resetTimeUncertaintyNanos() {
190        resetFlag(HAS_TIME_UNCERTAINTY);
191        mTimeUncertaintyNanos = Double.NaN;
192    }
193
194    /**
195     * Returns {@code true} if {@link #getFullBiasNanos()} is available, {@code false} otherwise.
196     */
197    public boolean hasFullBiasNanos() {
198        return isFlagSet(HAS_FULL_BIAS);
199    }
200
201    /**
202     * Gets the difference between hardware clock ({@link #getTimeNanos()}) inside GPS receiver and
203     * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
204     *
205     * <p>This value is available if the receiver has estimated GPS time. If the computed time is
206     * for a non-GPS constellation, the time offset of that constellation to GPS has to be applied
207     * to fill this value. The value is only available if {@link #hasFullBiasNanos()} is
208     * {@code true}.
209     *
210     * <p>The error estimate for the sum of this field and {@link #getBiasNanos} is
211     * {@link #getBiasUncertaintyNanos()}.
212     *
213     * <p>The sign of the value is defined by the following equation:
214     *
215     * <pre>
216     *     local estimate of GPS time = TimeNanos - (FullBiasNanos + BiasNanos)</pre>
217     */
218    public long getFullBiasNanos() {
219        return mFullBiasNanos;
220    }
221
222    /**
223     * Sets the full bias in nanoseconds.
224     * @hide
225     */
226    @TestApi
227    public void setFullBiasNanos(long value) {
228        setFlag(HAS_FULL_BIAS);
229        mFullBiasNanos = value;
230    }
231
232    /**
233     * Resets the full bias in nanoseconds.
234     * @hide
235     */
236    @TestApi
237    public void resetFullBiasNanos() {
238        resetFlag(HAS_FULL_BIAS);
239        mFullBiasNanos = Long.MIN_VALUE;
240    }
241
242    /**
243     * Returns {@code true} if {@link #getBiasNanos()} is available, {@code false} otherwise.
244     */
245    public boolean hasBiasNanos() {
246        return isFlagSet(HAS_BIAS);
247    }
248
249    /**
250     * Gets the clock's sub-nanosecond bias.
251     *
252     * <p>See the description of how this field is part of converting from hardware clock time, to
253     * GPS time, in {@link #getFullBiasNanos()}.
254     *
255     * <p>The error estimate for the sum of this field and {@link #getFullBiasNanos} is
256     * {@link #getBiasUncertaintyNanos()}.
257     *
258     * <p>The value is only available if {@link #hasBiasNanos()} is {@code true}.
259     */
260    public double getBiasNanos() {
261        return mBiasNanos;
262    }
263
264    /**
265     * Sets the sub-nanosecond bias.
266     * @hide
267     */
268    @TestApi
269    public void setBiasNanos(double biasNanos) {
270        setFlag(HAS_BIAS);
271        mBiasNanos = biasNanos;
272    }
273
274    /**
275     * Resets the clock's Bias in nanoseconds.
276     * @hide
277     */
278    @TestApi
279    public void resetBiasNanos() {
280        resetFlag(HAS_BIAS);
281        mBiasNanos = Double.NaN;
282    }
283
284    /**
285     * Returns {@code true} if {@link #getBiasUncertaintyNanos()} is available, {@code false}
286     * otherwise.
287     */
288    public boolean hasBiasUncertaintyNanos() {
289        return isFlagSet(HAS_BIAS_UNCERTAINTY);
290    }
291
292    /**
293     * Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
294     *
295     * <p>See the description of how this field provides the error estimate in the conversion from
296     * hardware clock time, to GPS time, in {@link #getFullBiasNanos()}.
297     *
298     * <p>The value is only available if {@link #hasBiasUncertaintyNanos()} is {@code true}.
299     */
300    public double getBiasUncertaintyNanos() {
301        return mBiasUncertaintyNanos;
302    }
303
304    /**
305     * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
306     * @hide
307     */
308    @TestApi
309    public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
310        setFlag(HAS_BIAS_UNCERTAINTY);
311        mBiasUncertaintyNanos = biasUncertaintyNanos;
312    }
313
314    /**
315     * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
316     * @hide
317     */
318    @TestApi
319    public void resetBiasUncertaintyNanos() {
320        resetFlag(HAS_BIAS_UNCERTAINTY);
321        mBiasUncertaintyNanos = Double.NaN;
322    }
323
324    /**
325     * Returns {@code true} if {@link #getDriftNanosPerSecond()} is available, {@code false}
326     * otherwise.
327     */
328    public boolean hasDriftNanosPerSecond() {
329        return isFlagSet(HAS_DRIFT);
330    }
331
332    /**
333     * Gets the clock's Drift in nanoseconds per second.
334     *
335     * <p>A positive value indicates that the frequency is higher than the nominal (e.g. GPS master
336     * clock) frequency. The error estimate for this reported drift is
337     * {@link #getDriftUncertaintyNanosPerSecond()}.
338     *
339     * <p>The value is only available if {@link #hasDriftNanosPerSecond()} is {@code true}.
340     */
341    public double getDriftNanosPerSecond() {
342        return mDriftNanosPerSecond;
343    }
344
345    /**
346     * Sets the clock's Drift in nanoseconds per second.
347     * @hide
348     */
349    @TestApi
350    public void setDriftNanosPerSecond(double driftNanosPerSecond) {
351        setFlag(HAS_DRIFT);
352        mDriftNanosPerSecond = driftNanosPerSecond;
353    }
354
355    /**
356     * Resets the clock's Drift in nanoseconds per second.
357     * @hide
358     */
359    @TestApi
360    public void resetDriftNanosPerSecond() {
361        resetFlag(HAS_DRIFT);
362        mDriftNanosPerSecond = Double.NaN;
363    }
364
365    /**
366     * Returns {@code true} if {@link #getDriftUncertaintyNanosPerSecond()} is available,
367     * {@code false} otherwise.
368     */
369    public boolean hasDriftUncertaintyNanosPerSecond() {
370        return isFlagSet(HAS_DRIFT_UNCERTAINTY);
371    }
372
373    /**
374     * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
375     *
376     * <p>The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is
377     * {@code true}.
378     */
379    public double getDriftUncertaintyNanosPerSecond() {
380        return mDriftUncertaintyNanosPerSecond;
381    }
382
383    /**
384     * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
385     * @hide
386     */
387    @TestApi
388    public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
389        setFlag(HAS_DRIFT_UNCERTAINTY);
390        mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
391    }
392
393    /**
394     * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
395     * @hide
396     */
397    @TestApi
398    public void resetDriftUncertaintyNanosPerSecond() {
399        resetFlag(HAS_DRIFT_UNCERTAINTY);
400        mDriftUncertaintyNanosPerSecond = Double.NaN;
401    }
402
403    /**
404     * Gets count of hardware clock discontinuities.
405     *
406     * <p>When this value stays the same, vs. a value in a previously reported {@link GnssClock}, it
407     * can be safely assumed that the {@code TimeNanos} value has been derived from a clock that has
408     * been running continuously - e.g. a single continuously powered crystal oscillator, and thus
409     * the {@code (FullBiasNanos + BiasNanos)} offset can be modelled with traditional clock bias
410     * &amp; drift models.
411     *
412     * <p>Each time this value changes, vs. the value in a previously reported {@link GnssClock},
413     * that suggests the hardware clock may have experienced a discontinuity (e.g. a power cycle or
414     * other anomaly), so that any assumptions about modelling a smoothly changing
415     * {@code (FullBiasNanos + BiasNanos)} offset, and a smoothly growing {@code (TimeNanos)}
416     * between this and the previously reported {@code GnssClock}, should be reset.
417     */
418    public int getHardwareClockDiscontinuityCount() {
419        return mHardwareClockDiscontinuityCount;
420    }
421
422    /**
423     * Sets count of last hardware clock discontinuity.
424     * @hide
425     */
426    @TestApi
427    public void setHardwareClockDiscontinuityCount(int value) {
428        mHardwareClockDiscontinuityCount = value;
429    }
430
431    public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
432        @Override
433        public GnssClock createFromParcel(Parcel parcel) {
434            GnssClock gpsClock = new GnssClock();
435
436            gpsClock.mFlags = parcel.readInt();
437            gpsClock.mLeapSecond = parcel.readInt();
438            gpsClock.mTimeNanos = parcel.readLong();
439            gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
440            gpsClock.mFullBiasNanos = parcel.readLong();
441            gpsClock.mBiasNanos = parcel.readDouble();
442            gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
443            gpsClock.mDriftNanosPerSecond = parcel.readDouble();
444            gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
445            gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
446
447            return gpsClock;
448        }
449
450        @Override
451        public GnssClock[] newArray(int size) {
452            return new GnssClock[size];
453        }
454    };
455
456    @Override
457    public void writeToParcel(Parcel parcel, int flags) {
458        parcel.writeInt(mFlags);
459        parcel.writeInt(mLeapSecond);
460        parcel.writeLong(mTimeNanos);
461        parcel.writeDouble(mTimeUncertaintyNanos);
462        parcel.writeLong(mFullBiasNanos);
463        parcel.writeDouble(mBiasNanos);
464        parcel.writeDouble(mBiasUncertaintyNanos);
465        parcel.writeDouble(mDriftNanosPerSecond);
466        parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
467        parcel.writeInt(mHardwareClockDiscontinuityCount);
468    }
469
470    @Override
471    public int describeContents() {
472        return 0;
473    }
474
475    @Override
476    public String toString() {
477        final String format = "   %-15s = %s\n";
478        final String formatWithUncertainty = "   %-15s = %-25s   %-26s = %s\n";
479        StringBuilder builder = new StringBuilder("GnssClock:\n");
480
481        builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
482
483        builder.append(String.format(
484                formatWithUncertainty,
485                "TimeNanos",
486                mTimeNanos,
487                "TimeUncertaintyNanos",
488                hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
489
490        builder.append(String.format(
491                format,
492                "FullBiasNanos",
493                hasFullBiasNanos() ? mFullBiasNanos : null));
494
495        builder.append(String.format(
496                formatWithUncertainty,
497                "BiasNanos",
498                hasBiasNanos() ? mBiasNanos : null,
499                "BiasUncertaintyNanos",
500                hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
501
502        builder.append(String.format(
503                formatWithUncertainty,
504                "DriftNanosPerSecond",
505                hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
506                "DriftUncertaintyNanosPerSecond",
507                hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
508
509        builder.append(String.format(
510                format,
511                "HardwareClockDiscontinuityCount",
512                mHardwareClockDiscontinuityCount));
513
514        return builder.toString();
515    }
516
517    private void initialize() {
518        mFlags = HAS_NO_FLAGS;
519        resetLeapSecond();
520        setTimeNanos(Long.MIN_VALUE);
521        resetTimeUncertaintyNanos();
522        resetFullBiasNanos();
523        resetBiasNanos();
524        resetBiasUncertaintyNanos();
525        resetDriftNanosPerSecond();
526        resetDriftUncertaintyNanosPerSecond();
527        setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
528    }
529
530    private void setFlag(int flag) {
531        mFlags |= flag;
532    }
533
534    private void resetFlag(int flag) {
535        mFlags &= ~flag;
536    }
537
538    private boolean isFlagSet(int flag) {
539        return (mFlags & flag) == flag;
540    }
541}
542