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 * & 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