/* * 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.SystemApi; import android.os.Parcel; import android.os.Parcelable; /** * A class representing a GPS satellite measurement, containing raw and computed information. * * @hide */ @SystemApi public class GpsMeasurement implements Parcelable { private int mFlags; private byte mPrn; private double mTimeOffsetInNs; private short mState; private long mReceivedGpsTowInNs; private long mReceivedGpsTowUncertaintyInNs; private double mCn0InDbHz; private double mPseudorangeRateInMetersPerSec; private double mPseudorangeRateUncertaintyInMetersPerSec; private short mAccumulatedDeltaRangeState; private double mAccumulatedDeltaRangeInMeters; private double mAccumulatedDeltaRangeUncertaintyInMeters; private double mPseudorangeInMeters; private double mPseudorangeUncertaintyInMeters; private double mCodePhaseInChips; private double mCodePhaseUncertaintyInChips; private float mCarrierFrequencyInHz; private long mCarrierCycles; private double mCarrierPhase; private double mCarrierPhaseUncertainty; private byte mLossOfLock; private int mBitNumber; private short mTimeFromLastBitInMs; private double mDopplerShiftInHz; private double mDopplerShiftUncertaintyInHz; private byte mMultipathIndicator; private double mSnrInDb; private double mElevationInDeg; private double mElevationUncertaintyInDeg; private double mAzimuthInDeg; private double mAzimuthUncertaintyInDeg; private boolean mUsedInFix; // 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_SNR = (1<<0); private static final int HAS_ELEVATION = (1<<1); private static final int HAS_ELEVATION_UNCERTAINTY = (1<<2); private static final int HAS_AZIMUTH = (1<<3); private static final int HAS_AZIMUTH_UNCERTAINTY = (1<<4); private static final int HAS_PSEUDORANGE = (1<<5); private static final int HAS_PSEUDORANGE_UNCERTAINTY = (1<<6); private static final int HAS_CODE_PHASE = (1<<7); private static final int HAS_CODE_PHASE_UNCERTAINTY = (1<<8); private static final int HAS_CARRIER_FREQUENCY = (1<<9); private static final int HAS_CARRIER_CYCLES = (1<<10); private static final int HAS_CARRIER_PHASE = (1<<11); private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12); private static final int HAS_BIT_NUMBER = (1<<13); private static final int HAS_TIME_FROM_LAST_BIT = (1<<14); private static final int HAS_DOPPLER_SHIFT = (1<<15); private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16); private static final int HAS_USED_IN_FIX = (1<<17); private static final int GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18); /** * The indicator is not available or it is unknown. */ public static final byte LOSS_OF_LOCK_UNKNOWN = 0; /** * The measurement does not present any indication of 'loss of lock'. */ public static final byte LOSS_OF_LOCK_OK = 1; /** * 'Loss of lock' detected between the previous and current observation: cycle slip possible. */ public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; /** * The indicator is not available or it is unknown. */ public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; /** * The measurement has been indicated to use multi-path. */ public static final byte MULTIPATH_INDICATOR_DETECTED = 1; /** * The measurement has been indicated not tu use multi-path. */ public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; /** * The state of GPS receiver the measurement is invalid or unknown. */ public static final short STATE_UNKNOWN = 0; /** * The state of the GPS receiver is ranging code lock. */ public static final short STATE_CODE_LOCK = (1<<0); /** * The state of the GPS receiver is in bit sync. */ public static final short STATE_BIT_SYNC = (1<<1); /** *The state of the GPS receiver is in sub-frame sync. */ public static final short STATE_SUBFRAME_SYNC = (1<<2); /** * The state of the GPS receiver has TOW decoded. */ public static final short STATE_TOW_DECODED = (1<<3); /** * The state of the GPS receiver contains millisecond ambiguity. */ public static final short STATE_MSEC_AMBIGUOUS = (1<<4); /** * All the GPS receiver state flags. */ private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC | STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS; /** * The state of the 'Accumulated Delta Range' is invalid or unknown. */ public static final short ADR_STATE_UNKNOWN = 0; /** * The state of the 'Accumulated Delta Range' is valid. */ public static final short ADR_STATE_VALID = (1<<0); /** * The state of the 'Accumulated Delta Range' has detected a reset. */ public static final short ADR_STATE_RESET = (1<<1); /** * The state of the 'Accumulated Delta Range' has a cycle slip detected. */ public static final short ADR_STATE_CYCLE_SLIP = (1<<2); /** * All the 'Accumulated Delta Range' flags. */ private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP; // End enumerations in sync with gps.h GpsMeasurement() { initialize(); } /** * Sets all contents to the values stored in the provided object. */ public void set(GpsMeasurement measurement) { mFlags = measurement.mFlags; mPrn = measurement.mPrn; mTimeOffsetInNs = measurement.mTimeOffsetInNs; mState = measurement.mState; mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs; mReceivedGpsTowUncertaintyInNs = measurement.mReceivedGpsTowUncertaintyInNs; mCn0InDbHz = measurement.mCn0InDbHz; mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec; mPseudorangeRateUncertaintyInMetersPerSec = measurement.mPseudorangeRateUncertaintyInMetersPerSec; mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState; mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters; mAccumulatedDeltaRangeUncertaintyInMeters = measurement.mAccumulatedDeltaRangeUncertaintyInMeters; mPseudorangeInMeters = measurement.mPseudorangeInMeters; mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters; mCodePhaseInChips = measurement.mCodePhaseInChips; mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips; mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz; mCarrierCycles = measurement.mCarrierCycles; mCarrierPhase = measurement.mCarrierPhase; mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty; mLossOfLock = measurement.mLossOfLock; mBitNumber = measurement.mBitNumber; mTimeFromLastBitInMs = measurement.mTimeFromLastBitInMs; mDopplerShiftInHz = measurement.mDopplerShiftInHz; mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz; mMultipathIndicator = measurement.mMultipathIndicator; mSnrInDb = measurement.mSnrInDb; mElevationInDeg = measurement.mElevationInDeg; mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg; mAzimuthInDeg = measurement.mAzimuthInDeg; mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg; mUsedInFix = measurement.mUsedInFix; } /** * Resets all the contents to its original state. */ public void reset() { initialize(); } /** * Gets the Pseudo-random number (PRN). * Range: [1, 32] */ public byte getPrn() { return mPrn; } /** * Sets the Pseud-random number (PRN). */ public void setPrn(byte value) { mPrn = value; } /** * Gets the time offset at which the measurement was taken in nanoseconds. * The reference receiver's time is specified by {@link GpsClock#getTimeInNs()} and should be * interpreted in the same way as indicated by {@link GpsClock#getType()}. * * The sign of this value is given by the following equation: * measurement time = time_ns + time_offset_ns * * The value provides an individual time-stamp for the measurement, and allows sub-nanosecond * accuracy. */ public double getTimeOffsetInNs() { return mTimeOffsetInNs; } /** * Sets the time offset at which the measurement was taken in nanoseconds. */ public void setTimeOffsetInNs(double value) { mTimeOffsetInNs = value; } /** * Gets per-satellite sync state. * It represents the current sync state for the associated satellite. * * This value helps interpret {@link #getReceivedGpsTowInNs()}. */ public short getState() { return mState; } /** * Sets the sync state. */ public void setState(short value) { mState = value; } /** * Gets a string representation of the 'sync state'. * For internal and logging use only. */ private String getStateString() { if (mState == STATE_UNKNOWN) { return "Unknown"; } StringBuilder builder = new StringBuilder(); if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) { builder.append("CodeLock|"); } if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) { builder.append("BitSync|"); } if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) { builder.append("SubframeSync|"); } if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) { builder.append("TowDecoded|"); } if ((mState & STATE_MSEC_AMBIGUOUS) == STATE_MSEC_AMBIGUOUS) { builder.append("MsecAmbiguous"); } int remainingStates = mState & ~STATE_ALL; if (remainingStates > 0) { builder.append("Other("); builder.append(Integer.toBinaryString(remainingStates)); builder.append(")|"); } builder.deleteCharAt(builder.length() - 1); return builder.toString(); } /** * Gets the received GPS Time-of-Week at the measurement time, in nanoseconds. * The value is relative to the beginning of the current GPS week. * * Given {@link #getState()} of the GPS receiver, the range of this field can be: * Searching : [ 0 ] : {@link #STATE_UNKNOWN} is set * Ranging code lock : [ 0 1 ms ] : {@link #STATE_CODE_LOCK} is set * Bit sync : [ 0 20 ms ] : {@link #STATE_BIT_SYNC} is set * Subframe sync : [ 0 6 ms ] : {@link #STATE_SUBFRAME_SYNC} is set * TOW decoded : [ 0 1 week ] : {@link #STATE_TOW_DECODED} is set */ public long getReceivedGpsTowInNs() { return mReceivedGpsTowInNs; } /** * Sets the received GPS time-of-week in nanoseconds. */ public void setReceivedGpsTowInNs(long value) { mReceivedGpsTowInNs = value; } /** * Gets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds. */ public long getReceivedGpsTowUncertaintyInNs() { return mReceivedGpsTowUncertaintyInNs; } /** * Sets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds. */ public void setReceivedGpsTowUncertaintyInNs(long value) { mReceivedGpsTowUncertaintyInNs = value; } /** * Gets the Carrier-to-noise density in dB-Hz. * Range: [0, 63]. * * The value contains the measured C/N0 for the signal at the antenna input. */ public double getCn0InDbHz() { return mCn0InDbHz; } /** * Sets the carrier-to-noise density in dB-Hz. */ public void setCn0InDbHz(double value) { mCn0InDbHz = value; } /** * Gets the Pseudorange rate at the timestamp in m/s. * The reported value includes {@link #getPseudorangeRateUncertaintyInMetersPerSec()}. * * The correction of a given Pseudorange Rate value includes corrections from receiver and * satellite clock frequency errors. * {@link #isPseudorangeRateCorrected()} identifies the type of value reported. * * A positive 'uncorrected' value indicates that the SV is moving away from the receiver. * The sign of the 'uncorrected' Pseudorange Rate and its relation to the sign of * {@link #getDopplerShiftInHz()} is given by the equation: * pseudorange rate = -k * doppler shift (where k is a constant) */ public double getPseudorangeRateInMetersPerSec() { return mPseudorangeRateInMetersPerSec; } /** * Sets the pseudorange rate at the timestamp in m/s. */ public void setPseudorangeRateInMetersPerSec(double value) { mPseudorangeRateInMetersPerSec = value; } /** * See {@link #getPseudorangeRateInMetersPerSec()} for more details. * * @return {@code true} if {@link #getPseudorangeRateInMetersPerSec()} contains a corrected * value, {@code false} if it contains an uncorrected value. */ public boolean isPseudorangeRateCorrected() { return !isFlagSet(GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE); } /** * Gets the pseudorange's rate uncertainty (1-Sigma) in m/s. * The uncertainty is represented as an absolute (single sided) value. */ public double getPseudorangeRateUncertaintyInMetersPerSec() { return mPseudorangeRateUncertaintyInMetersPerSec; } /** * Sets the pseudorange's rate uncertainty (1-Sigma) in m/s. */ public void setPseudorangeRateUncertaintyInMetersPerSec(double value) { mPseudorangeRateUncertaintyInMetersPerSec = value; } /** * Gets 'Accumulated Delta Range' state. * It indicates whether {@link #getAccumulatedDeltaRangeInMeters()} is reset or there is a * cycle slip (indicating 'loss of lock'). */ public short getAccumulatedDeltaRangeState() { return mAccumulatedDeltaRangeState; } /** * Sets the 'Accumulated Delta Range' state. */ public void setAccumulatedDeltaRangeState(short value) { mAccumulatedDeltaRangeState = value; } /** * Gets a string representation of the 'Accumulated Delta Range state'. * For internal and logging use only. */ private String getAccumulatedDeltaRangeStateString() { if (mAccumulatedDeltaRangeState == ADR_STATE_UNKNOWN) { return "Unknown"; } StringBuilder builder = new StringBuilder(); if ((mAccumulatedDeltaRangeState & ADR_STATE_VALID) == ADR_STATE_VALID) { builder.append("Valid|"); } if ((mAccumulatedDeltaRangeState & ADR_STATE_RESET) == ADR_STATE_RESET) { builder.append("Reset|"); } if ((mAccumulatedDeltaRangeState & ADR_STATE_CYCLE_SLIP) == ADR_STATE_CYCLE_SLIP) { builder.append("CycleSlip|"); } int remainingStates = mAccumulatedDeltaRangeState & ~ADR_ALL; if (remainingStates > 0) { builder.append("Other("); builder.append(Integer.toBinaryString(remainingStates)); builder.append(")|"); } builder.deleteCharAt(builder.length() - 1); return builder.toString(); } /** * Gets the accumulated delta range since the last channel reset, in meters. * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}. * * The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}. * * A positive value indicates that the SV is moving away from the receiver. * The sign of {@link #getAccumulatedDeltaRangeInMeters()} and its relation to the sign of * {@link #getCarrierPhase()} is given by the equation: * accumulated delta range = -k * carrier phase (where k is a constant) */ public double getAccumulatedDeltaRangeInMeters() { return mAccumulatedDeltaRangeInMeters; } /** * Sets the accumulated delta range in meters. */ public void setAccumulatedDeltaRangeInMeters(double value) { mAccumulatedDeltaRangeInMeters = value; } /** * Gets the accumulated delta range's uncertainty (1-Sigma) in meters. * The uncertainty is represented as an absolute (single sided) value. * * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}. */ public double getAccumulatedDeltaRangeUncertaintyInMeters() { return mAccumulatedDeltaRangeUncertaintyInMeters; } /** * Sets the accumulated delta range's uncertainty (1-sigma) in meters. * * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}. */ public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) { mAccumulatedDeltaRangeUncertaintyInMeters = value; } /** * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise. */ public boolean hasPseudorangeInMeters() { return isFlagSet(HAS_PSEUDORANGE); } /** * Gets the best derived pseudorange by the chipset, in meters. * The reported pseudorange includes {@link #getPseudorangeUncertaintyInMeters()}. * * The value is only available if {@link #hasPseudorangeInMeters()} is true. */ public double getPseudorangeInMeters() { return mPseudorangeInMeters; } /** * Sets the Pseudo-range in meters. */ public void setPseudorangeInMeters(double value) { setFlag(HAS_PSEUDORANGE); mPseudorangeInMeters = value; } /** * Resets the Pseudo-range in meters. */ public void resetPseudorangeInMeters() { resetFlag(HAS_PSEUDORANGE); mPseudorangeInMeters = Double.NaN; } /** * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise. */ public boolean hasPseudorangeUncertaintyInMeters() { return isFlagSet(HAS_PSEUDORANGE_UNCERTAINTY); } /** * Gets the pseudorange's uncertainty (1-Sigma) in meters. * The value contains the 'pseudorange' and 'clock' uncertainty in it. * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasPseudorangeUncertaintyInMeters()} is true. */ public double getPseudorangeUncertaintyInMeters() { return mPseudorangeUncertaintyInMeters; } /** * Sets the pseudo-range's uncertainty (1-Sigma) in meters. */ public void setPseudorangeUncertaintyInMeters(double value) { setFlag(HAS_PSEUDORANGE_UNCERTAINTY); mPseudorangeUncertaintyInMeters = value; } /** * Resets the pseudo-range's uncertainty (1-Sigma) in meters. */ public void resetPseudorangeUncertaintyInMeters() { resetFlag(HAS_PSEUDORANGE_UNCERTAINTY); mPseudorangeUncertaintyInMeters = Double.NaN; } /** * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise. */ public boolean hasCodePhaseInChips() { return isFlagSet(HAS_CODE_PHASE); } /** * Gets the fraction of the current C/A code cycle. * Range: [0, 1023] * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}. * The reported code-phase includes {@link #getCodePhaseUncertaintyInChips()}. * * The value is only available if {@link #hasCodePhaseInChips()} is true. */ public double getCodePhaseInChips() { return mCodePhaseInChips; } /** * Sets the Code-phase in chips. */ public void setCodePhaseInChips(double value) { setFlag(HAS_CODE_PHASE); mCodePhaseInChips = value; } /** * Resets the Code-phase in chips. */ public void resetCodePhaseInChips() { resetFlag(HAS_CODE_PHASE); mCodePhaseInChips = Double.NaN; } /** * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise. */ public boolean hasCodePhaseUncertaintyInChips() { return isFlagSet(HAS_CODE_PHASE_UNCERTAINTY); } /** * Gets the code-phase's uncertainty (1-Sigma) as a fraction of chips. * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasCodePhaseUncertaintyInChips()} is true. */ public double getCodePhaseUncertaintyInChips() { return mCodePhaseUncertaintyInChips; } /** * Sets the Code-phase's uncertainty (1-Sigma) in fractions of chips. */ public void setCodePhaseUncertaintyInChips(double value) { setFlag(HAS_CODE_PHASE_UNCERTAINTY); mCodePhaseUncertaintyInChips = value; } /** * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips. */ public void resetCodePhaseUncertaintyInChips() { resetFlag(HAS_CODE_PHASE_UNCERTAINTY); mCodePhaseUncertaintyInChips = Double.NaN; } /** * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise. */ public boolean hasCarrierFrequencyInHz() { return isFlagSet(HAS_CARRIER_FREQUENCY); } /** * Gets the carrier frequency at which codes and messages are modulated, it can be L1 or L2. * If the field is not set, the carrier frequency corresponds to L1. * * The value is only available if {@link #hasCarrierFrequencyInHz()} is true. */ public float getCarrierFrequencyInHz() { return mCarrierFrequencyInHz; } /** * Sets the Carrier frequency (L1 or L2) in Hz. */ public void setCarrierFrequencyInHz(float carrierFrequencyInHz) { setFlag(HAS_CARRIER_FREQUENCY); mCarrierFrequencyInHz = carrierFrequencyInHz; } /** * Resets the Carrier frequency (L1 or L2) in Hz. */ public void resetCarrierFrequencyInHz() { resetFlag(HAS_CARRIER_FREQUENCY); mCarrierFrequencyInHz = Float.NaN; } /** * Returns true if {@link #getCarrierCycles()} is available, false otherwise. */ public boolean hasCarrierCycles() { return isFlagSet(HAS_CARRIER_CYCLES); } /** * The number of full carrier cycles between the satellite and the receiver. * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}. * * The value is only available if {@link #hasCarrierCycles()} is true. */ public long getCarrierCycles() { return mCarrierCycles; } /** * Sets the number of full carrier cycles between the satellite and the receiver. */ public void setCarrierCycles(long value) { setFlag(HAS_CARRIER_CYCLES); mCarrierCycles = value; } /** * Resets the number of full carrier cycles between the satellite and the receiver. */ public void resetCarrierCycles() { resetFlag(HAS_CARRIER_CYCLES); mCarrierCycles = Long.MIN_VALUE; } /** * Returns true if {@link #getCarrierPhase()} is available, false otherwise. */ public boolean hasCarrierPhase() { return isFlagSet(HAS_CARRIER_PHASE); } /** * Gets the RF phase detected by the receiver. * Range: [0.0, 1.0]. * This is usually the fractional part of the complete carrier phase measurement. * * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}. * The reported carrier-phase includes {@link #getCarrierPhaseUncertainty()}. * * The value is only available if {@link #hasCarrierPhase()} is true. */ public double getCarrierPhase() { return mCarrierPhase; } /** * Sets the RF phase detected by the receiver. */ public void setCarrierPhase(double value) { setFlag(HAS_CARRIER_PHASE); mCarrierPhase = value; } /** * Resets the RF phase detected by the receiver. */ public void resetCarrierPhase() { resetFlag(HAS_CARRIER_PHASE); mCarrierPhase = Double.NaN; } /** * Returns true if {@link #getCarrierPhaseUncertainty()} is available, false otherwise. */ public boolean hasCarrierPhaseUncertainty() { return isFlagSet(HAS_CARRIER_PHASE_UNCERTAINTY); } /** * Gets the carrier-phase's uncertainty (1-Sigma). * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasCarrierPhaseUncertainty()} is true. */ public double getCarrierPhaseUncertainty() { return mCarrierPhaseUncertainty; } /** * Sets the Carrier-phase's uncertainty (1-Sigma) in cycles. */ public void setCarrierPhaseUncertainty(double value) { setFlag(HAS_CARRIER_PHASE_UNCERTAINTY); mCarrierPhaseUncertainty = value; } /** * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles. */ public void resetCarrierPhaseUncertainty() { resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY); mCarrierPhaseUncertainty = Double.NaN; } /** * Gets a value indicating the 'loss of lock' state of the event. */ public byte getLossOfLock() { return mLossOfLock; } /** * Sets the 'loss of lock' status. */ public void setLossOfLock(byte value) { mLossOfLock = value; } /** * Gets a string representation of the 'loss of lock'. * For internal and logging use only. */ private String getLossOfLockString() { switch (mLossOfLock) { case LOSS_OF_LOCK_UNKNOWN: return "Unknown"; case LOSS_OF_LOCK_OK: return "Ok"; case LOSS_OF_LOCK_CYCLE_SLIP: return "CycleSlip"; default: return "<Invalid:" + mLossOfLock + ">"; } } /** * Returns true if {@link #getBitNumber()} is available, false otherwise. */ public boolean hasBitNumber() { return isFlagSet(HAS_BIT_NUMBER); } /** * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week). * * The value is only available if {@link #hasBitNumber()} is true. */ public int getBitNumber() { return mBitNumber; } /** * Sets the bit number within the broadcast frame. */ public void setBitNumber(int bitNumber) { setFlag(HAS_BIT_NUMBER); mBitNumber = bitNumber; } /** * Resets the bit number within the broadcast frame. */ public void resetBitNumber() { resetFlag(HAS_BIT_NUMBER); mBitNumber = Integer.MIN_VALUE; } /** * Returns true if {@link #getTimeFromLastBitInMs()} is available, false otherwise. */ public boolean hasTimeFromLastBitInMs() { return isFlagSet(HAS_TIME_FROM_LAST_BIT); } /** * Gets the elapsed time since the last received bit in milliseconds. * Range: [0, 20]. * * The value is only available if {@link #hasTimeFromLastBitInMs()} is true. */ public short getTimeFromLastBitInMs() { return mTimeFromLastBitInMs; } /** * Sets the elapsed time since the last received bit in milliseconds. */ public void setTimeFromLastBitInMs(short value) { setFlag(HAS_TIME_FROM_LAST_BIT); mTimeFromLastBitInMs = value; } /** * Resets the elapsed time since the last received bit in milliseconds. */ public void resetTimeFromLastBitInMs() { resetFlag(HAS_TIME_FROM_LAST_BIT); mTimeFromLastBitInMs = Short.MIN_VALUE; } /** * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise. */ public boolean hasDopplerShiftInHz() { return isFlagSet(HAS_DOPPLER_SHIFT); } /** * Gets the Doppler Shift in Hz. * A positive value indicates that the SV is moving toward the receiver. * * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}. * The reported doppler shift includes {@link #getDopplerShiftUncertaintyInHz()}. * * The value is only available if {@link #hasDopplerShiftInHz()} is true. */ public double getDopplerShiftInHz() { return mDopplerShiftInHz; } /** * Sets the Doppler shift in Hz. */ public void setDopplerShiftInHz(double value) { setFlag(HAS_DOPPLER_SHIFT); mDopplerShiftInHz = value; } /** * Resets the Doppler shift in Hz. */ public void resetDopplerShiftInHz() { resetFlag(HAS_DOPPLER_SHIFT); mDopplerShiftInHz = Double.NaN; } /** * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise. */ public boolean hasDopplerShiftUncertaintyInHz() { return isFlagSet(HAS_DOPPLER_SHIFT_UNCERTAINTY); } /** * Gets the Doppler's Shift uncertainty (1-Sigma) in Hz. * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasDopplerShiftUncertaintyInHz()} is true. */ public double getDopplerShiftUncertaintyInHz() { return mDopplerShiftUncertaintyInHz; } /** * Sets the Doppler's shift uncertainty (1-Sigma) in Hz. */ public void setDopplerShiftUncertaintyInHz(double value) { setFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY); mDopplerShiftUncertaintyInHz = value; } /** * Resets the Doppler's shift uncertainty (1-Sigma) in Hz. */ public void resetDopplerShiftUncertaintyInHz() { resetFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY); mDopplerShiftUncertaintyInHz = Double.NaN; } /** * Gets a value indicating the 'multipath' state of the event. */ public byte getMultipathIndicator() { return mMultipathIndicator; } /** * Sets the 'multi-path' indicator. */ public void setMultipathIndicator(byte value) { mMultipathIndicator = value; } /** * Gets a string representation of the 'multi-path indicator'. * For internal and logging use only. */ private String getMultipathIndicatorString() { switch(mMultipathIndicator) { case MULTIPATH_INDICATOR_UNKNOWN: return "Unknown"; case MULTIPATH_INDICATOR_DETECTED: return "Detected"; case MULTIPATH_INDICATOR_NOT_USED: return "NotUsed"; default: return "<Invalid:" + mMultipathIndicator + ">"; } } /** * Returns true if {@link #getSnrInDb()} is available, false otherwise. */ public boolean hasSnrInDb() { return isFlagSet(HAS_SNR); } /** * Gets the Signal-to-Noise ratio (SNR) in dB. * * The value is only available if {@link #hasSnrInDb()} is true. */ public double getSnrInDb() { return mSnrInDb; } /** * Sets the Signal-to-noise ratio (SNR) in dB. */ public void setSnrInDb(double snrInDb) { setFlag(HAS_SNR); mSnrInDb = snrInDb; } /** * Resets the Signal-to-noise ratio (SNR) in dB. */ public void resetSnrInDb() { resetFlag(HAS_SNR); mSnrInDb = Double.NaN; } /** * Returns true if {@link #getElevationInDeg()} is available, false otherwise. */ public boolean hasElevationInDeg() { return isFlagSet(HAS_ELEVATION); } /** * Gets the Elevation in degrees. * Range: [-90, 90] * The reported elevation includes {@link #getElevationUncertaintyInDeg()}. * * The value is only available if {@link #hasElevationInDeg()} is true. */ public double getElevationInDeg() { return mElevationInDeg; } /** * Sets the Elevation in degrees. */ public void setElevationInDeg(double elevationInDeg) { setFlag(HAS_ELEVATION); mElevationInDeg = elevationInDeg; } /** * Resets the Elevation in degrees. */ public void resetElevationInDeg() { resetFlag(HAS_ELEVATION); mElevationInDeg = Double.NaN; } /** * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise. */ public boolean hasElevationUncertaintyInDeg() { return isFlagSet(HAS_ELEVATION_UNCERTAINTY); } /** * Gets the elevation's uncertainty (1-Sigma) in degrees. * Range: [0, 90] * * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasElevationUncertaintyInDeg()} is true. */ public double getElevationUncertaintyInDeg() { return mElevationUncertaintyInDeg; } /** * Sets the elevation's uncertainty (1-Sigma) in degrees. */ public void setElevationUncertaintyInDeg(double value) { setFlag(HAS_ELEVATION_UNCERTAINTY); mElevationUncertaintyInDeg = value; } /** * Resets the elevation's uncertainty (1-Sigma) in degrees. */ public void resetElevationUncertaintyInDeg() { resetFlag(HAS_ELEVATION_UNCERTAINTY); mElevationUncertaintyInDeg = Double.NaN; } /** * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise. */ public boolean hasAzimuthInDeg() { return isFlagSet(HAS_AZIMUTH); } /** * Gets the azimuth in degrees. * Range: [0, 360). * * The reported azimuth includes {@link #getAzimuthUncertaintyInDeg()}. * * The value is only available if {@link #hasAzimuthInDeg()} is true. */ public double getAzimuthInDeg() { return mAzimuthInDeg; } /** * Sets the Azimuth in degrees. */ public void setAzimuthInDeg(double value) { setFlag(HAS_AZIMUTH); mAzimuthInDeg = value; } /** * Resets the Azimuth in degrees. */ public void resetAzimuthInDeg() { resetFlag(HAS_AZIMUTH); mAzimuthInDeg = Double.NaN; } /** * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise. */ public boolean hasAzimuthUncertaintyInDeg() { return isFlagSet(HAS_AZIMUTH_UNCERTAINTY); } /** * Gets the azimuth's uncertainty (1-Sigma) in degrees. * Range: [0, 180]. * * The uncertainty is represented as an absolute (single sided) value. * * The value is only available if {@link #hasAzimuthUncertaintyInDeg()} is true. */ public double getAzimuthUncertaintyInDeg() { return mAzimuthUncertaintyInDeg; } /** * Sets the Azimuth's uncertainty (1-Sigma) in degrees. */ public void setAzimuthUncertaintyInDeg(double value) { setFlag(HAS_AZIMUTH_UNCERTAINTY); mAzimuthUncertaintyInDeg = value; } /** * Resets the Azimuth's uncertainty (1-Sigma) in degrees. */ public void resetAzimuthUncertaintyInDeg() { resetFlag(HAS_AZIMUTH_UNCERTAINTY); mAzimuthUncertaintyInDeg = Double.NaN; } /** * Gets a flag indicating whether the GPS represented by the measurement was used for computing * the most recent fix. * * @return A non-null value if the data is available, null otherwise. */ public boolean isUsedInFix() { return mUsedInFix; } /** * Sets the Used-in-Fix flag. */ public void setUsedInFix(boolean value) { mUsedInFix = value; } public static final Creator<GpsMeasurement> CREATOR = new Creator<GpsMeasurement>() { @Override public GpsMeasurement createFromParcel(Parcel parcel) { GpsMeasurement gpsMeasurement = new GpsMeasurement(); gpsMeasurement.mFlags = parcel.readInt(); gpsMeasurement.mPrn = parcel.readByte(); gpsMeasurement.mTimeOffsetInNs = parcel.readDouble(); gpsMeasurement.mState = (short) parcel.readInt(); gpsMeasurement.mReceivedGpsTowInNs = parcel.readLong(); gpsMeasurement.mReceivedGpsTowUncertaintyInNs = parcel.readLong(); gpsMeasurement.mCn0InDbHz = parcel.readDouble(); gpsMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble(); gpsMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble(); gpsMeasurement.mAccumulatedDeltaRangeState = (short) parcel.readInt(); gpsMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble(); gpsMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble(); gpsMeasurement.mPseudorangeInMeters = parcel.readDouble(); gpsMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble(); gpsMeasurement.mCodePhaseInChips = parcel.readDouble(); gpsMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble(); gpsMeasurement.mCarrierFrequencyInHz = parcel.readFloat(); gpsMeasurement.mCarrierCycles = parcel.readLong(); gpsMeasurement.mCarrierPhase = parcel.readDouble(); gpsMeasurement.mCarrierPhaseUncertainty = parcel.readDouble(); gpsMeasurement.mLossOfLock = parcel.readByte(); gpsMeasurement.mBitNumber = parcel.readInt(); gpsMeasurement.mTimeFromLastBitInMs = (short) parcel.readInt(); gpsMeasurement.mDopplerShiftInHz = parcel.readDouble(); gpsMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble(); gpsMeasurement.mMultipathIndicator = parcel.readByte(); gpsMeasurement.mSnrInDb = parcel.readDouble(); gpsMeasurement.mElevationInDeg = parcel.readDouble(); gpsMeasurement.mElevationUncertaintyInDeg = parcel.readDouble(); gpsMeasurement.mAzimuthInDeg = parcel.readDouble(); gpsMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble(); gpsMeasurement.mUsedInFix = parcel.readInt() != 0; return gpsMeasurement; } @Override public GpsMeasurement[] newArray(int i) { return new GpsMeasurement[i]; } }; public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mFlags); parcel.writeByte(mPrn); parcel.writeDouble(mTimeOffsetInNs); parcel.writeInt(mState); parcel.writeLong(mReceivedGpsTowInNs); parcel.writeLong(mReceivedGpsTowUncertaintyInNs); parcel.writeDouble(mCn0InDbHz); parcel.writeDouble(mPseudorangeRateInMetersPerSec); parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec); parcel.writeInt(mAccumulatedDeltaRangeState); parcel.writeDouble(mAccumulatedDeltaRangeInMeters); parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters); parcel.writeDouble(mPseudorangeInMeters); parcel.writeDouble(mPseudorangeUncertaintyInMeters); parcel.writeDouble(mCodePhaseInChips); parcel.writeDouble(mCodePhaseUncertaintyInChips); parcel.writeFloat(mCarrierFrequencyInHz); parcel.writeLong(mCarrierCycles); parcel.writeDouble(mCarrierPhase); parcel.writeDouble(mCarrierPhaseUncertainty); parcel.writeByte(mLossOfLock); parcel.writeInt(mBitNumber); parcel.writeInt(mTimeFromLastBitInMs); parcel.writeDouble(mDopplerShiftInHz); parcel.writeDouble(mDopplerShiftUncertaintyInHz); parcel.writeByte(mMultipathIndicator); parcel.writeDouble(mSnrInDb); parcel.writeDouble(mElevationInDeg); parcel.writeDouble(mElevationUncertaintyInDeg); parcel.writeDouble(mAzimuthInDeg); parcel.writeDouble(mAzimuthUncertaintyInDeg); parcel.writeInt(mUsedInFix ? 1 : 0); } @Override public int describeContents() { return 0; } @Override public String toString() { final String format = " %-29s = %s\n"; final String formatWithUncertainty = " %-29s = %-25s %-40s = %s\n"; StringBuilder builder = new StringBuilder("GpsMeasurement:\n"); builder.append(String.format(format, "Prn", mPrn)); builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs)); builder.append(String.format(format, "State", getStateString())); builder.append(String.format( formatWithUncertainty, "ReceivedGpsTowInNs", mReceivedGpsTowInNs, "ReceivedGpsTowUncertaintyInNs", mReceivedGpsTowUncertaintyInNs)); builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz)); builder.append(String.format( formatWithUncertainty, "PseudorangeRateInMetersPerSec", mPseudorangeRateInMetersPerSec, "PseudorangeRateUncertaintyInMetersPerSec", mPseudorangeRateUncertaintyInMetersPerSec)); builder.append(String.format( format, "PseudorangeRateIsCorrected", isPseudorangeRateCorrected())); builder.append(String.format( format, "AccumulatedDeltaRangeState", getAccumulatedDeltaRangeStateString())); builder.append(String.format( formatWithUncertainty, "AccumulatedDeltaRangeInMeters", mAccumulatedDeltaRangeInMeters, "AccumulatedDeltaRangeUncertaintyInMeters", mAccumulatedDeltaRangeUncertaintyInMeters)); builder.append(String.format( formatWithUncertainty, "PseudorangeInMeters", hasPseudorangeInMeters() ? mPseudorangeInMeters : null, "PseudorangeUncertaintyInMeters", hasPseudorangeUncertaintyInMeters() ? mPseudorangeUncertaintyInMeters : null)); builder.append(String.format( formatWithUncertainty, "CodePhaseInChips", hasCodePhaseInChips() ? mCodePhaseInChips : null, "CodePhaseUncertaintyInChips", hasCodePhaseUncertaintyInChips() ? mCodePhaseUncertaintyInChips : null)); builder.append(String.format( format, "CarrierFrequencyInHz", hasCarrierFrequencyInHz() ? mCarrierFrequencyInHz : null)); builder.append(String.format( format, "CarrierCycles", hasCarrierCycles() ? mCarrierCycles : null)); builder.append(String.format( formatWithUncertainty, "CarrierPhase", hasCarrierPhase() ? mCarrierPhase : null, "CarrierPhaseUncertainty", hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null)); builder.append(String.format(format, "LossOfLock", getLossOfLockString())); builder.append(String.format( format, "BitNumber", hasBitNumber() ? mBitNumber : null)); builder.append(String.format( format, "TimeFromLastBitInMs", hasTimeFromLastBitInMs() ? mTimeFromLastBitInMs : null)); builder.append(String.format( formatWithUncertainty, "DopplerShiftInHz", hasDopplerShiftInHz() ? mDopplerShiftInHz : null, "DopplerShiftUncertaintyInHz", hasDopplerShiftUncertaintyInHz() ? mDopplerShiftUncertaintyInHz : null)); builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString())); builder.append(String.format( format, "SnrInDb", hasSnrInDb() ? mSnrInDb : null)); builder.append(String.format( formatWithUncertainty, "ElevationInDeg", hasElevationInDeg() ? mElevationInDeg : null, "ElevationUncertaintyInDeg", hasElevationUncertaintyInDeg() ? mElevationUncertaintyInDeg : null)); builder.append(String.format( formatWithUncertainty, "AzimuthInDeg", hasAzimuthInDeg() ? mAzimuthInDeg : null, "AzimuthUncertaintyInDeg", hasAzimuthUncertaintyInDeg() ? mAzimuthUncertaintyInDeg : null)); builder.append(String.format(format, "UsedInFix", mUsedInFix)); return builder.toString(); } private void initialize() { mFlags = HAS_NO_FLAGS; setPrn(Byte.MIN_VALUE); setTimeOffsetInNs(Long.MIN_VALUE); setState(STATE_UNKNOWN); setReceivedGpsTowInNs(Long.MIN_VALUE); setReceivedGpsTowUncertaintyInNs(Long.MAX_VALUE); setCn0InDbHz(Double.MIN_VALUE); setPseudorangeRateInMetersPerSec(Double.MIN_VALUE); setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE); setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN); setAccumulatedDeltaRangeInMeters(Double.MIN_VALUE); setAccumulatedDeltaRangeUncertaintyInMeters(Double.MIN_VALUE); resetPseudorangeInMeters(); resetPseudorangeUncertaintyInMeters(); resetCodePhaseInChips(); resetCodePhaseUncertaintyInChips(); resetCarrierFrequencyInHz(); resetCarrierCycles(); resetCarrierPhase(); resetCarrierPhaseUncertainty(); setLossOfLock(LOSS_OF_LOCK_UNKNOWN); resetBitNumber(); resetTimeFromLastBitInMs(); resetDopplerShiftInHz(); resetDopplerShiftUncertaintyInHz(); setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN); resetSnrInDb(); resetElevationInDeg(); resetElevationUncertaintyInDeg(); resetAzimuthInDeg(); resetAzimuthUncertaintyInDeg(); setUsedInFix(false); } private void setFlag(int flag) { mFlags |= flag; } private void resetFlag(int flag) { mFlags &= ~flag; } private boolean isFlagSet(int flag) { return (mFlags & flag) == flag; } }