| /* |
| * 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.annotation.IntDef; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * A class representing a GNSS satellite measurement, containing raw and computed information. |
| */ |
| public final class GnssMeasurement implements Parcelable { |
| private int mFlags; |
| private int mSvid; |
| private int mConstellationType; |
| private double mTimeOffsetNanos; |
| private int mState; |
| private long mReceivedSvTimeNanos; |
| private long mReceivedSvTimeUncertaintyNanos; |
| private double mCn0DbHz; |
| private double mPseudorangeRateMetersPerSecond; |
| private double mPseudorangeRateUncertaintyMetersPerSecond; |
| private int mAccumulatedDeltaRangeState; |
| private double mAccumulatedDeltaRangeMeters; |
| private double mAccumulatedDeltaRangeUncertaintyMeters; |
| private float mCarrierFrequencyHz; |
| private long mCarrierCycles; |
| private double mCarrierPhase; |
| private double mCarrierPhaseUncertainty; |
| private int mMultipathIndicator; |
| private double mSnrInDb; |
| private double mAgcLevelDb; |
| |
| // 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_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_AUTOMATIC_GAIN_CONTROL = (1<<13); |
| |
| /** |
| * The status of the multipath indicator. |
| * @hide |
| */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED, |
| MULTIPATH_INDICATOR_NOT_DETECTED}) |
| public @interface MultipathIndicator {} |
| |
| /** |
| * The indicator is not available or the presence or absence of multipath is unknown. |
| */ |
| public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; |
| |
| /** |
| * The measurement shows signs of multi-path. |
| */ |
| public static final int MULTIPATH_INDICATOR_DETECTED = 1; |
| |
| /** |
| * The measurement shows no signs of multi-path. |
| */ |
| public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; |
| |
| /** This GNSS measurement's tracking state is invalid or unknown. */ |
| public static final int STATE_UNKNOWN = 0; |
| /** This GNSS measurement's tracking state has code lock. */ |
| public static final int STATE_CODE_LOCK = (1<<0); |
| /** This GNSS measurement's tracking state has bit sync. */ |
| public static final int STATE_BIT_SYNC = (1<<1); |
| /** This GNSS measurement's tracking state has sub-frame sync. */ |
| public static final int STATE_SUBFRAME_SYNC = (1<<2); |
| /** This GNSS measurement's tracking state has time-of-week decoded. */ |
| public static final int STATE_TOW_DECODED = (1<<3); |
| /** This GNSS measurement's tracking state contains millisecond ambiguity. */ |
| public static final int STATE_MSEC_AMBIGUOUS = (1<<4); |
| /** This GNSS measurement's tracking state has symbol sync. */ |
| public static final int STATE_SYMBOL_SYNC = (1<<5); |
| /** This Glonass measurement's tracking state has string sync. */ |
| public static final int STATE_GLO_STRING_SYNC = (1<<6); |
| /** This Glonass measurement's tracking state has time-of-day decoded. */ |
| public static final int STATE_GLO_TOD_DECODED = (1<<7); |
| /** This Beidou measurement's tracking state has D2 bit sync. */ |
| public static final int STATE_BDS_D2_BIT_SYNC = (1<<8); |
| /** This Beidou measurement's tracking state has D2 sub-frame sync. */ |
| public static final int STATE_BDS_D2_SUBFRAME_SYNC = (1<<9); |
| /** This Galileo measurement's tracking state has E1B/C code lock. */ |
| public static final int STATE_GAL_E1BC_CODE_LOCK = (1<<10); |
| /** This Galileo measurement's tracking state has E1C secondary code lock. */ |
| public static final int STATE_GAL_E1C_2ND_CODE_LOCK = (1<<11); |
| /** This Galileo measurement's tracking state has E1B page sync. */ |
| public static final int STATE_GAL_E1B_PAGE_SYNC = (1<<12); |
| /** This SBAS measurement's tracking state has whole second level sync. */ |
| public static final int STATE_SBAS_SYNC = (1<<13); |
| /** |
| * This GNSS measurement's tracking state has time-of-week known, possibly not decoded |
| * over the air but has been determined from other sources. If TOW decoded is set then TOW Known |
| * will also be set. |
| * @hide |
| */ |
| public static final int STATE_TOW_KNOWN = (1<<14); |
| /** |
| * This Glonass measurement's tracking state has time-of-day known, possibly not decoded |
| * over the air but has been determined from other sources. If TOD decoded is set then TOD Known |
| * will also be set. |
| * @hide |
| */ |
| public static final int STATE_GLO_TOD_KNOWN = (1<<15); |
| |
| /** |
| * All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any |
| * individual measurement.) |
| */ |
| private static final int STATE_ALL = 0x3fff; // 2 bits + 4 bits + 4 bits + 4 bits = 14 bits |
| |
| /** |
| * The state of the 'Accumulated Delta Range' is invalid or unknown. |
| */ |
| public static final int ADR_STATE_UNKNOWN = 0; |
| |
| /** |
| * The state of the 'Accumulated Delta Range' is valid. |
| */ |
| public static final int ADR_STATE_VALID = (1<<0); |
| |
| /** |
| * The state of the 'Accumulated Delta Range' has detected a reset. |
| */ |
| public static final int ADR_STATE_RESET = (1<<1); |
| |
| /** |
| * The state of the 'Accumulated Delta Range' has a cycle slip detected. |
| */ |
| public static final int ADR_STATE_CYCLE_SLIP = (1<<2); |
| |
| /** |
| * All the 'Accumulated Delta Range' flags. |
| */ |
| private static final int ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP; |
| |
| // End enumerations in sync with gps.h |
| |
| /** |
| * @hide |
| */ |
| @TestApi |
| public GnssMeasurement() { |
| initialize(); |
| } |
| |
| /** |
| * Sets all contents to the values stored in the provided object. |
| * @hide |
| */ |
| @TestApi |
| public void set(GnssMeasurement measurement) { |
| mFlags = measurement.mFlags; |
| mSvid = measurement.mSvid; |
| mConstellationType = measurement.mConstellationType; |
| mTimeOffsetNanos = measurement.mTimeOffsetNanos; |
| mState = measurement.mState; |
| mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos; |
| mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos; |
| mCn0DbHz = measurement.mCn0DbHz; |
| mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond; |
| mPseudorangeRateUncertaintyMetersPerSecond = |
| measurement.mPseudorangeRateUncertaintyMetersPerSecond; |
| mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState; |
| mAccumulatedDeltaRangeMeters = measurement.mAccumulatedDeltaRangeMeters; |
| mAccumulatedDeltaRangeUncertaintyMeters = |
| measurement.mAccumulatedDeltaRangeUncertaintyMeters; |
| mCarrierFrequencyHz = measurement.mCarrierFrequencyHz; |
| mCarrierCycles = measurement.mCarrierCycles; |
| mCarrierPhase = measurement.mCarrierPhase; |
| mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty; |
| mMultipathIndicator = measurement.mMultipathIndicator; |
| mSnrInDb = measurement.mSnrInDb; |
| mAgcLevelDb = measurement.mAgcLevelDb; |
| } |
| |
| /** |
| * Resets all the contents to its original state. |
| * @hide |
| */ |
| @TestApi |
| public void reset() { |
| initialize(); |
| } |
| |
| /** |
| * Gets the satellite ID. |
| * |
| * <p>Interpretation depends on {@link #getConstellationType()}. |
| * See {@link GnssStatus#getSvid(int)}. |
| */ |
| public int getSvid() { |
| return mSvid; |
| } |
| |
| /** |
| * Sets the Satellite ID. |
| * @hide |
| */ |
| @TestApi |
| public void setSvid(int value) { |
| mSvid = value; |
| } |
| |
| /** |
| * Gets the constellation type. |
| * |
| * <p>The return value is one of those constants with {@code CONSTELLATION_} prefix in |
| * {@link GnssStatus}. |
| */ |
| @GnssStatus.ConstellationType |
| public int getConstellationType() { |
| return mConstellationType; |
| } |
| |
| /** |
| * Sets the constellation type. |
| * @hide |
| */ |
| @TestApi |
| public void setConstellationType(@GnssStatus.ConstellationType int value) { |
| mConstellationType = value; |
| } |
| |
| /** |
| * Gets the time offset at which the measurement was taken in nanoseconds. |
| * |
| * <p>The reference receiver's time from which this is offset is specified by |
| * {@link GnssClock#getTimeNanos()}. |
| * |
| * <p>The sign of this value is given by the following equation: |
| * <pre> |
| * measurement time = TimeNanos + TimeOffsetNanos</pre> |
| * |
| * <p>The value provides an individual time-stamp for the measurement, and allows sub-nanosecond |
| * accuracy. |
| */ |
| public double getTimeOffsetNanos() { |
| return mTimeOffsetNanos; |
| } |
| |
| /** |
| * Sets the time offset at which the measurement was taken in nanoseconds. |
| * @hide |
| */ |
| @TestApi |
| public void setTimeOffsetNanos(double value) { |
| mTimeOffsetNanos = value; |
| } |
| |
| /** |
| * Gets per-satellite sync state. |
| * |
| * <p>It represents the current sync state for the associated satellite. |
| * |
| * <p>This value helps interpret {@link #getReceivedSvTimeNanos()}. |
| */ |
| public int getState() { |
| return mState; |
| } |
| |
| /** |
| * Sets the sync state. |
| * @hide |
| */ |
| @TestApi |
| public void setState(int value) { |
| mState = value; |
| } |
| |
| /** |
| * Gets a string representation of the 'sync state'. |
| * |
| * <p>For internal and logging use only. |
| */ |
| private String getStateString() { |
| if (mState == STATE_UNKNOWN) { |
| return "Unknown"; |
| } |
| |
| StringBuilder builder = new StringBuilder(); |
| if ((mState & STATE_CODE_LOCK) != 0) { |
| builder.append("CodeLock|"); |
| } |
| if ((mState & STATE_BIT_SYNC) != 0) { |
| builder.append("BitSync|"); |
| } |
| if ((mState & STATE_SUBFRAME_SYNC) != 0) { |
| builder.append("SubframeSync|"); |
| } |
| if ((mState & STATE_TOW_DECODED) != 0) { |
| builder.append("TowDecoded|"); |
| } |
| if ((mState & STATE_TOW_KNOWN) != 0) { |
| builder.append("TowKnown|"); |
| } |
| if ((mState & STATE_MSEC_AMBIGUOUS) != 0) { |
| builder.append("MsecAmbiguous|"); |
| } |
| if ((mState & STATE_SYMBOL_SYNC) != 0) { |
| builder.append("SymbolSync|"); |
| } |
| if ((mState & STATE_GLO_STRING_SYNC) != 0) { |
| builder.append("GloStringSync|"); |
| } |
| if ((mState & STATE_GLO_TOD_DECODED) != 0) { |
| builder.append("GloTodDecoded|"); |
| } |
| if ((mState & STATE_GLO_TOD_KNOWN) != 0) { |
| builder.append("GloTodKnown|"); |
| } |
| if ((mState & STATE_BDS_D2_BIT_SYNC) != 0) { |
| builder.append("BdsD2BitSync|"); |
| } |
| if ((mState & STATE_BDS_D2_SUBFRAME_SYNC) != 0) { |
| builder.append("BdsD2SubframeSync|"); |
| } |
| if ((mState & STATE_GAL_E1BC_CODE_LOCK) != 0) { |
| builder.append("GalE1bcCodeLock|"); |
| } |
| if ((mState & STATE_GAL_E1C_2ND_CODE_LOCK) != 0) { |
| builder.append("E1c2ndCodeLock|"); |
| } |
| if ((mState & STATE_GAL_E1B_PAGE_SYNC) != 0) { |
| builder.append("GalE1bPageSync|"); |
| } |
| if ((mState & STATE_SBAS_SYNC) != 0) { |
| builder.append("SbasSync|"); |
| } |
| |
| int remainingStates = mState & ~STATE_ALL; |
| if (remainingStates > 0) { |
| builder.append("Other("); |
| builder.append(Integer.toBinaryString(remainingStates)); |
| builder.append(")|"); |
| } |
| builder.setLength(builder.length() - 1); |
| return builder.toString(); |
| } |
| |
| /** |
| * Gets the received GNSS satellite time, at the measurement time, in nanoseconds. |
| * |
| * <p>For GPS & QZSS, this is: |
| * <ul> |
| * <li>Received GPS Time-of-Week at the measurement time, in nanoseconds.</li> |
| * <li>The value is relative to the beginning of the current GPS week.</li> |
| * </ul> |
| * |
| * <p>Given the highest sync state that can be achieved, per each satellite, valid range |
| * for this field can be: |
| * <pre> |
| * Searching : [ 0 ] : STATE_UNKNOWN |
| * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set |
| * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set |
| * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC is set |
| * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED is set |
| * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set</pre> |
| * |
| * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has |
| * been determined from other sources. If TOW decoded is set then TOW Known must also be set. |
| * |
| * <p>Note well: if there is any ambiguity in integer millisecond, {@code STATE_MSEC_AMBIGUOUS} |
| * must be set accordingly, in the 'state' field. |
| * |
| * <p>This value must be populated if 'state' != {@code STATE_UNKNOWN}. |
| * |
| * <p>For Glonass, this is: |
| * <ul> |
| * <li>Received Glonass time of day, at the measurement time in nanoseconds.</li> |
| * </ul> |
| * |
| * <p>Given the highest sync state that can be achieved, per each satellite, valid range for |
| * this field can be: |
| * <pre> |
| * Searching : [ 0 ] : STATE_UNKNOWN |
| * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set |
| * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC is set |
| * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set |
| * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC is set |
| * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED is set |
| * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set</pre> |
| * |
| * Note: Time of day known refers to the case where it is possibly not decoded over the air but |
| * has been determined from other sources. If Time of day decoded is set then Time of day known |
| * must also be set. |
| * |
| * <p>For Beidou, this is: |
| * <ul> |
| * <li>Received Beidou time of week, at the measurement time in nanoseconds.</li> |
| * </ul> |
| * |
| * <p>Given the highest sync state that can be achieved, per each satellite, valid range for |
| * this field can be: |
| * <pre> |
| * Searching : [ 0 ] : STATE_UNKNOWN |
| * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set |
| * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC is set |
| * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC is set |
| * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC is set |
| * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC is set |
| * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set |
| * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre> |
| * |
| * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has |
| * been determined from other sources. If TOW decoded is set then TOW Known must also be set. |
| * |
| * <p>For Galileo, this is: |
| * <ul> |
| * <li>Received Galileo time of week, at the measurement time in nanoseconds.</li> |
| * </ul> |
| * <pre> |
| * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set |
| * E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set |
| * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set |
| * Time of week decoded : [ 0 1week ] : STATE_GAL_TOW_DECODED is set |
| * Time of week known : [ 0 1week ] : STATE_GAL_TOW_KNOWN set</pre> |
| * |
| * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has |
| * been determined from other sources. If TOW decoded is set then TOW Known must also be set. |
| * |
| * <p>For SBAS, this is: |
| * <ul> |
| * <li>Received SBAS time, at the measurement time in nanoseconds.</li> |
| * </ul> |
| * |
| * <p>Given the highest sync state that can be achieved, per each satellite, valid range for |
| * this field can be: |
| * <pre> |
| * Searching : [ 0 ] : STATE_UNKNOWN |
| * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set |
| * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set |
| * Message : [ 0 1s ] : STATE_SBAS_SYNC is set</pre> |
| */ |
| public long getReceivedSvTimeNanos() { |
| return mReceivedSvTimeNanos; |
| } |
| |
| /** |
| * Sets the received GNSS time in nanoseconds. |
| * @hide |
| */ |
| @TestApi |
| public void setReceivedSvTimeNanos(long value) { |
| mReceivedSvTimeNanos = value; |
| } |
| |
| /** |
| * Gets the error estimate (1-sigma) for the received GNSS time, in nanoseconds. |
| */ |
| public long getReceivedSvTimeUncertaintyNanos() { |
| return mReceivedSvTimeUncertaintyNanos; |
| } |
| |
| /** |
| * Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds. |
| * @hide |
| */ |
| @TestApi |
| public void setReceivedSvTimeUncertaintyNanos(long value) { |
| mReceivedSvTimeUncertaintyNanos = value; |
| } |
| |
| /** |
| * Gets the Carrier-to-noise density in dB-Hz. |
| * |
| * <p>Typical range: 10-50 db-Hz. |
| * |
| * <p>The value contains the measured C/N0 for the signal at the antenna input. |
| */ |
| public double getCn0DbHz() { |
| return mCn0DbHz; |
| } |
| |
| /** |
| * Sets the carrier-to-noise density in dB-Hz. |
| * @hide |
| */ |
| @TestApi |
| public void setCn0DbHz(double value) { |
| mCn0DbHz = value; |
| } |
| |
| /** |
| * Gets the Pseudorange rate at the timestamp in m/s. |
| * |
| * <p>The error estimate for this value is |
| * {@link #getPseudorangeRateUncertaintyMetersPerSecond()}. |
| * |
| * <p>The value is uncorrected, i.e. corrections for receiver and satellite clock frequency |
| * errors are not included. |
| * |
| * <p>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 'doppler shift' |
| * is given by the equation: |
| * |
| * <pre> |
| * pseudorange rate = -k * doppler shift (where k is a constant)</pre> |
| */ |
| public double getPseudorangeRateMetersPerSecond() { |
| return mPseudorangeRateMetersPerSecond; |
| } |
| |
| /** |
| * Sets the pseudorange rate at the timestamp in m/s. |
| * @hide |
| */ |
| @TestApi |
| public void setPseudorangeRateMetersPerSecond(double value) { |
| mPseudorangeRateMetersPerSecond = value; |
| } |
| |
| /** |
| * Gets the pseudorange's rate uncertainty (1-Sigma) in m/s. |
| * |
| * <p>The uncertainty is represented as an absolute (single sided) value. |
| */ |
| public double getPseudorangeRateUncertaintyMetersPerSecond() { |
| return mPseudorangeRateUncertaintyMetersPerSecond; |
| } |
| |
| /** |
| * Sets the pseudorange's rate uncertainty (1-Sigma) in m/s. |
| * @hide |
| */ |
| @TestApi |
| public void setPseudorangeRateUncertaintyMetersPerSecond(double value) { |
| mPseudorangeRateUncertaintyMetersPerSecond = value; |
| } |
| |
| /** |
| * Gets 'Accumulated Delta Range' state. |
| * |
| * <p>It indicates whether {@link #getAccumulatedDeltaRangeMeters()} is reset or there is a |
| * cycle slip (indicating 'loss of lock'). |
| */ |
| public int getAccumulatedDeltaRangeState() { |
| return mAccumulatedDeltaRangeState; |
| } |
| |
| /** |
| * Sets the 'Accumulated Delta Range' state. |
| * @hide |
| */ |
| @TestApi |
| public void setAccumulatedDeltaRangeState(int value) { |
| mAccumulatedDeltaRangeState = value; |
| } |
| |
| /** |
| * Gets a string representation of the 'Accumulated Delta Range state'. |
| * |
| * <p>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. |
| * |
| * <p>The error estimate for this value is {@link #getAccumulatedDeltaRangeUncertaintyMeters()}. |
| * |
| * <p>The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}. |
| * |
| * <p>A positive value indicates that the SV is moving away from the receiver. |
| * The sign of {@link #getAccumulatedDeltaRangeMeters()} and its relation to the sign of |
| * {@link #getCarrierPhase()} is given by the equation: |
| * |
| * <pre> |
| * accumulated delta range = -k * carrier phase (where k is a constant)</pre> |
| */ |
| public double getAccumulatedDeltaRangeMeters() { |
| return mAccumulatedDeltaRangeMeters; |
| } |
| |
| /** |
| * Sets the accumulated delta range in meters. |
| * @hide |
| */ |
| @TestApi |
| public void setAccumulatedDeltaRangeMeters(double value) { |
| mAccumulatedDeltaRangeMeters = value; |
| } |
| |
| /** |
| * Gets the accumulated delta range's uncertainty (1-Sigma) in meters. |
| * |
| * <p>The uncertainty is represented as an absolute (single sided) value. |
| * |
| * <p>The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}. |
| */ |
| public double getAccumulatedDeltaRangeUncertaintyMeters() { |
| return mAccumulatedDeltaRangeUncertaintyMeters; |
| } |
| |
| /** |
| * Sets the accumulated delta range's uncertainty (1-sigma) in meters. |
| * |
| * <p>The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}. |
| * |
| * @hide |
| */ |
| @TestApi |
| public void setAccumulatedDeltaRangeUncertaintyMeters(double value) { |
| mAccumulatedDeltaRangeUncertaintyMeters = value; |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getCarrierFrequencyHz()} is available, {@code false} |
| * otherwise. |
| */ |
| public boolean hasCarrierFrequencyHz() { |
| return isFlagSet(HAS_CARRIER_FREQUENCY); |
| } |
| |
| /** |
| * Gets the carrier frequency of the tracked signal. |
| * |
| * <p>For example it can be the GPS L1 = 1.57542e9 Hz, or L2, L5, varying GLO channels, etc. If |
| * the field is not set, it is the primary common use frequency, e.g. L1 for GPS. |
| * |
| * <p>The value is only available if {@link #hasCarrierFrequencyHz()} is {@code true}. |
| */ |
| public float getCarrierFrequencyHz() { |
| return mCarrierFrequencyHz; |
| } |
| |
| /** |
| * Sets the Carrier frequency in Hz. |
| * @hide |
| */ |
| @TestApi |
| public void setCarrierFrequencyHz(float carrierFrequencyHz) { |
| setFlag(HAS_CARRIER_FREQUENCY); |
| mCarrierFrequencyHz = carrierFrequencyHz; |
| } |
| |
| /** |
| * Resets the Carrier frequency in Hz. |
| * @hide |
| */ |
| @TestApi |
| public void resetCarrierFrequencyHz() { |
| resetFlag(HAS_CARRIER_FREQUENCY); |
| mCarrierFrequencyHz = Float.NaN; |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getCarrierCycles()} is available, {@code false} otherwise. |
| */ |
| public boolean hasCarrierCycles() { |
| return isFlagSet(HAS_CARRIER_CYCLES); |
| } |
| |
| /** |
| * The number of full carrier cycles between the satellite and the receiver. |
| * |
| * <p>The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}. |
| * |
| * <p>The value is only available if {@link #hasCarrierCycles()} is {@code true}. |
| */ |
| public long getCarrierCycles() { |
| return mCarrierCycles; |
| } |
| |
| /** |
| * Sets the number of full carrier cycles between the satellite and the receiver. |
| * @hide |
| */ |
| @TestApi |
| public void setCarrierCycles(long value) { |
| setFlag(HAS_CARRIER_CYCLES); |
| mCarrierCycles = value; |
| } |
| |
| /** |
| * Resets the number of full carrier cycles between the satellite and the receiver. |
| * @hide |
| */ |
| @TestApi |
| public void resetCarrierCycles() { |
| resetFlag(HAS_CARRIER_CYCLES); |
| mCarrierCycles = Long.MIN_VALUE; |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getCarrierPhase()} is available, {@code false} otherwise. |
| */ |
| public boolean hasCarrierPhase() { |
| return isFlagSet(HAS_CARRIER_PHASE); |
| } |
| |
| /** |
| * Gets the RF phase detected by the receiver. |
| * |
| * <p>Range: [0.0, 1.0]. |
| * |
| * <p>This is the fractional part of the complete carrier phase measurement. |
| * |
| * <p>The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}. |
| * |
| * <p>The error estimate for this value is {@link #getCarrierPhaseUncertainty()}. |
| * |
| * <p>The value is only available if {@link #hasCarrierPhase()} is {@code true}. |
| */ |
| public double getCarrierPhase() { |
| return mCarrierPhase; |
| } |
| |
| /** |
| * Sets the RF phase detected by the receiver. |
| * @hide |
| */ |
| @TestApi |
| public void setCarrierPhase(double value) { |
| setFlag(HAS_CARRIER_PHASE); |
| mCarrierPhase = value; |
| } |
| |
| /** |
| * Resets the RF phase detected by the receiver. |
| * @hide |
| */ |
| @TestApi |
| public void resetCarrierPhase() { |
| resetFlag(HAS_CARRIER_PHASE); |
| mCarrierPhase = Double.NaN; |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getCarrierPhaseUncertainty()} is available, {@code false} |
| * otherwise. |
| */ |
| public boolean hasCarrierPhaseUncertainty() { |
| return isFlagSet(HAS_CARRIER_PHASE_UNCERTAINTY); |
| } |
| |
| /** |
| * Gets the carrier-phase's uncertainty (1-Sigma). |
| * |
| * <p>The uncertainty is represented as an absolute (single sided) value. |
| * |
| * <p>The value is only available if {@link #hasCarrierPhaseUncertainty()} is {@code true}. |
| */ |
| public double getCarrierPhaseUncertainty() { |
| return mCarrierPhaseUncertainty; |
| } |
| |
| /** |
| * Sets the Carrier-phase's uncertainty (1-Sigma) in cycles. |
| * @hide |
| */ |
| @TestApi |
| public void setCarrierPhaseUncertainty(double value) { |
| setFlag(HAS_CARRIER_PHASE_UNCERTAINTY); |
| mCarrierPhaseUncertainty = value; |
| } |
| |
| /** |
| * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles. |
| * @hide |
| */ |
| @TestApi |
| public void resetCarrierPhaseUncertainty() { |
| resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY); |
| mCarrierPhaseUncertainty = Double.NaN; |
| } |
| |
| /** |
| * Gets a value indicating the 'multipath' state of the event. |
| */ |
| @MultipathIndicator |
| public int getMultipathIndicator() { |
| return mMultipathIndicator; |
| } |
| |
| /** |
| * Sets the 'multi-path' indicator. |
| * @hide |
| */ |
| @TestApi |
| public void setMultipathIndicator(@MultipathIndicator int value) { |
| mMultipathIndicator = value; |
| } |
| |
| /** |
| * Gets a string representation of the 'multi-path indicator'. |
| * |
| * <p>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_DETECTED: |
| return "NotDetected"; |
| default: |
| return "<Invalid:" + mMultipathIndicator + ">"; |
| } |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getSnrInDb()} is available, {@code false} otherwise. |
| */ |
| public boolean hasSnrInDb() { |
| return isFlagSet(HAS_SNR); |
| } |
| |
| /** |
| * Gets the Signal-to-Noise ratio (SNR) in dB. |
| * |
| * <p>The value is only available if {@link #hasSnrInDb()} is {@code true}. |
| */ |
| public double getSnrInDb() { |
| return mSnrInDb; |
| } |
| |
| /** |
| * Sets the Signal-to-noise ratio (SNR) in dB. |
| * @hide |
| */ |
| @TestApi |
| public void setSnrInDb(double snrInDb) { |
| setFlag(HAS_SNR); |
| mSnrInDb = snrInDb; |
| } |
| |
| /** |
| * Resets the Signal-to-noise ratio (SNR) in dB. |
| * @hide |
| */ |
| @TestApi |
| public void resetSnrInDb() { |
| resetFlag(HAS_SNR); |
| mSnrInDb = Double.NaN; |
| } |
| |
| /** |
| * Returns {@code true} if {@link #getAgcLevelDb()} is available, {@code false} otherwise. |
| * @hide |
| */ |
| public boolean hasAgcLevelDb() { |
| return isFlagSet(HAS_AUTOMATIC_GAIN_CONTROL); |
| } |
| |
| /** |
| * Gets the Automatic Gain Control level in dB. |
| * |
| * <p> AGC acts as a variable gain amplifier adjusting the power of the incoming signal to |
| * minimize the quantization losses. The AGC level may be used to indicate potential |
| * interference. When AGC is at a nominal level, this value must be set as 0. Higher gain |
| * (and/or lower input power) shall be output as a positive number. Hence in cases of strong |
| * jamming, in the band of this signal, this value will go more negative. |
| * <p>Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW |
| * components) may also affect the typical output of of this value on any given hardware design |
| * in an open sky test - the important aspect of this output is that changes in this value are |
| * indicative of changes on input signal power in the frequency band for this measurement. |
| * <p>The value is only available if {@link #hasAgcLevelDb()} is {@code true}. |
| * @hide |
| */ |
| public double getAgcLevelDb() { |
| return mAgcLevelDb; |
| } |
| |
| /** |
| * Sets the Automatic Gain Control level in dB. |
| * @hide |
| */ |
| public void setAgcLevelDb(double agcLevelDb) { |
| setFlag(HAS_AUTOMATIC_GAIN_CONTROL); |
| mAgcLevelDb = agcLevelDb; |
| } |
| |
| /** |
| * Resets the Automatic Gain Control level. |
| * @hide |
| */ |
| public void resetAgcLevel() { |
| resetFlag(HAS_AUTOMATIC_GAIN_CONTROL); |
| mAgcLevelDb = Double.NaN; |
| } |
| |
| public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() { |
| @Override |
| public GnssMeasurement createFromParcel(Parcel parcel) { |
| GnssMeasurement gnssMeasurement = new GnssMeasurement(); |
| |
| gnssMeasurement.mFlags = parcel.readInt(); |
| gnssMeasurement.mSvid = parcel.readInt(); |
| gnssMeasurement.mConstellationType = parcel.readInt(); |
| gnssMeasurement.mTimeOffsetNanos = parcel.readDouble(); |
| gnssMeasurement.mState = parcel.readInt(); |
| gnssMeasurement.mReceivedSvTimeNanos = parcel.readLong(); |
| gnssMeasurement.mReceivedSvTimeUncertaintyNanos = parcel.readLong(); |
| gnssMeasurement.mCn0DbHz = parcel.readDouble(); |
| gnssMeasurement.mPseudorangeRateMetersPerSecond = parcel.readDouble(); |
| gnssMeasurement.mPseudorangeRateUncertaintyMetersPerSecond = parcel.readDouble(); |
| gnssMeasurement.mAccumulatedDeltaRangeState = parcel.readInt(); |
| gnssMeasurement.mAccumulatedDeltaRangeMeters = parcel.readDouble(); |
| gnssMeasurement.mAccumulatedDeltaRangeUncertaintyMeters = parcel.readDouble(); |
| gnssMeasurement.mCarrierFrequencyHz = parcel.readFloat(); |
| gnssMeasurement.mCarrierCycles = parcel.readLong(); |
| gnssMeasurement.mCarrierPhase = parcel.readDouble(); |
| gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble(); |
| gnssMeasurement.mMultipathIndicator = parcel.readInt(); |
| gnssMeasurement.mSnrInDb = parcel.readDouble(); |
| gnssMeasurement.mAgcLevelDb = parcel.readDouble(); |
| |
| return gnssMeasurement; |
| } |
| |
| @Override |
| public GnssMeasurement[] newArray(int i) { |
| return new GnssMeasurement[i]; |
| } |
| }; |
| |
| @Override |
| public void writeToParcel(Parcel parcel, int flags) { |
| parcel.writeInt(mFlags); |
| parcel.writeInt(mSvid); |
| parcel.writeInt(mConstellationType); |
| parcel.writeDouble(mTimeOffsetNanos); |
| parcel.writeInt(mState); |
| parcel.writeLong(mReceivedSvTimeNanos); |
| parcel.writeLong(mReceivedSvTimeUncertaintyNanos); |
| parcel.writeDouble(mCn0DbHz); |
| parcel.writeDouble(mPseudorangeRateMetersPerSecond); |
| parcel.writeDouble(mPseudorangeRateUncertaintyMetersPerSecond); |
| parcel.writeInt(mAccumulatedDeltaRangeState); |
| parcel.writeDouble(mAccumulatedDeltaRangeMeters); |
| parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyMeters); |
| parcel.writeFloat(mCarrierFrequencyHz); |
| parcel.writeLong(mCarrierCycles); |
| parcel.writeDouble(mCarrierPhase); |
| parcel.writeDouble(mCarrierPhaseUncertainty); |
| parcel.writeInt(mMultipathIndicator); |
| parcel.writeDouble(mSnrInDb); |
| parcel.writeDouble(mAgcLevelDb); |
| } |
| |
| @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("GnssMeasurement:\n"); |
| |
| builder.append(String.format(format, "Svid", mSvid)); |
| builder.append(String.format(format, "ConstellationType", mConstellationType)); |
| builder.append(String.format(format, "TimeOffsetNanos", mTimeOffsetNanos)); |
| |
| builder.append(String.format(format, "State", getStateString())); |
| |
| builder.append(String.format( |
| formatWithUncertainty, |
| "ReceivedSvTimeNanos", |
| mReceivedSvTimeNanos, |
| "ReceivedSvTimeUncertaintyNanos", |
| mReceivedSvTimeUncertaintyNanos)); |
| |
| builder.append(String.format(format, "Cn0DbHz", mCn0DbHz)); |
| |
| builder.append(String.format( |
| formatWithUncertainty, |
| "PseudorangeRateMetersPerSecond", |
| mPseudorangeRateMetersPerSecond, |
| "PseudorangeRateUncertaintyMetersPerSecond", |
| mPseudorangeRateUncertaintyMetersPerSecond)); |
| |
| builder.append(String.format( |
| format, |
| "AccumulatedDeltaRangeState", |
| getAccumulatedDeltaRangeStateString())); |
| |
| builder.append(String.format( |
| formatWithUncertainty, |
| "AccumulatedDeltaRangeMeters", |
| mAccumulatedDeltaRangeMeters, |
| "AccumulatedDeltaRangeUncertaintyMeters", |
| mAccumulatedDeltaRangeUncertaintyMeters)); |
| |
| builder.append(String.format( |
| format, |
| "CarrierFrequencyHz", |
| hasCarrierFrequencyHz() ? mCarrierFrequencyHz : 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, "MultipathIndicator", getMultipathIndicatorString())); |
| |
| builder.append(String.format( |
| format, |
| "SnrInDb", |
| hasSnrInDb() ? mSnrInDb : null)); |
| builder.append(String.format( |
| format, |
| "AgcLevelDb", |
| hasAgcLevelDb() ? mAgcLevelDb : null)); |
| |
| return builder.toString(); |
| } |
| |
| private void initialize() { |
| mFlags = HAS_NO_FLAGS; |
| setSvid(0); |
| setTimeOffsetNanos(Long.MIN_VALUE); |
| setState(STATE_UNKNOWN); |
| setReceivedSvTimeNanos(Long.MIN_VALUE); |
| setReceivedSvTimeUncertaintyNanos(Long.MAX_VALUE); |
| setCn0DbHz(Double.MIN_VALUE); |
| setPseudorangeRateMetersPerSecond(Double.MIN_VALUE); |
| setPseudorangeRateUncertaintyMetersPerSecond(Double.MIN_VALUE); |
| setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN); |
| setAccumulatedDeltaRangeMeters(Double.MIN_VALUE); |
| setAccumulatedDeltaRangeUncertaintyMeters(Double.MIN_VALUE); |
| resetCarrierFrequencyHz(); |
| resetCarrierCycles(); |
| resetCarrierPhase(); |
| resetCarrierPhaseUncertainty(); |
| setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN); |
| resetSnrInDb(); |
| resetAgcLevel(); |
| } |
| |
| private void setFlag(int flag) { |
| mFlags |= flag; |
| } |
| |
| private void resetFlag(int flag) { |
| mFlags &= ~flag; |
| } |
| |
| private boolean isFlagSet(int flag) { |
| return (mFlags & flag) == flag; |
| } |
| } |