542 lines
17 KiB
Java
542 lines
17 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License
|
|
*/
|
|
|
|
package android.location;
|
|
|
|
import android.annotation.TestApi;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
|
|
/**
|
|
* A class containing a GPS clock timestamp.
|
|
*
|
|
* <p>It represents a measurement of the GPS receiver's clock.
|
|
*/
|
|
public final class GnssClock implements Parcelable {
|
|
// The following enumerations must be in sync with the values declared in gps.h
|
|
|
|
private static final int HAS_NO_FLAGS = 0;
|
|
private static final int HAS_LEAP_SECOND = (1<<0);
|
|
private static final int HAS_TIME_UNCERTAINTY = (1<<1);
|
|
private static final int HAS_FULL_BIAS = (1<<2);
|
|
private static final int HAS_BIAS = (1<<3);
|
|
private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
|
|
private static final int HAS_DRIFT = (1<<5);
|
|
private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
|
|
|
|
// End enumerations in sync with gps.h
|
|
|
|
private int mFlags;
|
|
private int mLeapSecond;
|
|
private long mTimeNanos;
|
|
private double mTimeUncertaintyNanos;
|
|
private long mFullBiasNanos;
|
|
private double mBiasNanos;
|
|
private double mBiasUncertaintyNanos;
|
|
private double mDriftNanosPerSecond;
|
|
private double mDriftUncertaintyNanosPerSecond;
|
|
private int mHardwareClockDiscontinuityCount;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public GnssClock() {
|
|
initialize();
|
|
}
|
|
|
|
/**
|
|
* Sets all contents to the values stored in the provided object.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void set(GnssClock clock) {
|
|
mFlags = clock.mFlags;
|
|
mLeapSecond = clock.mLeapSecond;
|
|
mTimeNanos = clock.mTimeNanos;
|
|
mTimeUncertaintyNanos = clock.mTimeUncertaintyNanos;
|
|
mFullBiasNanos = clock.mFullBiasNanos;
|
|
mBiasNanos = clock.mBiasNanos;
|
|
mBiasUncertaintyNanos = clock.mBiasUncertaintyNanos;
|
|
mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
|
|
mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
|
|
mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
|
|
}
|
|
|
|
/**
|
|
* Resets all the contents to its original state.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void reset() {
|
|
initialize();
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getLeapSecond()} is available, {@code false} otherwise.
|
|
*/
|
|
public boolean hasLeapSecond() {
|
|
return isFlagSet(HAS_LEAP_SECOND);
|
|
}
|
|
|
|
/**
|
|
* Gets the leap second associated with the clock's time.
|
|
*
|
|
* <p>The sign of the value is defined by the following equation:
|
|
* <pre>
|
|
* UtcTimeNanos = TimeNanos - (FullBiasNanos + BiasNanos) - LeapSecond * 1,000,000,000</pre>
|
|
*
|
|
* <p>The value is only available if {@link #hasLeapSecond()} is {@code true}.
|
|
*/
|
|
public int getLeapSecond() {
|
|
return mLeapSecond;
|
|
}
|
|
|
|
/**
|
|
* Sets the leap second associated with the clock's time.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setLeapSecond(int leapSecond) {
|
|
setFlag(HAS_LEAP_SECOND);
|
|
mLeapSecond = leapSecond;
|
|
}
|
|
|
|
/**
|
|
* Resets the leap second associated with the clock's time.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetLeapSecond() {
|
|
resetFlag(HAS_LEAP_SECOND);
|
|
mLeapSecond = Integer.MIN_VALUE;
|
|
}
|
|
|
|
/**
|
|
* Gets the GNSS receiver internal hardware clock value in nanoseconds.
|
|
*
|
|
* <p>This value is expected to be monotonically increasing while the hardware clock remains
|
|
* powered on. For the case of a hardware clock that is not continuously on, see the
|
|
* {@link #getHardwareClockDiscontinuityCount} field. The GPS time can be derived by subtracting
|
|
* the sum of {@link #getFullBiasNanos()} and {@link #getBiasNanos()} (when they are available)
|
|
* from this value. Sub-nanosecond accuracy can be provided by means of {@link #getBiasNanos()}.
|
|
*
|
|
* <p>The error estimate for this value (if applicable) is {@link #getTimeUncertaintyNanos()}.
|
|
*/
|
|
public long getTimeNanos() {
|
|
return mTimeNanos;
|
|
}
|
|
|
|
/**
|
|
* Sets the GNSS receiver internal clock in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setTimeNanos(long timeNanos) {
|
|
mTimeNanos = timeNanos;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getTimeUncertaintyNanos()} is available, {@code false}
|
|
* otherwise.
|
|
*/
|
|
public boolean hasTimeUncertaintyNanos() {
|
|
return isFlagSet(HAS_TIME_UNCERTAINTY);
|
|
}
|
|
|
|
/**
|
|
* Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
|
|
*
|
|
* <p>The uncertainty is represented as an absolute (single sided) value.
|
|
*
|
|
* <p>The value is only available if {@link #hasTimeUncertaintyNanos()} is {@code true}.
|
|
*
|
|
* <p>This value is often effectively zero (it is the reference clock by which all other times
|
|
* and time uncertainties are measured), and thus this field may often be 0, or not provided.
|
|
*/
|
|
public double getTimeUncertaintyNanos() {
|
|
return mTimeUncertaintyNanos;
|
|
}
|
|
|
|
/**
|
|
* Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
|
|
setFlag(HAS_TIME_UNCERTAINTY);
|
|
mTimeUncertaintyNanos = timeUncertaintyNanos;
|
|
}
|
|
|
|
/**
|
|
* Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetTimeUncertaintyNanos() {
|
|
resetFlag(HAS_TIME_UNCERTAINTY);
|
|
mTimeUncertaintyNanos = Double.NaN;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getFullBiasNanos()} is available, {@code false} otherwise.
|
|
*/
|
|
public boolean hasFullBiasNanos() {
|
|
return isFlagSet(HAS_FULL_BIAS);
|
|
}
|
|
|
|
/**
|
|
* Gets the difference between hardware clock ({@link #getTimeNanos()}) inside GPS receiver and
|
|
* the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
|
|
*
|
|
* <p>This value is available if the receiver has estimated GPS time. If the computed time is
|
|
* for a non-GPS constellation, the time offset of that constellation to GPS has to be applied
|
|
* to fill this value. The value is only available if {@link #hasFullBiasNanos()} is
|
|
* {@code true}.
|
|
*
|
|
* <p>The error estimate for the sum of this field and {@link #getBiasNanos} is
|
|
* {@link #getBiasUncertaintyNanos()}.
|
|
*
|
|
* <p>The sign of the value is defined by the following equation:
|
|
*
|
|
* <pre>
|
|
* local estimate of GPS time = TimeNanos - (FullBiasNanos + BiasNanos)</pre>
|
|
*/
|
|
public long getFullBiasNanos() {
|
|
return mFullBiasNanos;
|
|
}
|
|
|
|
/**
|
|
* Sets the full bias in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setFullBiasNanos(long value) {
|
|
setFlag(HAS_FULL_BIAS);
|
|
mFullBiasNanos = value;
|
|
}
|
|
|
|
/**
|
|
* Resets the full bias in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetFullBiasNanos() {
|
|
resetFlag(HAS_FULL_BIAS);
|
|
mFullBiasNanos = Long.MIN_VALUE;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getBiasNanos()} is available, {@code false} otherwise.
|
|
*/
|
|
public boolean hasBiasNanos() {
|
|
return isFlagSet(HAS_BIAS);
|
|
}
|
|
|
|
/**
|
|
* Gets the clock's sub-nanosecond bias.
|
|
*
|
|
* <p>See the description of how this field is part of converting from hardware clock time, to
|
|
* GPS time, in {@link #getFullBiasNanos()}.
|
|
*
|
|
* <p>The error estimate for the sum of this field and {@link #getFullBiasNanos} is
|
|
* {@link #getBiasUncertaintyNanos()}.
|
|
*
|
|
* <p>The value is only available if {@link #hasBiasNanos()} is {@code true}.
|
|
*/
|
|
public double getBiasNanos() {
|
|
return mBiasNanos;
|
|
}
|
|
|
|
/**
|
|
* Sets the sub-nanosecond bias.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setBiasNanos(double biasNanos) {
|
|
setFlag(HAS_BIAS);
|
|
mBiasNanos = biasNanos;
|
|
}
|
|
|
|
/**
|
|
* Resets the clock's Bias in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetBiasNanos() {
|
|
resetFlag(HAS_BIAS);
|
|
mBiasNanos = Double.NaN;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getBiasUncertaintyNanos()} is available, {@code false}
|
|
* otherwise.
|
|
*/
|
|
public boolean hasBiasUncertaintyNanos() {
|
|
return isFlagSet(HAS_BIAS_UNCERTAINTY);
|
|
}
|
|
|
|
/**
|
|
* Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
|
|
*
|
|
* <p>See the description of how this field provides the error estimate in the conversion from
|
|
* hardware clock time, to GPS time, in {@link #getFullBiasNanos()}.
|
|
*
|
|
* <p>The value is only available if {@link #hasBiasUncertaintyNanos()} is {@code true}.
|
|
*/
|
|
public double getBiasUncertaintyNanos() {
|
|
return mBiasUncertaintyNanos;
|
|
}
|
|
|
|
/**
|
|
* Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
|
|
setFlag(HAS_BIAS_UNCERTAINTY);
|
|
mBiasUncertaintyNanos = biasUncertaintyNanos;
|
|
}
|
|
|
|
/**
|
|
* Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetBiasUncertaintyNanos() {
|
|
resetFlag(HAS_BIAS_UNCERTAINTY);
|
|
mBiasUncertaintyNanos = Double.NaN;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getDriftNanosPerSecond()} is available, {@code false}
|
|
* otherwise.
|
|
*/
|
|
public boolean hasDriftNanosPerSecond() {
|
|
return isFlagSet(HAS_DRIFT);
|
|
}
|
|
|
|
/**
|
|
* Gets the clock's Drift in nanoseconds per second.
|
|
*
|
|
* <p>A positive value indicates that the frequency is higher than the nominal (e.g. GPS master
|
|
* clock) frequency. The error estimate for this reported drift is
|
|
* {@link #getDriftUncertaintyNanosPerSecond()}.
|
|
*
|
|
* <p>The value is only available if {@link #hasDriftNanosPerSecond()} is {@code true}.
|
|
*/
|
|
public double getDriftNanosPerSecond() {
|
|
return mDriftNanosPerSecond;
|
|
}
|
|
|
|
/**
|
|
* Sets the clock's Drift in nanoseconds per second.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setDriftNanosPerSecond(double driftNanosPerSecond) {
|
|
setFlag(HAS_DRIFT);
|
|
mDriftNanosPerSecond = driftNanosPerSecond;
|
|
}
|
|
|
|
/**
|
|
* Resets the clock's Drift in nanoseconds per second.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetDriftNanosPerSecond() {
|
|
resetFlag(HAS_DRIFT);
|
|
mDriftNanosPerSecond = Double.NaN;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if {@link #getDriftUncertaintyNanosPerSecond()} is available,
|
|
* {@code false} otherwise.
|
|
*/
|
|
public boolean hasDriftUncertaintyNanosPerSecond() {
|
|
return isFlagSet(HAS_DRIFT_UNCERTAINTY);
|
|
}
|
|
|
|
/**
|
|
* Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
|
|
*
|
|
* <p>The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is
|
|
* {@code true}.
|
|
*/
|
|
public double getDriftUncertaintyNanosPerSecond() {
|
|
return mDriftUncertaintyNanosPerSecond;
|
|
}
|
|
|
|
/**
|
|
* Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
|
|
setFlag(HAS_DRIFT_UNCERTAINTY);
|
|
mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
|
|
}
|
|
|
|
/**
|
|
* Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void resetDriftUncertaintyNanosPerSecond() {
|
|
resetFlag(HAS_DRIFT_UNCERTAINTY);
|
|
mDriftUncertaintyNanosPerSecond = Double.NaN;
|
|
}
|
|
|
|
/**
|
|
* Gets count of hardware clock discontinuities.
|
|
*
|
|
* <p>When this value stays the same, vs. a value in a previously reported {@link GnssClock}, it
|
|
* can be safely assumed that the {@code TimeNanos} value has been derived from a clock that has
|
|
* been running continuously - e.g. a single continuously powered crystal oscillator, and thus
|
|
* the {@code (FullBiasNanos + BiasNanos)} offset can be modelled with traditional clock bias
|
|
* & drift models.
|
|
*
|
|
* <p>Each time this value changes, vs. the value in a previously reported {@link GnssClock},
|
|
* that suggests the hardware clock may have experienced a discontinuity (e.g. a power cycle or
|
|
* other anomaly), so that any assumptions about modelling a smoothly changing
|
|
* {@code (FullBiasNanos + BiasNanos)} offset, and a smoothly growing {@code (TimeNanos)}
|
|
* between this and the previously reported {@code GnssClock}, should be reset.
|
|
*/
|
|
public int getHardwareClockDiscontinuityCount() {
|
|
return mHardwareClockDiscontinuityCount;
|
|
}
|
|
|
|
/**
|
|
* Sets count of last hardware clock discontinuity.
|
|
* @hide
|
|
*/
|
|
@TestApi
|
|
public void setHardwareClockDiscontinuityCount(int value) {
|
|
mHardwareClockDiscontinuityCount = value;
|
|
}
|
|
|
|
public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
|
|
@Override
|
|
public GnssClock createFromParcel(Parcel parcel) {
|
|
GnssClock gpsClock = new GnssClock();
|
|
|
|
gpsClock.mFlags = parcel.readInt();
|
|
gpsClock.mLeapSecond = parcel.readInt();
|
|
gpsClock.mTimeNanos = parcel.readLong();
|
|
gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
|
|
gpsClock.mFullBiasNanos = parcel.readLong();
|
|
gpsClock.mBiasNanos = parcel.readDouble();
|
|
gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
|
|
gpsClock.mDriftNanosPerSecond = parcel.readDouble();
|
|
gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
|
|
gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
|
|
|
|
return gpsClock;
|
|
}
|
|
|
|
@Override
|
|
public GnssClock[] newArray(int size) {
|
|
return new GnssClock[size];
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel parcel, int flags) {
|
|
parcel.writeInt(mFlags);
|
|
parcel.writeInt(mLeapSecond);
|
|
parcel.writeLong(mTimeNanos);
|
|
parcel.writeDouble(mTimeUncertaintyNanos);
|
|
parcel.writeLong(mFullBiasNanos);
|
|
parcel.writeDouble(mBiasNanos);
|
|
parcel.writeDouble(mBiasUncertaintyNanos);
|
|
parcel.writeDouble(mDriftNanosPerSecond);
|
|
parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
|
|
parcel.writeInt(mHardwareClockDiscontinuityCount);
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
final String format = " %-15s = %s\n";
|
|
final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n";
|
|
StringBuilder builder = new StringBuilder("GnssClock:\n");
|
|
|
|
builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
|
|
|
|
builder.append(String.format(
|
|
formatWithUncertainty,
|
|
"TimeNanos",
|
|
mTimeNanos,
|
|
"TimeUncertaintyNanos",
|
|
hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
|
|
|
|
builder.append(String.format(
|
|
format,
|
|
"FullBiasNanos",
|
|
hasFullBiasNanos() ? mFullBiasNanos : null));
|
|
|
|
builder.append(String.format(
|
|
formatWithUncertainty,
|
|
"BiasNanos",
|
|
hasBiasNanos() ? mBiasNanos : null,
|
|
"BiasUncertaintyNanos",
|
|
hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
|
|
|
|
builder.append(String.format(
|
|
formatWithUncertainty,
|
|
"DriftNanosPerSecond",
|
|
hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
|
|
"DriftUncertaintyNanosPerSecond",
|
|
hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
|
|
|
|
builder.append(String.format(
|
|
format,
|
|
"HardwareClockDiscontinuityCount",
|
|
mHardwareClockDiscontinuityCount));
|
|
|
|
return builder.toString();
|
|
}
|
|
|
|
private void initialize() {
|
|
mFlags = HAS_NO_FLAGS;
|
|
resetLeapSecond();
|
|
setTimeNanos(Long.MIN_VALUE);
|
|
resetTimeUncertaintyNanos();
|
|
resetFullBiasNanos();
|
|
resetBiasNanos();
|
|
resetBiasUncertaintyNanos();
|
|
resetDriftNanosPerSecond();
|
|
resetDriftUncertaintyNanosPerSecond();
|
|
setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
|
|
}
|
|
|
|
private void setFlag(int flag) {
|
|
mFlags |= flag;
|
|
}
|
|
|
|
private void resetFlag(int flag) {
|
|
mFlags &= ~flag;
|
|
}
|
|
|
|
private boolean isFlagSet(int flag) {
|
|
return (mFlags & flag) == flag;
|
|
}
|
|
}
|