Home | History | Annotate | Download | only in location
      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
     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
     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
     84     public void reset() {
     85         initialize();
     86     }
     87 
     88     /**
     89      * Returns {@code true} if {@link #getLeapSecond()} is available, {@code false} otherwise.
     90      */
     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      */
    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
    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
    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      */
    139     public long getTimeNanos() {
    140         return mTimeNanos;
    141     }
    142 
    143     /**
    144      * Sets the GNSS receiver internal clock in nanoseconds.
    145      * @hide
    146      */
    147     @TestApi
    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      */
    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      */
    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
    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
    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      */
    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      */
    218     public long getFullBiasNanos() {
    219         return mFullBiasNanos;
    220     }
    221 
    222     /**
    223      * Sets the full bias in nanoseconds.
    224      * @hide
    225      */
    226     @TestApi
    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
    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      */
    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      */
    260     public double getBiasNanos() {
    261         return mBiasNanos;
    262     }
    263 
    264     /**
    265      * Sets the sub-nanosecond bias.
    266      * @hide
    267      */
    268     @TestApi
    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
    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      */
    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      */
    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
    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
    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      */
    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>This value is the instantaneous time-derivative of the value provided by
    336      * {@link #getBiasNanos()}.
    337      *
    338      * <p>A positive value indicates that the frequency is higher than the nominal (e.g. GPS master
    339      * clock) frequency. The error estimate for this reported drift is
    340      * {@link #getDriftUncertaintyNanosPerSecond()}.
    341      *
    342      * <p>The value is only available if {@link #hasDriftNanosPerSecond()} is {@code true}.
    343      */
    344     public double getDriftNanosPerSecond() {
    345         return mDriftNanosPerSecond;
    346     }
    347 
    348     /**
    349      * Sets the clock's Drift in nanoseconds per second.
    350      * @hide
    351      */
    352     @TestApi
    353     public void setDriftNanosPerSecond(double driftNanosPerSecond) {
    354         setFlag(HAS_DRIFT);
    355         mDriftNanosPerSecond = driftNanosPerSecond;
    356     }
    357 
    358     /**
    359      * Resets the clock's Drift in nanoseconds per second.
    360      * @hide
    361      */
    362     @TestApi
    363     public void resetDriftNanosPerSecond() {
    364         resetFlag(HAS_DRIFT);
    365         mDriftNanosPerSecond = Double.NaN;
    366     }
    367 
    368     /**
    369      * Returns {@code true} if {@link #getDriftUncertaintyNanosPerSecond()} is available,
    370      * {@code false} otherwise.
    371      */
    372     public boolean hasDriftUncertaintyNanosPerSecond() {
    373         return isFlagSet(HAS_DRIFT_UNCERTAINTY);
    374     }
    375 
    376     /**
    377      * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
    378      *
    379      * <p>The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is
    380      * {@code true}.
    381      */
    382     public double getDriftUncertaintyNanosPerSecond() {
    383         return mDriftUncertaintyNanosPerSecond;
    384     }
    385 
    386     /**
    387      * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
    388      * @hide
    389      */
    390     @TestApi
    391     public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
    392         setFlag(HAS_DRIFT_UNCERTAINTY);
    393         mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
    394     }
    395 
    396     /**
    397      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
    398      * @hide
    399      */
    400     @TestApi
    401     public void resetDriftUncertaintyNanosPerSecond() {
    402         resetFlag(HAS_DRIFT_UNCERTAINTY);
    403         mDriftUncertaintyNanosPerSecond = Double.NaN;
    404     }
    405 
    406     /**
    407      * Gets count of hardware clock discontinuities.
    408      *
    409      * <p>When this value stays the same, vs. a value in a previously reported {@link GnssClock}, it
    410      * can be safely assumed that the {@code TimeNanos} value has been derived from a clock that has
    411      * been running continuously - e.g. a single continuously powered crystal oscillator, and thus
    412      * the {@code (FullBiasNanos + BiasNanos)} offset can be modelled with traditional clock bias
    413      * &amp; drift models.
    414      *
    415      * <p>Each time this value changes, vs. the value in a previously reported {@link GnssClock},
    416      * that suggests the hardware clock may have experienced a discontinuity (e.g. a power cycle or
    417      * other anomaly), so that any assumptions about modelling a smoothly changing
    418      * {@code (FullBiasNanos + BiasNanos)} offset, and a smoothly growing {@code (TimeNanos)}
    419      * between this and the previously reported {@code GnssClock}, should be reset.
    420      */
    421     public int getHardwareClockDiscontinuityCount() {
    422         return mHardwareClockDiscontinuityCount;
    423     }
    424 
    425     /**
    426      * Sets count of last hardware clock discontinuity.
    427      * @hide
    428      */
    429     @TestApi
    430     public void setHardwareClockDiscontinuityCount(int value) {
    431         mHardwareClockDiscontinuityCount = value;
    432     }
    433 
    434     public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
    435         @Override
    436         public GnssClock createFromParcel(Parcel parcel) {
    437             GnssClock gpsClock = new GnssClock();
    438 
    439             gpsClock.mFlags = parcel.readInt();
    440             gpsClock.mLeapSecond = parcel.readInt();
    441             gpsClock.mTimeNanos = parcel.readLong();
    442             gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
    443             gpsClock.mFullBiasNanos = parcel.readLong();
    444             gpsClock.mBiasNanos = parcel.readDouble();
    445             gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
    446             gpsClock.mDriftNanosPerSecond = parcel.readDouble();
    447             gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
    448             gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
    449 
    450             return gpsClock;
    451         }
    452 
    453         @Override
    454         public GnssClock[] newArray(int size) {
    455             return new GnssClock[size];
    456         }
    457     };
    458 
    459     @Override
    460     public void writeToParcel(Parcel parcel, int flags) {
    461         parcel.writeInt(mFlags);
    462         parcel.writeInt(mLeapSecond);
    463         parcel.writeLong(mTimeNanos);
    464         parcel.writeDouble(mTimeUncertaintyNanos);
    465         parcel.writeLong(mFullBiasNanos);
    466         parcel.writeDouble(mBiasNanos);
    467         parcel.writeDouble(mBiasUncertaintyNanos);
    468         parcel.writeDouble(mDriftNanosPerSecond);
    469         parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
    470         parcel.writeInt(mHardwareClockDiscontinuityCount);
    471     }
    472 
    473     @Override
    474     public int describeContents() {
    475         return 0;
    476     }
    477 
    478     @Override
    479     public String toString() {
    480         final String format = "   %-15s = %s\n";
    481         final String formatWithUncertainty = "   %-15s = %-25s   %-26s = %s\n";
    482         StringBuilder builder = new StringBuilder("GnssClock:\n");
    483 
    484         builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
    485 
    486         builder.append(String.format(
    487                 formatWithUncertainty,
    488                 "TimeNanos",
    489                 mTimeNanos,
    490                 "TimeUncertaintyNanos",
    491                 hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
    492 
    493         builder.append(String.format(
    494                 format,
    495                 "FullBiasNanos",
    496                 hasFullBiasNanos() ? mFullBiasNanos : null));
    497 
    498         builder.append(String.format(
    499                 formatWithUncertainty,
    500                 "BiasNanos",
    501                 hasBiasNanos() ? mBiasNanos : null,
    502                 "BiasUncertaintyNanos",
    503                 hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
    504 
    505         builder.append(String.format(
    506                 formatWithUncertainty,
    507                 "DriftNanosPerSecond",
    508                 hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
    509                 "DriftUncertaintyNanosPerSecond",
    510                 hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
    511 
    512         builder.append(String.format(
    513                 format,
    514                 "HardwareClockDiscontinuityCount",
    515                 mHardwareClockDiscontinuityCount));
    516 
    517         return builder.toString();
    518     }
    519 
    520     private void initialize() {
    521         mFlags = HAS_NO_FLAGS;
    522         resetLeapSecond();
    523         setTimeNanos(Long.MIN_VALUE);
    524         resetTimeUncertaintyNanos();
    525         resetFullBiasNanos();
    526         resetBiasNanos();
    527         resetBiasUncertaintyNanos();
    528         resetDriftNanosPerSecond();
    529         resetDriftUncertaintyNanosPerSecond();
    530         setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
    531     }
    532 
    533     private void setFlag(int flag) {
    534         mFlags |= flag;
    535     }
    536 
    537     private void resetFlag(int flag) {
    538         mFlags &= ~flag;
    539     }
    540 
    541     private boolean isFlagSet(int flag) {
    542         return (mFlags & flag) == flag;
    543     }
    544 }
    545