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