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