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