Home | History | Annotate | Download | only in location
      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 
     17 package android.location;
     18 
     19 import android.annotation.TestApi;
     20 import android.annotation.IntDef;
     21 import android.annotation.NonNull;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 
     25 import java.lang.annotation.Retention;
     26 import java.lang.annotation.RetentionPolicy;
     27 import java.security.InvalidParameterException;
     28 
     29 /**
     30  * A class containing a GNSS satellite Navigation Message.
     31  */
     32 public 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 Navigation Message 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