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