1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.location;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 /**
27  * A class that contains GNSS satellite position, velocity and time information at the
28  * same signal transmission time {@link GnssMeasurement#getReceivedSvTimeNanos()}.
29  *
30  * <p>The position and velocity must be in ECEF coordinates.
31  *
32  * <p>If {@link GnssMeasurement#getSatellitePvt()} is derived from Broadcast ephemeris, then the
33  * position is already w.r.t. the antenna phase center. However, if
34  * {@link GnssMeasurement#getSatellitePvt()} is derived from other modeled orbits, such as
35  * long-term orbits, or precise orbits, then the orbits may have been computed w.r.t.
36  * the satellite center of mass, and then GNSS vendors are expected to correct for the effect
37  * on different phase centers (can differ by meters) of different GNSS signals (e.g. L1, L5)
38  * on the reported satellite position. Accordingly, we might observe a different satellite
39  * position reported for L1 GnssMeasurement struct compared to L5 GnssMeasurement struct.
40  *
41  * <p>If {@link GnssMeasurement#getReceivedSvTimeNanos()} is not fully decoded,
42  * {@link GnssMeasurement#getSatellitePvt()} could still be reported and
43  * {@link GnssMeasurement#getReceivedSvTimeUncertaintyNanos()} would be used to provide confidence.
44  * @hide
45  */
46 @SystemApi
47 public final class SatellitePvt implements Parcelable {
48     /**
49      * Bit mask for {@link #mFlags} indicating valid satellite position, velocity and clock info
50      * fields are stored in the SatellitePvt.
51      */
52     private static final int HAS_POSITION_VELOCITY_CLOCK_INFO = 1 << 0;
53 
54     /**
55      * Bit mask for {@link #mFlags} indicating a valid iono delay field is stored in the
56      * SatellitePvt.
57      */
58     private static final int HAS_IONO = 1 << 1;
59 
60     /**
61      * Bit mask for {@link #mFlags} indicating a valid tropo delay field is stored in the
62      * SatellitePvt.
63      */
64     private static final int HAS_TROPO = 1 << 2;
65 
66     /**
67      * A bitfield of flags indicating the validity of the fields in this SatellitePvt.
68      * The bit masks are defined in the constants with prefix HAS_*
69      *
70      * <p>Fields for which there is no corresponding flag must be filled in with a valid value.
71      * For convenience, these are marked as mandatory.
72      *
73      * <p>Others fields may have invalid information in them, if not marked as valid by the
74      * corresponding bit in flags.
75      */
76     private final int mFlags;
77 
78     @Nullable
79     private final PositionEcef mPositionEcef;
80     @Nullable
81     private final VelocityEcef mVelocityEcef;
82     @Nullable
83     private final ClockInfo mClockInfo;
84     private final double mIonoDelayMeters;
85     private final double mTropoDelayMeters;
86 
87     /**
88      * Class containing estimates of the satellite position fields in ECEF coordinate frame.
89      *
90      * <p>The satellite position must be defined at the time of transmission of the signal
91      * receivedSvTimeNs.
92      */
93     public static final class PositionEcef implements Parcelable {
94         private final double mXMeters;
95         private final double mYMeters;
96         private final double mZMeters;
97         private final double mUreMeters;
98 
PositionEcef( double xMeters, double yMeters, double zMeters, double ureMeters)99         public PositionEcef(
100                 double xMeters,
101                 double yMeters,
102                 double zMeters,
103                 double ureMeters) {
104             mXMeters = xMeters;
105             mYMeters = yMeters;
106             mZMeters = zMeters;
107             mUreMeters = ureMeters;
108         }
109 
110         public static final @NonNull Creator<PositionEcef> CREATOR =
111                 new Creator<PositionEcef>() {
112                     @Override
113                     public PositionEcef createFromParcel(Parcel in) {
114                         return new PositionEcef(
115                                 in.readDouble(),
116                                 in.readDouble(),
117                                 in.readDouble(),
118                                 in.readDouble()
119                         );
120                     }
121 
122                     @Override
123                     public PositionEcef[] newArray(int size) {
124                         return new PositionEcef[size];
125                     }
126                 };
127 
128         /**
129          * Returns the satellite position X in WGS84 ECEF (meters).
130          */
131         @FloatRange()
getXMeters()132         public double getXMeters() {
133             return mXMeters;
134         }
135 
136         /**
137          * Returns the satellite position Y in WGS84 ECEF (meters).
138          */
139         @FloatRange()
getYMeters()140         public double getYMeters() {
141             return mYMeters;
142         }
143 
144         /**
145          * Returns the satellite position Z in WGS84 ECEF (meters).
146          */
147         @FloatRange()
getZMeters()148         public double getZMeters() {
149             return mZMeters;
150         }
151 
152         /**
153          * Returns the signal in Space User Range Error (URE) (meters).
154          */
155         @FloatRange(from = 0.0f, fromInclusive = false)
getUreMeters()156         public double getUreMeters() {
157             return mUreMeters;
158         }
159 
160         @Override
describeContents()161         public int describeContents() {
162             return 0;
163         }
164 
165         @Override
writeToParcel(@onNull Parcel dest, int flags)166         public void writeToParcel(@NonNull Parcel dest, int flags) {
167             dest.writeDouble(mXMeters);
168             dest.writeDouble(mYMeters);
169             dest.writeDouble(mZMeters);
170             dest.writeDouble(mUreMeters);
171         }
172 
173         @Override
toString()174         public String toString() {
175             return "PositionEcef{"
176                     + "xMeters=" + mXMeters
177                     + ", yMeters=" + mYMeters
178                     + ", zMeters=" + mZMeters
179                     + ", ureMeters=" + mUreMeters
180                     + "}";
181         }
182     }
183 
184     /**
185      * Class containing estimates of the satellite velocity fields in the ECEF coordinate frame.
186      *
187      * <p>The satellite velocity must be defined at the time of transmission of the signal
188      * receivedSvTimeNs.
189      */
190     public static final class VelocityEcef implements Parcelable {
191         private final double mXMetersPerSecond;
192         private final double mYMetersPerSecond;
193         private final double mZMetersPerSecond;
194         private final double mUreRateMetersPerSecond;
195 
VelocityEcef( double xMetersPerSecond, double yMetersPerSecond, double zMetersPerSecond, double ureRateMetersPerSecond)196         public VelocityEcef(
197                 double xMetersPerSecond,
198                 double yMetersPerSecond,
199                 double zMetersPerSecond,
200                 double ureRateMetersPerSecond) {
201             mXMetersPerSecond = xMetersPerSecond;
202             mYMetersPerSecond = yMetersPerSecond;
203             mZMetersPerSecond = zMetersPerSecond;
204             mUreRateMetersPerSecond = ureRateMetersPerSecond;
205         }
206 
207         public static final @NonNull Creator<VelocityEcef> CREATOR =
208                 new Creator<VelocityEcef>() {
209                     @Override
210                     public VelocityEcef createFromParcel(Parcel in) {
211                         return new VelocityEcef(
212                                 in.readDouble(),
213                                 in.readDouble(),
214                                 in.readDouble(),
215                                 in.readDouble()
216                         );
217                     }
218 
219                     @Override
220                     public VelocityEcef[] newArray(int size) {
221                         return new VelocityEcef[size];
222                     }
223                 };
224 
225         /**
226          * Returns the satellite velocity X in WGS84 ECEF (meters per second).
227          */
228         @FloatRange()
getXMetersPerSecond()229         public double getXMetersPerSecond() {
230             return mXMetersPerSecond;
231         }
232 
233         /**
234          * Returns the satellite velocity Y in WGS84 ECEF (meters per second).
235          */
236         @FloatRange()
getYMetersPerSecond()237         public double getYMetersPerSecond() {
238             return mYMetersPerSecond;
239         }
240 
241         /**
242          *Returns the satellite velocity Z in WGS84 ECEF (meters per second).
243          */
244         @FloatRange()
getZMetersPerSecond()245         public double getZMetersPerSecond() {
246             return mZMetersPerSecond;
247         }
248 
249         /**
250          * Returns the signal in Space User Range Error Rate (URE Rate) (meters per second).
251          *
252          * <p>It covers satellite velocity error and Satellite clock drift
253          * projected to the pseudorange rate measurements.
254          */
255         @FloatRange(from = 0.0f, fromInclusive = false)
getUreRateMetersPerSecond()256         public double getUreRateMetersPerSecond() {
257             return mUreRateMetersPerSecond;
258         }
259 
260         @Override
describeContents()261         public int describeContents() {
262             return 0;
263         }
264 
265         @Override
writeToParcel(@onNull Parcel dest, int flags)266         public void writeToParcel(@NonNull Parcel dest, int flags) {
267             dest.writeDouble(mXMetersPerSecond);
268             dest.writeDouble(mYMetersPerSecond);
269             dest.writeDouble(mZMetersPerSecond);
270             dest.writeDouble(mUreRateMetersPerSecond);
271         }
272 
273         @Override
toString()274         public String toString() {
275             return "VelocityEcef{"
276                     + "xMetersPerSecond=" + mXMetersPerSecond
277                     + ", yMetersPerSecond=" + mYMetersPerSecond
278                     + ", zMetersPerSecond=" + mZMetersPerSecond
279                     + ", ureRateMetersPerSecond=" + mUreRateMetersPerSecond
280                     + "}";
281         }
282     }
283 
284     /**
285      * Class containing estimates of the satellite clock info.
286      */
287     public static final class ClockInfo implements Parcelable {
288         private final double mHardwareCodeBiasMeters;
289         private final double mTimeCorrectionMeters;
290         private final double mClockDriftMetersPerSecond;
291 
ClockInfo( double hardwareCodeBiasMeters, double timeCorrectionMeters, double clockDriftMetersPerSecond)292         public ClockInfo(
293                 double hardwareCodeBiasMeters,
294                 double timeCorrectionMeters,
295                 double clockDriftMetersPerSecond) {
296             mHardwareCodeBiasMeters = hardwareCodeBiasMeters;
297             mTimeCorrectionMeters = timeCorrectionMeters;
298             mClockDriftMetersPerSecond = clockDriftMetersPerSecond;
299         }
300 
301         public static final @NonNull Creator<ClockInfo> CREATOR =
302                 new Creator<ClockInfo>() {
303                     @Override
304                     public ClockInfo createFromParcel(Parcel in) {
305                         return new ClockInfo(
306                                 in.readDouble(),
307                                 in.readDouble(),
308                                 in.readDouble()
309                         );
310                     }
311 
312                     @Override
313                     public ClockInfo[] newArray(int size) {
314                         return new ClockInfo[size];
315                     }
316                 };
317 
318         /**
319          * Returns the satellite hardware code bias of the reported code type w.r.t
320          * ionosphere-free measurement in meters.
321          *
322          * <p>When broadcast ephemeris is used, this is the offset caused
323          * by the satellite hardware delays at different frequencies;
324          * e.g. in IS-GPS-705D, this term is described in Section
325          * 20.3.3.3.1.2.1.
326          *
327          * <p>For GPS this term is ~10ns, and affects the satellite position
328          * computation by less than a millimeter.
329          */
330         @FloatRange()
getHardwareCodeBiasMeters()331         public double getHardwareCodeBiasMeters() {
332             return mHardwareCodeBiasMeters;
333         }
334 
335         /**
336          * Returns the satellite time correction for ionospheric-free signal measurement
337          * (meters). The satellite clock correction for the given signal type
338          * = satTimeCorrectionMeters - satHardwareCodeBiasMeters.
339          *
340          * <p>When broadcast ephemeris is used, this is the offset modeled in the
341          * clock terms broadcast over the air by the satellites;
342          * e.g. in IS-GPS-200H, Section 20.3.3.3.3.1, this term is
343          * ∆tsv = af0 + af1(t - toc) + af2(t - toc)^2 + ∆tr.
344          *
345          * <p>If another source of ephemeris is used for SatellitePvt, then the
346          * equivalent value of satTimeCorrection must be provided.
347          *
348          * <p>For GPS this term is ~1ms, and affects the satellite position
349          * computation by ~1m.
350          */
351         @FloatRange()
getTimeCorrectionMeters()352         public double getTimeCorrectionMeters() {
353             return mTimeCorrectionMeters;
354         }
355 
356         /**
357          * Returns the satellite clock drift (meters per second).
358          */
359         @FloatRange()
getClockDriftMetersPerSecond()360         public double getClockDriftMetersPerSecond() {
361             return mClockDriftMetersPerSecond;
362         }
363 
364         @Override
describeContents()365         public int describeContents() {
366             return 0;
367         }
368 
369         @Override
writeToParcel(@onNull Parcel dest, int flags)370         public void writeToParcel(@NonNull Parcel dest, int flags) {
371             dest.writeDouble(mHardwareCodeBiasMeters);
372             dest.writeDouble(mTimeCorrectionMeters);
373             dest.writeDouble(mClockDriftMetersPerSecond);
374         }
375 
376         @Override
toString()377         public String toString() {
378             return "ClockInfo{"
379                     + "hardwareCodeBiasMeters=" + mHardwareCodeBiasMeters
380                     + ", timeCorrectionMeters=" + mTimeCorrectionMeters
381                     + ", clockDriftMetersPerSecond=" + mClockDriftMetersPerSecond
382                     + "}";
383         }
384     }
385 
SatellitePvt( int flags, @Nullable PositionEcef positionEcef, @Nullable VelocityEcef velocityEcef, @Nullable ClockInfo clockInfo, double ionoDelayMeters, double tropoDelayMeters)386     private SatellitePvt(
387             int flags,
388             @Nullable PositionEcef positionEcef,
389             @Nullable VelocityEcef velocityEcef,
390             @Nullable ClockInfo clockInfo,
391             double ionoDelayMeters,
392             double tropoDelayMeters) {
393         mFlags = flags;
394         mPositionEcef = positionEcef;
395         mVelocityEcef = velocityEcef;
396         mClockInfo = clockInfo;
397         mIonoDelayMeters = ionoDelayMeters;
398         mTropoDelayMeters = tropoDelayMeters;
399     }
400 
401     /**
402      * Returns a {@link PositionEcef} object that contains estimates of the satellite
403      * position fields in ECEF coordinate frame.
404      */
405     @Nullable
getPositionEcef()406     public PositionEcef getPositionEcef() {
407         return mPositionEcef;
408     }
409 
410     /**
411      * Returns a {@link VelocityEcef} object that contains estimates of the satellite
412      * velocity fields in the ECEF coordinate frame.
413      */
414     @Nullable
getVelocityEcef()415     public VelocityEcef getVelocityEcef() {
416         return mVelocityEcef;
417     }
418 
419     /**
420      * Returns a {@link ClockInfo} object that contains estimates of the satellite
421      * clock info.
422      */
423     @Nullable
getClockInfo()424     public ClockInfo getClockInfo() {
425         return mClockInfo;
426     }
427 
428     /**
429      * Returns the ionospheric delay in meters.
430      */
431     @FloatRange()
getIonoDelayMeters()432     public double getIonoDelayMeters() {
433         return mIonoDelayMeters;
434     }
435 
436     /**
437      * Returns the tropospheric delay in meters.
438      */
439     @FloatRange()
getTropoDelayMeters()440     public double getTropoDelayMeters() {
441         return mTropoDelayMeters;
442     }
443 
444     /** Returns {@code true} if {@link #getPositionEcef()}, {@link #getVelocityEcef()},
445      * and {@link #getClockInfo()} are valid.
446      */
hasPositionVelocityClockInfo()447     public boolean hasPositionVelocityClockInfo() {
448         return (mFlags & HAS_POSITION_VELOCITY_CLOCK_INFO) != 0;
449     }
450 
451     /** Returns {@code true} if {@link #getIonoDelayMeters()} is valid. */
hasIono()452     public boolean hasIono() {
453         return (mFlags & HAS_IONO) != 0;
454     }
455 
456     /** Returns {@code true} if {@link #getTropoDelayMeters()} is valid. */
hasTropo()457     public boolean hasTropo() {
458         return (mFlags & HAS_TROPO) != 0;
459     }
460 
461     public static final @android.annotation.NonNull Creator<SatellitePvt> CREATOR =
462             new Creator<SatellitePvt>() {
463                 @Override
464                 @Nullable
465                 public SatellitePvt createFromParcel(Parcel in) {
466                     int flags = in.readInt();
467                     ClassLoader classLoader = getClass().getClassLoader();
468                     PositionEcef positionEcef = in.readParcelable(classLoader);
469                     VelocityEcef velocityEcef = in.readParcelable(classLoader);
470                     ClockInfo clockInfo = in.readParcelable(classLoader);
471                     double ionoDelayMeters = in.readDouble();
472                     double tropoDelayMeters = in.readDouble();
473 
474                     return new SatellitePvt(
475                             flags,
476                             positionEcef,
477                             velocityEcef,
478                             clockInfo,
479                             ionoDelayMeters,
480                             tropoDelayMeters);
481                 }
482 
483                 @Override
484                 public SatellitePvt[] newArray(int size) {
485                     return new SatellitePvt[size];
486                 }
487             };
488 
489     @Override
describeContents()490     public int describeContents() {
491         return 0;
492     }
493 
494     @Override
writeToParcel(@onNull Parcel parcel, int flags)495     public void writeToParcel(@NonNull Parcel parcel, int flags) {
496         parcel.writeInt(mFlags);
497         parcel.writeParcelable(mPositionEcef, flags);
498         parcel.writeParcelable(mVelocityEcef, flags);
499         parcel.writeParcelable(mClockInfo, flags);
500         parcel.writeDouble(mIonoDelayMeters);
501         parcel.writeDouble(mTropoDelayMeters);
502     }
503 
504     @Override
toString()505     public String toString() {
506         return "SatellitePvt{"
507                 + "Flags=" + mFlags
508                 + ", PositionEcef=" + mPositionEcef
509                 + ", VelocityEcef=" + mVelocityEcef
510                 + ", ClockInfo=" + mClockInfo
511                 + ", IonoDelayMeters=" + mIonoDelayMeters
512                 + ", TropoDelayMeters=" + mTropoDelayMeters
513                 + "}";
514     }
515 
516     /**
517      * Builder class for SatellitePvt.
518      */
519     public static final class Builder {
520         /**
521          * For documentation of below fields, see corresponding fields in {@link
522          * SatellitePvt}.
523          */
524         private int mFlags;
525         @Nullable private PositionEcef mPositionEcef;
526         @Nullable private VelocityEcef mVelocityEcef;
527         @Nullable private ClockInfo mClockInfo;
528         private double mIonoDelayMeters;
529         private double mTropoDelayMeters;
530 
531         /**
532          * Set position ECEF.
533          *
534          * @param positionEcef position ECEF object
535          * @return Builder builder object
536          */
537         @NonNull
setPositionEcef( @onNull PositionEcef positionEcef)538         public Builder setPositionEcef(
539                 @NonNull PositionEcef positionEcef) {
540             mPositionEcef = positionEcef;
541             updateFlags();
542             return this;
543         }
544 
545         /**
546          * Set velocity ECEF.
547          *
548          * @param velocityEcef velocity ECEF object
549          * @return Builder builder object
550          */
551         @NonNull
setVelocityEcef( @onNull VelocityEcef velocityEcef)552         public Builder setVelocityEcef(
553                 @NonNull VelocityEcef velocityEcef) {
554             mVelocityEcef = velocityEcef;
555             updateFlags();
556             return this;
557         }
558 
559         /**
560          * Set clock info.
561          *
562          * @param clockInfo clock info object
563          * @return Builder builder object
564          */
565         @NonNull
setClockInfo( @onNull ClockInfo clockInfo)566         public Builder setClockInfo(
567                 @NonNull ClockInfo clockInfo) {
568             mClockInfo = clockInfo;
569             updateFlags();
570             return this;
571         }
572 
updateFlags()573         private void updateFlags() {
574             if (mPositionEcef != null && mVelocityEcef != null && mClockInfo != null) {
575                 mFlags = (byte) (mFlags | HAS_POSITION_VELOCITY_CLOCK_INFO);
576             }
577         }
578 
579         /**
580          * Set ionospheric delay in meters.
581          *
582          * @param ionoDelayMeters ionospheric delay (meters)
583          * @return Builder builder object
584          */
585         @NonNull
setIonoDelayMeters( @loatRangefrom = 0.0f, to = 100.0f) double ionoDelayMeters)586         public Builder setIonoDelayMeters(
587                 @FloatRange(from = 0.0f, to = 100.0f) double ionoDelayMeters) {
588             mIonoDelayMeters = ionoDelayMeters;
589             mFlags = (byte) (mFlags | HAS_IONO);
590             return this;
591         }
592 
593         /**
594          * Set tropospheric delay in meters.
595          *
596          * @param tropoDelayMeters tropospheric delay (meters)
597          * @return Builder builder object
598          */
599         @NonNull
setTropoDelayMeters( @loatRangefrom = 0.0f, to = 100.0f) double tropoDelayMeters)600         public Builder setTropoDelayMeters(
601                 @FloatRange(from = 0.0f, to = 100.0f) double tropoDelayMeters) {
602             mTropoDelayMeters = tropoDelayMeters;
603             mFlags = (byte) (mFlags | HAS_TROPO);
604             return this;
605         }
606 
607         /**
608          * Build SatellitePvt object.
609          *
610          * @return instance of SatellitePvt
611          */
612         @NonNull
build()613         public SatellitePvt build() {
614             return new SatellitePvt(mFlags, mPositionEcef, mVelocityEcef, mClockInfo,
615                     mIonoDelayMeters, mTropoDelayMeters);
616         }
617     }
618 }
619