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