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