• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation, nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include <LocationUtil.h>
31 #include <log_util.h>
32 #include <inttypes.h>
33 #include <loc_misc_utils.h>
34 #include <gps_extended_c.h>
35 
36 namespace android {
37 namespace hardware {
38 namespace gnss {
39 namespace V2_1 {
40 namespace implementation {
41 
42 using ::android::hardware::gnss::V2_0::GnssLocation;
43 using ::android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
44 using ::android::hardware::gnss::V2_0::GnssConstellationType;
45 using ::android::hardware::gnss::V1_0::GnssLocationFlags;
46 using ::android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
47 
convertGnssLocation(Location & in,V1_0::GnssLocation & out)48 void convertGnssLocation(Location& in, V1_0::GnssLocation& out)
49 {
50     memset(&out, 0, sizeof(V1_0::GnssLocation));
51     if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
52         out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
53         out.latitudeDegrees = in.latitude;
54         out.longitudeDegrees = in.longitude;
55     }
56     if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
57         out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
58         out.altitudeMeters = in.altitude;
59     }
60     if (in.flags & LOCATION_HAS_SPEED_BIT) {
61         out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
62         out.speedMetersPerSec = in.speed;
63     }
64     if (in.flags & LOCATION_HAS_BEARING_BIT) {
65         out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
66         out.bearingDegrees = in.bearing;
67     }
68     if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
69         out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
70         out.horizontalAccuracyMeters = in.accuracy;
71     }
72     if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
73         out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
74         out.verticalAccuracyMeters = in.verticalAccuracy;
75     }
76     if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
77         out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
78         out.speedAccuracyMetersPerSecond = in.speedAccuracy;
79     }
80     if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
81         out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
82         out.bearingAccuracyDegrees = in.bearingAccuracy;
83     }
84 
85     out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
86 }
87 
getCurrentTime(struct timespec & currentTime,int64_t & sinceBootTimeNanos)88 bool getCurrentTime(struct timespec& currentTime, int64_t& sinceBootTimeNanos)
89 {
90     struct timespec sinceBootTime;
91     struct timespec sinceBootTimeTest;
92     bool clockGetTimeSuccess = false;
93     const uint32_t MAX_TIME_DELTA_VALUE_NANOS = 10000;
94     const uint32_t MAX_GET_TIME_COUNT = 20;
95     /* Attempt to get CLOCK_REALTIME and CLOCK_BOOTIME in succession without an interruption
96     or context switch (for up to MAX_GET_TIME_COUNT times) to avoid errors in the calculation */
97     for (uint32_t i = 0; i < MAX_GET_TIME_COUNT; i++) {
98         if (clock_gettime(CLOCK_BOOTTIME, &sinceBootTime) != 0) {
99             break;
100         };
101         if (clock_gettime(CLOCK_REALTIME, &currentTime) != 0) {
102             break;
103         }
104         if (clock_gettime(CLOCK_BOOTTIME, &sinceBootTimeTest) != 0) {
105             break;
106         };
107         sinceBootTimeNanos = sinceBootTime.tv_sec * 1000000000 + sinceBootTime.tv_nsec;
108         int64_t sinceBootTimeTestNanos =
109             sinceBootTimeTest.tv_sec * 1000000000 + sinceBootTimeTest.tv_nsec;
110         int64_t sinceBootTimeDeltaNanos = sinceBootTimeTestNanos - sinceBootTimeNanos;
111 
112         /* sinceBootTime and sinceBootTimeTest should have a close value if there was no
113         interruption or context switch between clock_gettime for CLOCK_BOOTIME and
114         clock_gettime for CLOCK_REALTIME */
115         if (sinceBootTimeDeltaNanos < MAX_TIME_DELTA_VALUE_NANOS) {
116             clockGetTimeSuccess = true;
117             break;
118         } else {
119             LOC_LOGd("Delta:%" PRIi64 "ns time too large, retry number #%u...",
120                      sinceBootTimeDeltaNanos, i + 1);
121         }
122     }
123     return clockGetTimeSuccess;
124 }
125 
convertGnssLocation(Location & in,V2_0::GnssLocation & out)126 void convertGnssLocation(Location& in, V2_0::GnssLocation& out)
127 {
128     memset(&out, 0, sizeof(V2_0::GnssLocation));
129     convertGnssLocation(in, out.v1_0);
130 
131     struct timespec currentTime;
132     int64_t sinceBootTimeNanos;
133 
134     if (getCurrentTime(currentTime, sinceBootTimeNanos)) {
135         if (in.flags & LOCATION_HAS_ELAPSED_REAL_TIME) {
136             uint64_t qtimerDiff = 0;
137             uint64_t qTimerTickCount = getQTimerTickCount();
138             if (qTimerTickCount >= in.elapsedRealTime) {
139                 qtimerDiff = qTimerTickCount - in.elapsedRealTime;
140             }
141             LOC_LOGv("sinceBootTimeNanos:%" PRIi64 " in.elapsedRealTime=%" PRIi64 ""
142                      " qTimerTickCount=%" PRIi64 " qtimerDiff=%" PRIi64 "",
143                      sinceBootTimeNanos, in.elapsedRealTime, qTimerTickCount, qtimerDiff);
144             uint64_t qTimerDiffNanos = qTimerTicksToNanos(double(qtimerDiff));
145             if (sinceBootTimeNanos >= qTimerDiffNanos) {
146                 out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
147                 out.elapsedRealtime.timestampNs = sinceBootTimeNanos - qTimerDiffNanos;
148                 out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
149                 out.elapsedRealtime.timeUncertaintyNs = in.elapsedRealTimeUnc;
150             }
151         } else {
152             int64_t currentTimeNanos = currentTime.tv_sec*1000000000 + currentTime.tv_nsec;
153             int64_t locationTimeNanos = in.timestamp*1000000;
154             LOC_LOGv("sinceBootTimeNanos:%" PRIi64 " currentTimeNanos:%" PRIi64 ""
155                      " locationTimeNanos:%" PRIi64 "",
156                      sinceBootTimeNanos, currentTimeNanos, locationTimeNanos);
157             if (currentTimeNanos >= locationTimeNanos) {
158                 int64_t ageTimeNanos = currentTimeNanos - locationTimeNanos;
159                 LOC_LOGv("ageTimeNanos:%" PRIi64 ")", ageTimeNanos);
160                 // the max trusted propagation time 100ms for ageTimeNanos to avoid user setting
161                 // wrong time, it will affect elapsedRealtimeNanos
162                 if (ageTimeNanos <= 100000000) {
163                     out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
164                     out.elapsedRealtime.timestampNs = sinceBootTimeNanos - ageTimeNanos;
165                     out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
166                     // time uncertainty is the max value between abs(AP_UTC - MP_UTC) and 100ms, to
167                     // verify if user change the sys time
168                     out.elapsedRealtime.timeUncertaintyNs =
169                             std::max(ageTimeNanos, (int64_t)100000000);
170                 }
171             }
172         }
173     }
174     LOC_LOGv("out.elapsedRealtime.timestampNs=%" PRIi64 ""
175              " out.elapsedRealtime.timeUncertaintyNs=%" PRIi64 ""
176              " out.elapsedRealtime.flags=0x%X",
177              out.elapsedRealtime.timestampNs,
178              out.elapsedRealtime.timeUncertaintyNs, out.elapsedRealtime.flags);
179 }
180 
convertGnssLocation(const V1_0::GnssLocation & in,Location & out)181 void convertGnssLocation(const V1_0::GnssLocation& in, Location& out)
182 {
183     memset(&out, 0, sizeof(out));
184     if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
185         out.flags |= LOCATION_HAS_LAT_LONG_BIT;
186         out.latitude = in.latitudeDegrees;
187         out.longitude = in.longitudeDegrees;
188     }
189     if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
190         out.flags |= LOCATION_HAS_ALTITUDE_BIT;
191         out.altitude = in.altitudeMeters;
192     }
193     if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
194         out.flags |= LOCATION_HAS_SPEED_BIT;
195         out.speed = in.speedMetersPerSec;
196     }
197     if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
198         out.flags |= LOCATION_HAS_BEARING_BIT;
199         out.bearing = in.bearingDegrees;
200     }
201     if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
202         out.flags |= LOCATION_HAS_ACCURACY_BIT;
203         out.accuracy = in.horizontalAccuracyMeters;
204     }
205     if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
206         out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
207         out.verticalAccuracy = in.verticalAccuracyMeters;
208     }
209     if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
210         out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
211         out.speedAccuracy = in.speedAccuracyMetersPerSecond;
212     }
213     if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
214         out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
215         out.bearingAccuracy = in.bearingAccuracyDegrees;
216     }
217 
218     out.timestamp = static_cast<uint64_t>(in.timestamp);
219 }
220 
convertGnssLocation(const V2_0::GnssLocation & in,Location & out)221 void convertGnssLocation(const V2_0::GnssLocation& in, Location& out)
222 {
223     memset(&out, 0, sizeof(out));
224     convertGnssLocation(in.v1_0, out);
225 }
226 
convertGnssConstellationType(GnssSvType & in,V1_0::GnssConstellationType & out)227 void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out)
228 {
229     switch(in) {
230         case GNSS_SV_TYPE_GPS:
231             out = V1_0::GnssConstellationType::GPS;
232             break;
233         case GNSS_SV_TYPE_SBAS:
234             out = V1_0::GnssConstellationType::SBAS;
235             break;
236         case GNSS_SV_TYPE_GLONASS:
237             out = V1_0::GnssConstellationType::GLONASS;
238             break;
239         case GNSS_SV_TYPE_QZSS:
240             out = V1_0::GnssConstellationType::QZSS;
241             break;
242         case GNSS_SV_TYPE_BEIDOU:
243             out = V1_0::GnssConstellationType::BEIDOU;
244             break;
245         case GNSS_SV_TYPE_GALILEO:
246             out = V1_0::GnssConstellationType::GALILEO;
247             break;
248         case GNSS_SV_TYPE_UNKNOWN:
249         default:
250             out = V1_0::GnssConstellationType::UNKNOWN;
251             break;
252     }
253 }
254 
convertGnssConstellationType(GnssSvType & in,V2_0::GnssConstellationType & out)255 void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out)
256 {
257     switch(in) {
258         case GNSS_SV_TYPE_GPS:
259             out = V2_0::GnssConstellationType::GPS;
260             break;
261         case GNSS_SV_TYPE_SBAS:
262             out = V2_0::GnssConstellationType::SBAS;
263             break;
264         case GNSS_SV_TYPE_GLONASS:
265             out = V2_0::GnssConstellationType::GLONASS;
266             break;
267         case GNSS_SV_TYPE_QZSS:
268             out = V2_0::GnssConstellationType::QZSS;
269             break;
270         case GNSS_SV_TYPE_BEIDOU:
271             out = V2_0::GnssConstellationType::BEIDOU;
272             break;
273         case GNSS_SV_TYPE_GALILEO:
274             out = V2_0::GnssConstellationType::GALILEO;
275             break;
276         case GNSS_SV_TYPE_NAVIC:
277             out = V2_0::GnssConstellationType::IRNSS;
278             break;
279         case GNSS_SV_TYPE_UNKNOWN:
280         default:
281             out = V2_0::GnssConstellationType::UNKNOWN;
282             break;
283     }
284 }
285 
convertGnssSvid(GnssSv & in,int16_t & out)286 void convertGnssSvid(GnssSv& in, int16_t& out)
287 {
288     switch (in.type) {
289         case GNSS_SV_TYPE_GPS:
290             out = in.svId;
291             break;
292         case GNSS_SV_TYPE_SBAS:
293             out = in.svId;
294             break;
295         case GNSS_SV_TYPE_GLONASS:
296             out = in.svId - GLO_SV_PRN_MIN + 1;
297             break;
298         case GNSS_SV_TYPE_QZSS:
299             out = in.svId;
300             break;
301         case GNSS_SV_TYPE_BEIDOU:
302             out = in.svId - BDS_SV_PRN_MIN + 1;
303             break;
304         case GNSS_SV_TYPE_GALILEO:
305             out = in.svId - GAL_SV_PRN_MIN + 1;
306             break;
307         case GNSS_SV_TYPE_NAVIC:
308             /*Android doesn't define Navic svid range yet, use Naviv svid [1, 14] now
309               will update this once Android give Navic svid definiitons */
310             out = in.svId - NAVIC_SV_PRN_MIN + 1;
311             break;
312         default:
313             out = in.svId;
314             break;
315     }
316 }
317 
convertGnssSvid(GnssMeasurementsData & in,int16_t & out)318 void convertGnssSvid(GnssMeasurementsData& in, int16_t& out)
319 {
320     switch (in.svType) {
321         case GNSS_SV_TYPE_GPS:
322             out = in.svId;
323             break;
324         case GNSS_SV_TYPE_SBAS:
325             out = in.svId;
326             break;
327         case GNSS_SV_TYPE_GLONASS:
328             if (in.svId != 255) { // OSN is known
329                 out = in.svId - GLO_SV_PRN_MIN + 1;
330             } else { // OSN is not known, report FCN
331                 out = in.gloFrequency + 92;
332             }
333             break;
334         case GNSS_SV_TYPE_QZSS:
335             out = in.svId;
336             break;
337         case GNSS_SV_TYPE_BEIDOU:
338             out = in.svId - BDS_SV_PRN_MIN + 1;
339             break;
340         case GNSS_SV_TYPE_GALILEO:
341             out = in.svId - GAL_SV_PRN_MIN + 1;
342             break;
343         case GNSS_SV_TYPE_NAVIC:
344             /*Android doesn't define Navic svid range yet, use Naviv svid [1, 14] now
345               will update this once Android give Navic svid definiitons */
346             out = in.svId - NAVIC_SV_PRN_MIN + 1;
347             break;
348         default:
349             out = in.svId;
350             break;
351     }
352 }
353 
convertGnssEphemerisType(GnssEphemerisType & in,GnssDebug::SatelliteEphemerisType & out)354 void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
355 {
356     switch(in) {
357         case GNSS_EPH_TYPE_EPHEMERIS:
358             out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
359             break;
360         case GNSS_EPH_TYPE_ALMANAC:
361             out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
362             break;
363         case GNSS_EPH_TYPE_UNKNOWN:
364         default:
365             out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
366             break;
367     }
368 }
369 
convertGnssEphemerisSource(GnssEphemerisSource & in,GnssDebug::SatelliteEphemerisSource & out)370 void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
371 {
372     switch(in) {
373         case GNSS_EPH_SOURCE_DEMODULATED:
374             out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
375             break;
376         case GNSS_EPH_SOURCE_SUPL_PROVIDED:
377             out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
378             break;
379         case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
380             out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
381             break;
382         case GNSS_EPH_SOURCE_LOCAL:
383         case GNSS_EPH_SOURCE_UNKNOWN:
384         default:
385             out = GnssDebug::SatelliteEphemerisSource::OTHER;
386             break;
387     }
388 }
389 
convertGnssEphemerisHealth(GnssEphemerisHealth & in,GnssDebug::SatelliteEphemerisHealth & out)390 void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
391 {
392     switch(in) {
393         case GNSS_EPH_HEALTH_GOOD:
394             out = GnssDebug::SatelliteEphemerisHealth::GOOD;
395             break;
396         case GNSS_EPH_HEALTH_BAD:
397             out = GnssDebug::SatelliteEphemerisHealth::BAD;
398             break;
399         case GNSS_EPH_HEALTH_UNKNOWN:
400         default:
401             out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
402             break;
403     }
404 }
405 
convertSingleSatCorrections(const SingleSatCorrection & in,GnssSingleSatCorrection & out)406 void convertSingleSatCorrections(const SingleSatCorrection& in, GnssSingleSatCorrection& out)
407 {
408     out.flags = GNSS_MEAS_CORR_UNKNOWN_BIT;
409     if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY)) {
410         out.flags |= GNSS_MEAS_CORR_HAS_SAT_IS_LOS_PROBABILITY_BIT;
411     }
412     if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH)) {
413         out.flags |= GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_BIT;
414     }
415     if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC)) {
416         out.flags |= GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_UNC_BIT;
417     }
418     if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE)) {
419         out.flags |= GNSS_MEAS_CORR_HAS_REFLECTING_PLANE_BIT;
420     }
421     switch (in.constellation) {
422     case (::android::hardware::gnss::V1_0::GnssConstellationType::GPS):
423         out.svType = GNSS_SV_TYPE_GPS;
424         break;
425     case (::android::hardware::gnss::V1_0::GnssConstellationType::SBAS):
426         out.svType = GNSS_SV_TYPE_SBAS;
427         break;
428     case (::android::hardware::gnss::V1_0::GnssConstellationType::GLONASS):
429         out.svType = GNSS_SV_TYPE_GLONASS;
430         break;
431     case (::android::hardware::gnss::V1_0::GnssConstellationType::QZSS):
432         out.svType = GNSS_SV_TYPE_QZSS;
433         break;
434     case (::android::hardware::gnss::V1_0::GnssConstellationType::BEIDOU):
435         out.svType = GNSS_SV_TYPE_BEIDOU;
436         break;
437     case (::android::hardware::gnss::V1_0::GnssConstellationType::GALILEO):
438         out.svType = GNSS_SV_TYPE_GALILEO;
439         break;
440     case (::android::hardware::gnss::V1_0::GnssConstellationType::UNKNOWN):
441     default:
442         out.svType = GNSS_SV_TYPE_UNKNOWN;
443         break;
444     }
445     out.svId = in.svid;
446     out.carrierFrequencyHz = in.carrierFrequencyHz;
447     out.probSatIsLos = in.probSatIsLos;
448     out.excessPathLengthMeters = in.excessPathLengthMeters;
449     out.excessPathLengthUncertaintyMeters = in.excessPathLengthUncertaintyMeters;
450 
451     out.reflectingPlane.latitudeDegrees = in.reflectingPlane.latitudeDegrees;
452     out.reflectingPlane.longitudeDegrees = in.reflectingPlane.longitudeDegrees;
453     out.reflectingPlane.altitudeMeters = in.reflectingPlane.altitudeMeters;
454     out.reflectingPlane.azimuthDegrees = in.reflectingPlane.azimuthDegrees;
455 }
456 
convertMeasurementCorrections(const MeasurementCorrectionsV1_0 & in,GnssMeasurementCorrections & out)457 void convertMeasurementCorrections(const MeasurementCorrectionsV1_0& in,
458                                    GnssMeasurementCorrections& out)
459 {
460     memset(&out, 0, sizeof(GnssMeasurementCorrections));
461     out.latitudeDegrees = in.latitudeDegrees;
462     out.longitudeDegrees = in.longitudeDegrees;
463     out.altitudeMeters = in.altitudeMeters;
464     out.horizontalPositionUncertaintyMeters = in.horizontalPositionUncertaintyMeters;
465     out.verticalPositionUncertaintyMeters = in.verticalPositionUncertaintyMeters;
466     out.toaGpsNanosecondsOfWeek = in.toaGpsNanosecondsOfWeek;
467 
468     for (int i = 0; i < in.satCorrections.size(); i++) {
469         GnssSingleSatCorrection gnssSingleSatCorrection;
470 
471         convertSingleSatCorrections(in.satCorrections[i], gnssSingleSatCorrection);
472         out.satCorrections.push_back(gnssSingleSatCorrection);
473     }
474 }
475 
476 }  // namespace implementation
477 }  // namespace V2_1
478 }  // namespace gnss
479 }  // namespace hardware
480 }  // namespace android
481