GpsClock.java revision a62050d42c7d76d57ae555ffcb6d8efc5cf79de1
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.SystemApi;
20import android.os.Parcel;
21import android.os.Parcelable;
22import 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
31public 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
74    GpsClock() {
75        initialize();
76    }
77
78    /**
79     * Sets all contents to the values stored in the provided object.
80     */
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     */
97    public void reset() {
98        initialize();
99    }
100
101    /**
102     * Gets the type of time reported by {@link #getTimeInNs()}.
103     */
104    public byte getType() {
105        return mType;
106    }
107
108    /**
109     * Sets the type of time reported.
110     */
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     */
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     */
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     */
156    public short getLeapSecond() {
157        return mLeapSecond;
158    }
159
160    /**
161     * Sets the leap second associated with the clock's time.
162     */
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     */
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     */
193    public long getTimeInNs() {
194        return mTimeInNs;
195    }
196
197    /**
198     * Sets the GPS receiver internal clock in nanoseconds.
199     */
200    public void setTimeInNs(long timeInNs) {
201        mTimeInNs = timeInNs;
202    }
203
204    /**
205     * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
206     */
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     */
217    public double getTimeUncertaintyInNs() {
218        return mTimeUncertaintyInNs;
219    }
220
221    /**
222     * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
223     */
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     */
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     */
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     */
258    public long getFullBiasInNs() {
259        return mFullBiasInNs;
260    }
261
262    /**
263     * Sets the full bias in nanoseconds.
264     */
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     */
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     */
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     */
291    public double getBiasInNs() {
292        return mBiasInNs;
293    }
294
295    /**
296     * Sets the sub-nanosecond bias.
297     */
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     */
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     */
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     */
323    public double getBiasUncertaintyInNs() {
324        return mBiasUncertaintyInNs;
325    }
326
327    /**
328     * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
329     */
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     */
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     */
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     */
357    public double getDriftInNsPerSec() {
358        return mDriftInNsPerSec;
359    }
360
361    /**
362     * Sets the clock's Drift in nanoseconds per second.
363     */
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     */
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     */
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     */
389    public double getDriftUncertaintyInNsPerSec() {
390        return mDriftUncertaintyInNsPerSec;
391    }
392
393    /**
394     * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
395     */
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     */
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
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
448    public int describeContents() {
449        return 0;
450    }
451
452    @Override
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
491    private void initialize() {
492        mFlags = HAS_NO_FLAGS;
493        resetLeapSecond();
494        setType(TYPE_UNKNOWN);
495        setTimeInNs(Long.MIN_VALUE);
496        resetTimeUncertaintyInNs();
497        resetBiasInNs();
498        resetBiasUncertaintyInNs();
499        resetDriftInNsPerSec();
500        resetDriftUncertaintyInNsPerSec();
501    }
502
503    private void setFlag(short flag) {
504        mFlags |= flag;
505    }
506
507    private void resetFlag(short flag) {
508        mFlags &= ~flag;
509    }
510
511    private boolean isFlagSet(short flag) {
512        return (mFlags & flag) == flag;
513    }
514}
515