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 
17 package android.location;
18 
19 import android.annotation.TestApi;
20 import android.os.Parcel;
21 import 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  */
28 public 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
GnssClock()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
set(GnssClock clock)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
reset()84     public void reset() {
85         initialize();
86     }
87 
88     /**
89      * Returns {@code true} if {@link #getLeapSecond()} is available, {@code false} otherwise.
90      */
hasLeapSecond()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      */
getLeapSecond()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
setLeapSecond(int leapSecond)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
resetLeapSecond()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      */
getTimeNanos()139     public long getTimeNanos() {
140         return mTimeNanos;
141     }
142 
143     /**
144      * Sets the GNSS receiver internal clock in nanoseconds.
145      * @hide
146      */
147     @TestApi
setTimeNanos(long timeNanos)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      */
hasTimeUncertaintyNanos()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      */
getTimeUncertaintyNanos()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
setTimeUncertaintyNanos(double timeUncertaintyNanos)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
resetTimeUncertaintyNanos()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      */
hasFullBiasNanos()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      */
getFullBiasNanos()218     public long getFullBiasNanos() {
219         return mFullBiasNanos;
220     }
221 
222     /**
223      * Sets the full bias in nanoseconds.
224      * @hide
225      */
226     @TestApi
setFullBiasNanos(long value)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
resetFullBiasNanos()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      */
hasBiasNanos()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      */
getBiasNanos()260     public double getBiasNanos() {
261         return mBiasNanos;
262     }
263 
264     /**
265      * Sets the sub-nanosecond bias.
266      * @hide
267      */
268     @TestApi
setBiasNanos(double biasNanos)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
resetBiasNanos()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      */
hasBiasUncertaintyNanos()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      */
getBiasUncertaintyNanos()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
setBiasUncertaintyNanos(double biasUncertaintyNanos)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
resetBiasUncertaintyNanos()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      */
hasDriftNanosPerSecond()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      */
getDriftNanosPerSecond()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
setDriftNanosPerSecond(double driftNanosPerSecond)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
resetDriftNanosPerSecond()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      */
hasDriftUncertaintyNanosPerSecond()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      */
getDriftUncertaintyNanosPerSecond()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
setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond)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
resetDriftUncertaintyNanosPerSecond()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      */
getHardwareClockDiscontinuityCount()418     public int getHardwareClockDiscontinuityCount() {
419         return mHardwareClockDiscontinuityCount;
420     }
421 
422     /**
423      * Sets count of last hardware clock discontinuity.
424      * @hide
425      */
426     @TestApi
setHardwareClockDiscontinuityCount(int value)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
writeToParcel(Parcel parcel, int flags)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
describeContents()471     public int describeContents() {
472         return 0;
473     }
474 
475     @Override
toString()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 
initialize()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 
setFlag(int flag)530     private void setFlag(int flag) {
531         mFlags |= flag;
532     }
533 
resetFlag(int flag)534     private void resetFlag(int flag) {
535         mFlags &= ~flag;
536     }
537 
isFlagSet(int flag)538     private boolean isFlagSet(int flag) {
539         return (mFlags & flag) == flag;
540     }
541 }
542