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