GnssNavigationMessage.java revision e8abe8e5ad830bd130b258c6801d75f6542200b5
1/*
2 * Copyright (C) 2014 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
17package android.location;
18
19import android.annotation.TestApi;
20import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.os.Parcel;
23import android.os.Parcelable;
24
25import java.lang.annotation.Retention;
26import java.lang.annotation.RetentionPolicy;
27import java.security.InvalidParameterException;
28
29/**
30 * A class containing a GNSS satellite Navigation Message.
31 */
32public final class GnssNavigationMessage implements Parcelable {
33
34    private static final byte[] EMPTY_ARRAY = new byte[0];
35
36    /**
37     * The type of the GNSS Navigation Message
38     * @hide
39     */
40    @Retention(RetentionPolicy.SOURCE)
41    @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2,
42        TYPE_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F})
43    public @interface GnssNavigationMessageType {}
44
45    // The following enumerations must be in sync with the values declared in gps.h
46
47    /** Message type unknown */
48    public static final int TYPE_UNKNOWN = 0;
49    /** GPS L1 C/A message contained in the structure.  */
50    public static final int TYPE_GPS_L1CA = 0x0101;
51    /** GPS L2-CNAV message contained in the structure. */
52    public static final int TYPE_GPS_L2CNAV = 0x0102;
53    /** GPS L5-CNAV message contained in the structure. */
54    public static final int TYPE_GPS_L5CNAV = 0x0103;
55    /** GPS CNAV-2 message contained in the structure. */
56    public static final int TYPE_GPS_CNAV2 = 0x0104;
57    /** Glonass L1 CA message contained in the structure. */
58    public static final int TYPE_GLO_L1CA = 0x0301;
59    /** Beidou D1 message contained in the structure. */
60    public static final int TYPE_BDS_D1 = 0x0501;
61    /** Beidou D2 message contained in the structure. */
62    public static final int TYPE_BDS_D2 = 0x0502;
63    /** Galileo I/NAV message contained in the structure. */
64    public static final int TYPE_GAL_I = 0x0601;
65    /** Galileo F/NAV message contained in the structure. */
66    public static final int TYPE_GAL_F = 0x0602;
67
68    /**
69     * The Navigation Message Status is 'unknown'.
70     */
71    public static final int STATUS_UNKNOWN = 0;
72
73    /**
74     * The Navigation Message was received without any parity error in its navigation words.
75     */
76    public static final int STATUS_PARITY_PASSED = (1<<0);
77
78    /**
79     * The Navigation Message was received with words that failed parity check, but the receiver was
80     * able to correct those words.
81     */
82    public static final int STATUS_PARITY_REBUILT = (1<<1);
83
84    /**
85     * Used for receiving GNSS satellite Navigation Messages from the GNSS engine.
86     *
87     * <p>You can implement this interface and call
88     * {@link LocationManager#registerGnssNavigationMessageCallback}.
89     */
90    public static abstract class Callback {
91        /**
92         * The status of GNSS measurements event.
93         * @hide
94         */
95        @Retention(RetentionPolicy.SOURCE)
96        @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED})
97        public @interface GnssNavigationMessageStatus {}
98
99        /**
100         * The system does not support tracking of GNSS Navigation Messages.
101         *
102         * This status will not change in the future.
103         */
104        public static final int STATUS_NOT_SUPPORTED = 0;
105
106        /**
107         * GNSS Navigation Messages are successfully being tracked, it will receive updates once
108         * they are available.
109         */
110        public static final int STATUS_READY = 1;
111
112        /**
113         * GNSS provider or Location is disabled, updated will not be received until they are
114         * enabled.
115         */
116        public static final int STATUS_LOCATION_DISABLED = 2;
117
118        /**
119         * Returns the latest collected GNSS Navigation Message.
120         */
121        public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {}
122
123        /**
124         * Returns the latest status of the GNSS Navigation Messages sub-system.
125         */
126        public void onStatusChanged(@GnssNavigationMessageStatus int status) {}
127    }
128
129    // End enumerations in sync with gps.h
130
131    private int mType;
132    private int mSvid;
133    private int mMessageId;
134    private int mSubmessageId;
135    private byte[] mData;
136    private int mStatus;
137
138    /**
139     * @hide
140     */
141    @TestApi
142    public GnssNavigationMessage() {
143        initialize();
144    }
145
146    /**
147     * Sets all contents to the values stored in the provided object.
148     * @hide
149     */
150    @TestApi
151    public void set(GnssNavigationMessage navigationMessage) {
152        mType = navigationMessage.mType;
153        mSvid = navigationMessage.mSvid;
154        mMessageId = navigationMessage.mMessageId;
155        mSubmessageId = navigationMessage.mSubmessageId;
156        mData = navigationMessage.mData;
157        mStatus = navigationMessage.mStatus;
158    }
159
160    /**
161     * Resets all the contents to its original state.
162     * @hide
163     */
164    @TestApi
165    public void reset() {
166        initialize();
167    }
168
169    /**
170     * Gets the type of the navigation message contained in the object.
171     */
172    @GnssNavigationMessageType
173    public int getType() {
174        return mType;
175    }
176
177    /**
178     * Sets the type of the navigation message.
179     * @hide
180     */
181    @TestApi
182    public void setType(@GnssNavigationMessageType int value) {
183        mType = value;
184    }
185
186    /**
187     * Gets a string representation of the 'type'.
188     * For internal and logging use only.
189     */
190    private String getTypeString() {
191        switch (mType) {
192            case TYPE_UNKNOWN:
193                return "Unknown";
194            case TYPE_GPS_L1CA:
195                return "GPS L1 C/A";
196            case TYPE_GPS_L2CNAV:
197                return "GPS L2-CNAV";
198            case TYPE_GPS_L5CNAV:
199                return "GPS L5-CNAV";
200            case TYPE_GPS_CNAV2:
201                return "GPS CNAV2";
202            case TYPE_GLO_L1CA:
203                return "Glonass L1 C/A";
204            case TYPE_BDS_D1:
205                return "Beidou D1";
206            case TYPE_BDS_D2:
207                return "Beidou D2";
208            case TYPE_GAL_I:
209                return "Galileo I";
210            case TYPE_GAL_F:
211                return "Galileo F";
212            default:
213                return "<Invalid:" + mType + ">";
214        }
215    }
216
217    /**
218     * Gets the satellite ID.
219     *
220     * <p>Range varies by constellation.  See definition at {@code GnssStatus#getSvid(int)}
221     */
222    public int getSvid() {
223        return mSvid;
224    }
225
226    /**
227     * Sets the satellite ID.
228     * @hide
229     */
230    @TestApi
231    public void setSvid(int value) {
232        mSvid = value;
233    }
234
235    /**
236     * Gets the Message identifier.
237     *
238     * <p>This provides an index to help with complete Navigation Message assembly. Similar
239     * identifiers within the data bits themselves often supplement this information, in ways even
240     * more specific to each message type; see the relevant satellite constellation ICDs for
241     * details.
242     *
243     * <ul>
244     * <li> For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame id' of the
245     * navigation message, in the range of 1-25 (Subframe 1, 2, 3 does not contain a 'frame id' and
246     * this value can be set to -1.)</li>
247     * <li> For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.</li>
248     * <li> For BeiDou D1, this refers to the frame number in the range of 1-24</li>
249     * <li> For Beidou D2, this refers to the frame number, in the range of 1-120</li>
250     * <li> For Galileo F/NAV nominal frame structure, this refers to the subframe number, in the
251     * range of 1-12</li>
252     * <li> For Galileo I/NAV nominal frame structure, this refers to the subframe number in the
253     * range of 1-24</li>
254     * </ul>
255     */
256    public int getMessageId() {
257        return mMessageId;
258    }
259
260    /**
261     * Sets the Message Identifier.
262     * @hide
263     */
264    @TestApi
265    public void setMessageId(int value) {
266        mMessageId = value;
267    }
268
269    /**
270     * Gets the sub-message identifier, relevant to the {@link #getType()} of the message.
271     *
272     * <ul>
273     * <li> For GPS L1 C/A, BeiDou D1 &amp; BeiDou D2, the submessage id corresponds to the subframe
274     * number of the navigation message, in the range of 1-5.</li>
275     * <li>For Glonass L1 C/A, this refers to the String number, in the range from 1-15</li>
276     * <li>For Galileo F/NAV, this refers to the page type in the range 1-6</li>
277     * <li>For Galileo I/NAV, this refers to the word type in the range 1-10+</li>
278     * <li>For Galileo in particular, the type information embedded within the data bits may be even
279     * more useful in interpretation, than the nominal page and word types provided in this
280     * field.</li>
281     * </ul>
282     */
283    public int getSubmessageId() {
284        return mSubmessageId;
285    }
286
287    /**
288     * Sets the Sub-message identifier.
289     * @hide
290     */
291    @TestApi
292    public void setSubmessageId(int value) {
293        mSubmessageId = value;
294    }
295
296    /**
297     * Gets the data of the reported GPS message.
298     *
299     * <p>The bytes (or words) specified using big endian format (MSB first).
300     *
301     * <ul>
302     * <li>For GPS L1 C/A, Beidou D1 &amp; Beidou D2, each subframe contains 10 30-bit words. Each
303     * word (30 bits) should be fit into the last 30 bits in a 4-byte word (skip B31 and B32), with
304     * MSB first, for a total of 40 bytes, covering a time period of 6, 6, and 0.6 seconds,
305     * respectively.</li>
306     * <li>For Glonass L1 C/A, each string contains 85 data bits, including the checksum.  These
307     * bits should be fit into 11 bytes, with MSB first (skip B86-B88), covering a time period of 2
308     * seconds.</li>
309     * <li>For Galileo F/NAV, each word consists of 238-bit (sync &amp; tail symbols excluded). Each
310     * word should be fit into 30-bytes, with MSB first (skip B239, B240), covering a time period of
311     * 10 seconds.</li>
312     * <li>For Galileo I/NAV, each page contains 2 page parts, even and odd, with a total of 2x114 =
313     * 228 bits, (sync &amp; tail excluded) that should be fit into 29 bytes, with MSB first (skip
314     * B229-B232).</li>
315     * </ul>
316     */
317    @NonNull
318    public byte[] getData() {
319        return mData;
320    }
321
322    /**
323     * Sets the data associated with the Navigation Message.
324     * @hide
325     */
326    @TestApi
327    public void setData(byte[] value) {
328        if (value == null) {
329            throw new InvalidParameterException("Data must be a non-null array");
330        }
331
332        mData = value;
333    }
334
335    /**
336     * Gets the Status of the navigation message contained in the object.
337     */
338    public int getStatus() {
339        return mStatus;
340    }
341
342    /**
343     * Sets the status of the navigation message.
344     * @hide
345     */
346    @TestApi
347    public void setStatus(int value) {
348        mStatus = value;
349    }
350
351    /**
352     * Gets a string representation of the 'status'.
353     * For internal and logging use only.
354     */
355    private String getStatusString() {
356        switch (mStatus) {
357            case STATUS_UNKNOWN:
358                return "Unknown";
359            case STATUS_PARITY_PASSED:
360                return "ParityPassed";
361            case STATUS_PARITY_REBUILT:
362                return "ParityRebuilt";
363            default:
364                return "<Invalid:" + mStatus + ">";
365        }
366    }
367
368    public static final Creator<GnssNavigationMessage> CREATOR =
369            new Creator<GnssNavigationMessage>() {
370        @Override
371        public GnssNavigationMessage createFromParcel(Parcel parcel) {
372            GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
373
374            navigationMessage.setType(parcel.readInt());
375            navigationMessage.setSvid(parcel.readInt());
376            navigationMessage.setMessageId(parcel.readInt());
377            navigationMessage.setSubmessageId(parcel.readInt());
378            int dataLength = parcel.readInt();
379            byte[] data = new byte[dataLength];
380            parcel.readByteArray(data);
381            navigationMessage.setData(data);
382            navigationMessage.setStatus(parcel.readInt());
383
384            return navigationMessage;
385        }
386
387        @Override
388        public GnssNavigationMessage[] newArray(int size) {
389            return new GnssNavigationMessage[size];
390        }
391    };
392
393    @Override
394    public void writeToParcel(Parcel parcel, int flags) {
395        parcel.writeInt(mType);
396        parcel.writeInt(mSvid);
397        parcel.writeInt(mMessageId);
398        parcel.writeInt(mSubmessageId);
399        parcel.writeInt(mData.length);
400        parcel.writeByteArray(mData);
401        parcel.writeInt(mStatus);
402    }
403
404    @Override
405    public int describeContents() {
406        return 0;
407    }
408
409    @Override
410    public String toString() {
411        final String format = "   %-15s = %s\n";
412        StringBuilder builder = new StringBuilder("GnssNavigationMessage:\n");
413
414        builder.append(String.format(format, "Type", getTypeString()));
415        builder.append(String.format(format, "Svid", mSvid));
416        builder.append(String.format(format, "Status", getStatusString()));
417        builder.append(String.format(format, "MessageId", mMessageId));
418        builder.append(String.format(format, "SubmessageId", mSubmessageId));
419
420        builder.append(String.format(format, "Data", "{"));
421        String prefix = "        ";
422        for(byte value : mData) {
423            builder.append(prefix);
424            builder.append(value);
425            prefix = ", ";
426        }
427        builder.append(" }");
428
429        return builder.toString();
430    }
431
432    private void initialize() {
433        mType = TYPE_UNKNOWN;
434        mSvid = 0;
435        mMessageId = -1;
436        mSubmessageId = -1;
437        mData = EMPTY_ARRAY;
438        mStatus = STATUS_UNKNOWN;
439    }
440}
441