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.SystemApi;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 import android.util.Log;
23 
24 /**
25  * A class containing a GPS clock timestamp.
26  * It represents a measurement of the GPS receiver's clock.
27  *
28  * @hide
29  */
30 @SystemApi
31 public class GpsClock implements Parcelable {
32     private static final String TAG = "GpsClock";
33 
34     // The following enumerations must be in sync with the values declared in gps.h
35 
36     /**
37      * The type of the time stored is not available or it is unknown.
38      */
39     public static final byte TYPE_UNKNOWN = 0;
40 
41     /**
42      * The source of the time value reported by this class is the 'Local Hardware Clock'.
43      */
44     public static final byte TYPE_LOCAL_HW_TIME = 1;
45 
46     /**
47      * The source of the time value reported by this class is the 'GPS time' derived from
48      * satellites (epoch = Jan 6, 1980).
49      */
50     public static final byte TYPE_GPS_TIME = 2;
51 
52     private static final short HAS_NO_FLAGS = 0;
53     private static final short HAS_LEAP_SECOND = (1<<0);
54     private static final short HAS_TIME_UNCERTAINTY = (1<<1);
55     private static final short HAS_FULL_BIAS = (1<<2);
56     private static final short HAS_BIAS = (1<<3);
57     private static final short HAS_BIAS_UNCERTAINTY = (1<<4);
58     private static final short HAS_DRIFT = (1<<5);
59     private static final short HAS_DRIFT_UNCERTAINTY = (1<<6);
60 
61     // End enumerations in sync with gps.h
62 
63     private short mFlags;
64     private short mLeapSecond;
65     private byte mType;
66     private long mTimeInNs;
67     private double mTimeUncertaintyInNs;
68     private long mFullBiasInNs;
69     private double mBiasInNs;
70     private double mBiasUncertaintyInNs;
71     private double mDriftInNsPerSec;
72     private double mDriftUncertaintyInNsPerSec;
73 
GpsClock()74     GpsClock() {
75         initialize();
76     }
77 
78     /**
79      * Sets all contents to the values stored in the provided object.
80      */
set(GpsClock clock)81     public void set(GpsClock clock) {
82         mFlags = clock.mFlags;
83         mLeapSecond = clock.mLeapSecond;
84         mType = clock.mType;
85         mTimeInNs = clock.mTimeInNs;
86         mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
87         mFullBiasInNs = clock.mFullBiasInNs;
88         mBiasInNs = clock.mBiasInNs;
89         mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
90         mDriftInNsPerSec = clock.mDriftInNsPerSec;
91         mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
92     }
93 
94     /**
95      * Resets all the contents to its original state.
96      */
reset()97     public void reset() {
98         initialize();
99     }
100 
101     /**
102      * Gets the type of time reported by {@link #getTimeInNs()}.
103      */
getType()104     public byte getType() {
105         return mType;
106     }
107 
108     /**
109      * Sets the type of time reported.
110      */
setType(byte value)111     public void setType(byte value) {
112         switch (value) {
113             case TYPE_UNKNOWN:
114             case TYPE_GPS_TIME:
115             case TYPE_LOCAL_HW_TIME:
116                 mType = value;
117                 break;
118             default:
119                 Log.d(TAG, "Sanitizing invalid 'type': " + value);
120                 mType = TYPE_UNKNOWN;
121                 break;
122         }
123     }
124 
125     /**
126      * Gets a string representation of the 'type'.
127      * For internal and logging use only.
128      */
getTypeString()129     private String getTypeString() {
130         switch (mType) {
131             case TYPE_UNKNOWN:
132                 return "Unknown";
133             case TYPE_GPS_TIME:
134                 return "GpsTime";
135             case TYPE_LOCAL_HW_TIME:
136                 return "LocalHwClock";
137             default:
138                 return "<Invalid>";
139         }
140     }
141 
142     /**
143      * Returns true if {@link #getLeapSecond()} is available, false otherwise.
144      */
hasLeapSecond()145     public boolean hasLeapSecond() {
146         return isFlagSet(HAS_LEAP_SECOND);
147     }
148 
149     /**
150      * Gets the leap second associated with the clock's time.
151      * The sign of the value is defined by the following equation:
152      *      utc_time_ns = time_ns + (full_bias_ns + bias_ns) - leap_second * 1,000,000,000
153      *
154      * The value is only available if {@link #hasLeapSecond()} is true.
155      */
getLeapSecond()156     public short getLeapSecond() {
157         return mLeapSecond;
158     }
159 
160     /**
161      * Sets the leap second associated with the clock's time.
162      */
setLeapSecond(short leapSecond)163     public void setLeapSecond(short leapSecond) {
164         setFlag(HAS_LEAP_SECOND);
165         mLeapSecond = leapSecond;
166     }
167 
168     /**
169      * Resets the leap second associated with the clock's time.
170      */
resetLeapSecond()171     public void resetLeapSecond() {
172         resetFlag(HAS_LEAP_SECOND);
173         mLeapSecond = Short.MIN_VALUE;
174     }
175 
176     /**
177      * Gets the GPS receiver internal clock value in nanoseconds.
178      * This can be either the 'local hardware clock' value ({@link #TYPE_LOCAL_HW_TIME}), or the
179      * current GPS time derived inside GPS receiver ({@link #TYPE_GPS_TIME}).
180      * {@link #getType()} defines the time reported.
181      *
182      * For 'local hardware clock' this value is expected to be monotonically increasing during the
183      * reporting session. The real GPS time can be derived by compensating
184      * {@link #getFullBiasInNs()} (when it is available) from this value.
185      *
186      * For 'GPS time' this value is expected to be the best estimation of current GPS time that GPS
187      * receiver can achieve. {@link #getTimeUncertaintyInNs()} should be available when GPS time is
188      * specified.
189      *
190      * Sub-nanosecond accuracy can be provided by means of {@link #getBiasInNs()}.
191      * The reported time includes {@link #getTimeUncertaintyInNs()}.
192      */
getTimeInNs()193     public long getTimeInNs() {
194         return mTimeInNs;
195     }
196 
197     /**
198      * Sets the GPS receiver internal clock in nanoseconds.
199      */
setTimeInNs(long timeInNs)200     public void setTimeInNs(long timeInNs) {
201         mTimeInNs = timeInNs;
202     }
203 
204     /**
205      * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
206      */
hasTimeUncertaintyInNs()207     public boolean hasTimeUncertaintyInNs() {
208         return isFlagSet(HAS_TIME_UNCERTAINTY);
209     }
210 
211     /**
212      * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
213      * The uncertainty is represented as an absolute (single sided) value.
214      *
215      * The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
216      */
getTimeUncertaintyInNs()217     public double getTimeUncertaintyInNs() {
218         return mTimeUncertaintyInNs;
219     }
220 
221     /**
222      * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
223      */
setTimeUncertaintyInNs(double timeUncertaintyInNs)224     public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
225         setFlag(HAS_TIME_UNCERTAINTY);
226         mTimeUncertaintyInNs = timeUncertaintyInNs;
227     }
228 
229     /**
230      * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
231      */
resetTimeUncertaintyInNs()232     public void resetTimeUncertaintyInNs() {
233         resetFlag(HAS_TIME_UNCERTAINTY);
234         mTimeUncertaintyInNs = Double.NaN;
235     }
236 
237     /**
238      * Returns true if {@link @getFullBiasInNs()} is available, false otherwise.
239      */
hasFullBiasInNs()240     public boolean hasFullBiasInNs() {
241         return isFlagSet(HAS_FULL_BIAS);
242     }
243 
244     /**
245      * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
246      * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
247      *
248      * This value is available if {@link #TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
249      * the clock for GPS time.
250      * {@link #getBiasUncertaintyInNs()} should be used for quality check.
251      *
252      * The sign of the value is defined by the following equation:
253      *      true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
254      *
255      * The reported full bias includes {@link #getBiasUncertaintyInNs()}.
256      * The value is onl available if {@link #hasFullBiasInNs()} is true.
257      */
getFullBiasInNs()258     public long getFullBiasInNs() {
259         return mFullBiasInNs;
260     }
261 
262     /**
263      * Sets the full bias in nanoseconds.
264      */
setFullBiasInNs(long value)265     public void setFullBiasInNs(long value) {
266         setFlag(HAS_FULL_BIAS);
267         mFullBiasInNs = value;
268     }
269 
270     /**
271      * Resets the full bias in nanoseconds.
272      */
resetFullBiasInNs()273     public void resetFullBiasInNs() {
274         resetFlag(HAS_FULL_BIAS);
275         mFullBiasInNs = Long.MIN_VALUE;
276     }
277 
278     /**
279      * Returns true if {@link #getBiasInNs()} is available, false otherwise.
280      */
hasBiasInNs()281     public boolean hasBiasInNs() {
282         return isFlagSet(HAS_BIAS);
283     }
284 
285     /**
286      * Gets the clock's sub-nanosecond bias.
287      * The reported bias includes {@link #getBiasUncertaintyInNs()}.
288      *
289      * The value is only available if {@link #hasBiasInNs()} is true.
290      */
getBiasInNs()291     public double getBiasInNs() {
292         return mBiasInNs;
293     }
294 
295     /**
296      * Sets the sub-nanosecond bias.
297      */
setBiasInNs(double biasInNs)298     public void setBiasInNs(double biasInNs) {
299         setFlag(HAS_BIAS);
300         mBiasInNs = biasInNs;
301     }
302 
303     /**
304      * Resets the clock's Bias in nanoseconds.
305      */
resetBiasInNs()306     public void resetBiasInNs() {
307         resetFlag(HAS_BIAS);
308         mBiasInNs = Double.NaN;
309     }
310 
311     /**
312      * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
313      */
hasBiasUncertaintyInNs()314     public boolean hasBiasUncertaintyInNs() {
315         return isFlagSet(HAS_BIAS_UNCERTAINTY);
316     }
317 
318     /**
319      * Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
320      *
321      * The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
322      */
getBiasUncertaintyInNs()323     public double getBiasUncertaintyInNs() {
324         return mBiasUncertaintyInNs;
325     }
326 
327     /**
328      * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
329      */
setBiasUncertaintyInNs(double biasUncertaintyInNs)330     public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
331         setFlag(HAS_BIAS_UNCERTAINTY);
332         mBiasUncertaintyInNs = biasUncertaintyInNs;
333     }
334 
335     /**
336      * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
337      */
resetBiasUncertaintyInNs()338     public void resetBiasUncertaintyInNs() {
339         resetFlag(HAS_BIAS_UNCERTAINTY);
340         mBiasUncertaintyInNs = Double.NaN;
341     }
342 
343     /**
344      * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
345      */
hasDriftInNsPerSec()346     public boolean hasDriftInNsPerSec() {
347         return isFlagSet(HAS_DRIFT);
348     }
349 
350     /**
351      * Gets the clock's Drift in nanoseconds per second.
352      * A positive value indicates that the frequency is higher than the nominal frequency.
353      * The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
354      *
355      * The value is only available if {@link #hasDriftInNsPerSec()} is true.
356      */
getDriftInNsPerSec()357     public double getDriftInNsPerSec() {
358         return mDriftInNsPerSec;
359     }
360 
361     /**
362      * Sets the clock's Drift in nanoseconds per second.
363      */
setDriftInNsPerSec(double driftInNsPerSec)364     public void setDriftInNsPerSec(double driftInNsPerSec) {
365         setFlag(HAS_DRIFT);
366         mDriftInNsPerSec = driftInNsPerSec;
367     }
368 
369     /**
370      * Resets the clock's Drift in nanoseconds per second.
371      */
resetDriftInNsPerSec()372     public void resetDriftInNsPerSec() {
373         resetFlag(HAS_DRIFT);
374         mDriftInNsPerSec = Double.NaN;
375     }
376 
377     /**
378      * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
379      */
hasDriftUncertaintyInNsPerSec()380     public boolean hasDriftUncertaintyInNsPerSec() {
381         return isFlagSet(HAS_DRIFT_UNCERTAINTY);
382     }
383 
384     /**
385      * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
386      *
387      * The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
388      */
getDriftUncertaintyInNsPerSec()389     public double getDriftUncertaintyInNsPerSec() {
390         return mDriftUncertaintyInNsPerSec;
391     }
392 
393     /**
394      * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
395      */
setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec)396     public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
397         setFlag(HAS_DRIFT_UNCERTAINTY);
398         mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
399     }
400 
401     /**
402      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
403      */
resetDriftUncertaintyInNsPerSec()404     public void resetDriftUncertaintyInNsPerSec() {
405         resetFlag(HAS_DRIFT_UNCERTAINTY);
406         mDriftUncertaintyInNsPerSec = Double.NaN;
407     }
408 
409     public static final Creator<GpsClock> CREATOR = new Creator<GpsClock>() {
410         @Override
411         public GpsClock createFromParcel(Parcel parcel) {
412             GpsClock gpsClock = new GpsClock();
413 
414             gpsClock.mFlags = (short) parcel.readInt();
415             gpsClock.mLeapSecond = (short) parcel.readInt();
416             gpsClock.mType = parcel.readByte();
417             gpsClock.mTimeInNs = parcel.readLong();
418             gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
419             gpsClock.mFullBiasInNs = parcel.readLong();
420             gpsClock.mBiasInNs = parcel.readDouble();
421             gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
422             gpsClock.mDriftInNsPerSec = parcel.readDouble();
423             gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
424 
425             return gpsClock;
426         }
427 
428         @Override
429         public GpsClock[] newArray(int size) {
430             return new GpsClock[size];
431         }
432     };
433 
writeToParcel(Parcel parcel, int flags)434     public void writeToParcel(Parcel parcel, int flags) {
435         parcel.writeInt(mFlags);
436         parcel.writeInt(mLeapSecond);
437         parcel.writeByte(mType);
438         parcel.writeLong(mTimeInNs);
439         parcel.writeDouble(mTimeUncertaintyInNs);
440         parcel.writeLong(mFullBiasInNs);
441         parcel.writeDouble(mBiasInNs);
442         parcel.writeDouble(mBiasUncertaintyInNs);
443         parcel.writeDouble(mDriftInNsPerSec);
444         parcel.writeDouble(mDriftUncertaintyInNsPerSec);
445     }
446 
447     @Override
describeContents()448     public int describeContents() {
449         return 0;
450     }
451 
452     @Override
toString()453     public String toString() {
454         final String format = "   %-15s = %s\n";
455         final String formatWithUncertainty = "   %-15s = %-25s   %-26s = %s\n";
456         StringBuilder builder = new StringBuilder("GpsClock:\n");
457 
458         builder.append(String.format(format, "Type", getTypeString()));
459 
460         builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
461 
462         builder.append(String.format(
463                 formatWithUncertainty,
464                 "TimeInNs",
465                 mTimeInNs,
466                 "TimeUncertaintyInNs",
467                 hasTimeUncertaintyInNs() ? mTimeUncertaintyInNs : null));
468 
469         builder.append(String.format(
470                 format,
471                 "FullBiasInNs",
472                 hasFullBiasInNs() ? mFullBiasInNs : null));
473 
474         builder.append(String.format(
475                 formatWithUncertainty,
476                 "BiasInNs",
477                 hasBiasInNs() ? mBiasInNs : null,
478                 "BiasUncertaintyInNs",
479                 hasBiasUncertaintyInNs() ? mBiasUncertaintyInNs : null));
480 
481         builder.append(String.format(
482                 formatWithUncertainty,
483                 "DriftInNsPerSec",
484                 hasDriftInNsPerSec() ? mDriftInNsPerSec : null,
485                 "DriftUncertaintyInNsPerSec",
486                 hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
487 
488         return builder.toString();
489     }
490 
initialize()491     private void initialize() {
492         mFlags = HAS_NO_FLAGS;
493         resetLeapSecond();
494         setType(TYPE_UNKNOWN);
495         setTimeInNs(Long.MIN_VALUE);
496         resetTimeUncertaintyInNs();
497         resetFullBiasInNs();
498         resetBiasInNs();
499         resetBiasUncertaintyInNs();
500         resetDriftInNsPerSec();
501         resetDriftUncertaintyInNsPerSec();
502     }
503 
setFlag(short flag)504     private void setFlag(short flag) {
505         mFlags |= flag;
506     }
507 
resetFlag(short flag)508     private void resetFlag(short flag) {
509         mFlags &= ~flag;
510     }
511 
isFlagSet(short flag)512     private boolean isFlagSet(short flag) {
513         return (mFlags & flag) == flag;
514     }
515 }
516