1 /* 2 * Copyright (C) 2022 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 com.google.uwb.support.dltdoa; 18 19 import android.os.PersistableBundle; 20 import android.uwb.RangingMeasurement; 21 22 import androidx.annotation.Nullable; 23 24 /** 25 * DlTDoA measurement values 26 * 27 * <p> This is passed as a bundle with RangingMeasurement for mRangingReportMetadata 28 * {@link RangingMeasurement#getRangingMeasurementMetadata()} This will be passed for sessions 29 * with DL-TDoA measurements only. For other sessions, the metadata will contain something else 30 */ 31 public class DlTDoAMeasurement { 32 private final int mMessageType; 33 private final int mMessageControl; 34 private final int mBlockIndex; 35 private final int mRoundIndex; 36 private final int mNLoS; 37 private final long mTxTimestamp; 38 private final long mRxTimestamp; 39 private final float mAnchorCfo; 40 private final float mCfo; 41 private final long mInitiatorReplyTime; 42 private final long mResponderReplyTime; 43 private final int mInitiatorResponderTof; 44 private final byte[] mAnchorLocation; 45 private final byte[] mActiveRangingRounds; 46 47 public static final String KEY_BUNDLE_VERSION = "bundle_version"; 48 public static final String MESSAGE_TYPE = "message_type"; 49 public static final String MESSAGE_CONTROL = "message_control"; 50 public static final String BLOCK_INDEX = "block_index"; 51 public static final String ROUND_INDEX = "round_index"; 52 public static final String NLOS = "nlos"; 53 public static final String RSSI = "rssi"; 54 public static final String TX_TIMESTAMP = "tx_timestamp"; 55 public static final String RX_TIMESTAMP = "rx_timestamp"; 56 public static final String ANCHOR_CFO = "anchor_cfo"; 57 public static final String CFO = "cfo"; 58 public static final String INITIATOR_REPLY_TIME = "initiator_reply_time"; 59 public static final String RESPONDER_REPLY_TIME = "responder_reply_time"; 60 public static final String INITIATOR_RESPONDER_TOF = "initiator_responder_time"; 61 public static final String ANCHOR_LOCATION = "anchor_location"; 62 public static final String ACTIVE_RANGING_ROUNDS = "active_ranging_rounds"; 63 64 private static final int BUNDLE_VERSION_1 = 1; 65 private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1; 66 DlTDoAMeasurement(int messageType, int messageControl, int blockIndex, int roundIndex, int NLoS, long txTimestamp, long rxTimestamp, float anchorCfo, float cfo, long initiatorReplyTime, long responderReplyTime, int initiatorResponderTof, byte[] anchorLocation, byte[] activeRangingRounds)67 public DlTDoAMeasurement(int messageType, int messageControl, int blockIndex, int roundIndex, 68 int NLoS, long txTimestamp, long rxTimestamp, float anchorCfo, float cfo, 69 long initiatorReplyTime, long responderReplyTime, int initiatorResponderTof, 70 byte[] anchorLocation, byte[] activeRangingRounds) { 71 mMessageType = messageType; 72 mMessageControl = messageControl; 73 mBlockIndex = blockIndex; 74 mRoundIndex = roundIndex; 75 mNLoS = NLoS; 76 mTxTimestamp = txTimestamp; 77 mRxTimestamp = rxTimestamp; 78 mAnchorCfo = anchorCfo; 79 mCfo = cfo; 80 mInitiatorReplyTime = initiatorReplyTime; 81 mResponderReplyTime = responderReplyTime; 82 mInitiatorResponderTof = initiatorResponderTof; 83 mAnchorLocation = anchorLocation; 84 mActiveRangingRounds = activeRangingRounds; 85 } 86 getBundleVersion()87 protected int getBundleVersion() { 88 return BUNDLE_VERSION_CURRENT; 89 } 90 getMessageType()91 public int getMessageType() { 92 return mMessageType; 93 } 94 getMessageControl()95 public int getMessageControl() { 96 return mMessageControl; 97 } 98 getBlockIndex()99 public int getBlockIndex() { 100 return mBlockIndex; 101 } 102 getRoundIndex()103 public int getRoundIndex() { 104 return mRoundIndex; 105 } 106 getNLoS()107 public int getNLoS() { 108 return mNLoS; 109 } 110 getTxTimestamp()111 public long getTxTimestamp() { 112 return mTxTimestamp; 113 } 114 getRxTimestamp()115 public long getRxTimestamp() { 116 return mRxTimestamp; 117 } 118 getAnchorCfo()119 public float getAnchorCfo() { 120 return mAnchorCfo; 121 } 122 getCfo()123 public float getCfo() { 124 return mCfo; 125 } 126 getInitiatorReplyTime()127 public long getInitiatorReplyTime() { 128 return mInitiatorReplyTime; 129 } 130 getResponderReplyTime()131 public long getResponderReplyTime() { 132 return mResponderReplyTime; 133 } 134 getInitiatorResponderTof()135 public int getInitiatorResponderTof() { 136 return mInitiatorResponderTof; 137 } 138 getAnchorLocation()139 public byte[] getAnchorLocation() { 140 return mAnchorLocation; 141 } 142 getActiveRangingRounds()143 public byte[] getActiveRangingRounds() { 144 return mActiveRangingRounds; 145 } 146 147 @Nullable byteArrayToIntArray(@ullable byte[] bytes)148 private static int[] byteArrayToIntArray(@Nullable byte[] bytes) { 149 if (bytes == null) { 150 return null; 151 } 152 int[] values = new int[bytes.length]; 153 for (int i = 0; i < values.length; i++) { 154 values[i] = (bytes[i]); 155 } 156 return values; 157 } 158 159 @Nullable intArrayToByteArray(@ullable int[] values)160 private static byte[] intArrayToByteArray(@Nullable int[] values) { 161 if (values == null) { 162 return null; 163 } 164 byte[] bytes = new byte[values.length]; 165 for (int i = 0; i < values.length; i++) { 166 bytes[i] = (byte) values[i]; 167 } 168 return bytes; 169 } 170 isDlTDoAMeasurement(PersistableBundle bundle)171 public static boolean isDlTDoAMeasurement(PersistableBundle bundle) { 172 return bundle.containsKey(ANCHOR_LOCATION) && bundle.containsKey(ACTIVE_RANGING_ROUNDS); 173 } 174 toBundle()175 public PersistableBundle toBundle() { 176 PersistableBundle bundle = new PersistableBundle(); 177 bundle.putInt(KEY_BUNDLE_VERSION, BUNDLE_VERSION_CURRENT); 178 bundle.putInt(MESSAGE_TYPE, mMessageType); 179 bundle.putInt(MESSAGE_CONTROL, mMessageControl); 180 bundle.putInt(BLOCK_INDEX, mBlockIndex); 181 bundle.putInt(ROUND_INDEX, mRoundIndex); 182 bundle.putInt(NLOS, mNLoS); 183 bundle.putLong(TX_TIMESTAMP, mTxTimestamp); 184 bundle.putLong(RX_TIMESTAMP, mRxTimestamp); 185 bundle.putDouble(ANCHOR_CFO, mAnchorCfo); 186 bundle.putDouble(CFO, mCfo); 187 bundle.putLong(INITIATOR_REPLY_TIME, mInitiatorReplyTime); 188 bundle.putLong(RESPONDER_REPLY_TIME, mResponderReplyTime); 189 bundle.putInt(INITIATOR_RESPONDER_TOF, mInitiatorResponderTof); 190 bundle.putIntArray(ANCHOR_LOCATION, byteArrayToIntArray(mAnchorLocation)); 191 bundle.putIntArray(ACTIVE_RANGING_ROUNDS, byteArrayToIntArray(mActiveRangingRounds)); 192 return bundle; 193 } 194 fromBundle(PersistableBundle bundle)195 public static DlTDoAMeasurement fromBundle(PersistableBundle bundle) { 196 switch (bundle.getInt(KEY_BUNDLE_VERSION)) { 197 case BUNDLE_VERSION_1: 198 return parseVersion1(bundle); 199 default: 200 throw new IllegalArgumentException("Invalid bundle version"); 201 } 202 } 203 parseVersion1(PersistableBundle bundle)204 private static DlTDoAMeasurement parseVersion1(PersistableBundle bundle) { 205 return new DlTDoAMeasurement.Builder() 206 .setMessageType(bundle.getInt(MESSAGE_TYPE)) 207 .setMessageControl(bundle.getInt(MESSAGE_CONTROL)) 208 .setBlockIndex(bundle.getInt(BLOCK_INDEX)) 209 .setRoundIndex(bundle.getInt(ROUND_INDEX)) 210 .setNLoS(bundle.getInt(NLOS)) 211 .setTxTimestamp(bundle.getLong(TX_TIMESTAMP)) 212 .setRxTimestamp(bundle.getLong(RX_TIMESTAMP)) 213 .setAnchorCfo((float) bundle.getDouble(ANCHOR_CFO)) 214 .setCfo((float) bundle.getDouble(CFO)) 215 .setInitiatorReplyTime(bundle.getLong(INITIATOR_REPLY_TIME)) 216 .setResponderReplyTime(bundle.getLong(RESPONDER_REPLY_TIME)) 217 .setInitiatorResponderTof(bundle.getInt(INITIATOR_RESPONDER_TOF)) 218 .setAnchorLocation(intArrayToByteArray(bundle.getIntArray(ANCHOR_LOCATION))) 219 .setActiveRangingRounds( 220 intArrayToByteArray(bundle.getIntArray(ACTIVE_RANGING_ROUNDS))) 221 .build(); 222 } 223 224 /** Builder */ 225 public static class Builder { 226 private int mMessageType; 227 private int mMessageControl; 228 private int mBlockIndex; 229 private int mRoundIndex; 230 private int mNLoS; 231 private long mTxTimestamp; 232 private long mRxTimestamp; 233 private float mAnchorCfo; 234 private float mCfo; 235 private long mInitiatorReplyTime; 236 private long mResponderReplyTime; 237 private int mInitiatorResponderTof; 238 private byte[] mAnchorLocation; 239 private byte[] mActiveRangingRounds; 240 setMessageType(int messageType)241 public DlTDoAMeasurement.Builder setMessageType(int messageType) { 242 mMessageType = messageType; 243 return this; 244 } 245 setMessageControl(int messageControl)246 public DlTDoAMeasurement.Builder setMessageControl(int messageControl) { 247 mMessageControl = messageControl; 248 return this; 249 } 250 setBlockIndex(int blockIndex)251 public DlTDoAMeasurement.Builder setBlockIndex(int blockIndex) { 252 mBlockIndex = blockIndex; 253 return this; 254 } 255 setRoundIndex(int roundIndex)256 public DlTDoAMeasurement.Builder setRoundIndex(int roundIndex) { 257 mRoundIndex = roundIndex; 258 return this; 259 } 260 setNLoS(int nLoS)261 public DlTDoAMeasurement.Builder setNLoS(int nLoS) { 262 mNLoS = nLoS; 263 return this; 264 } 265 setTxTimestamp(long txTimestamp)266 public DlTDoAMeasurement.Builder setTxTimestamp(long txTimestamp) { 267 mTxTimestamp = txTimestamp; 268 return this; 269 } 270 setRxTimestamp(long rxTimestamp)271 public DlTDoAMeasurement.Builder setRxTimestamp(long rxTimestamp) { 272 mRxTimestamp = rxTimestamp; 273 return this; 274 } 275 setAnchorCfo(float anchorCfo)276 public DlTDoAMeasurement.Builder setAnchorCfo(float anchorCfo) { 277 mAnchorCfo = anchorCfo; 278 return this; 279 } 280 setCfo(float cfo)281 public DlTDoAMeasurement.Builder setCfo(float cfo) { 282 mCfo = cfo; 283 return this; 284 } 285 setInitiatorReplyTime(long initiatorReplyTime)286 public DlTDoAMeasurement.Builder setInitiatorReplyTime(long initiatorReplyTime) { 287 mInitiatorReplyTime = initiatorReplyTime; 288 return this; 289 } 290 setResponderReplyTime(long responderReplyTime)291 public DlTDoAMeasurement.Builder setResponderReplyTime(long responderReplyTime) { 292 mResponderReplyTime = responderReplyTime; 293 return this; 294 } 295 setInitiatorResponderTof(int initiatorResponderTof)296 public DlTDoAMeasurement.Builder setInitiatorResponderTof(int initiatorResponderTof) { 297 mInitiatorResponderTof = initiatorResponderTof; 298 return this; 299 } 300 setAnchorLocation(byte[] anchorLocation)301 public DlTDoAMeasurement.Builder setAnchorLocation(byte[] anchorLocation) { 302 mAnchorLocation = anchorLocation; 303 return this; 304 } 305 setActiveRangingRounds(byte[] activeRangingRounds)306 public DlTDoAMeasurement.Builder setActiveRangingRounds(byte[] activeRangingRounds) { 307 mActiveRangingRounds = activeRangingRounds; 308 return this; 309 } 310 build()311 public DlTDoAMeasurement build() { 312 return new DlTDoAMeasurement( 313 mMessageType, 314 mMessageControl, 315 mBlockIndex, 316 mRoundIndex, 317 mNLoS, 318 mTxTimestamp, 319 mRxTimestamp, 320 mAnchorCfo, 321 mCfo, 322 mInitiatorReplyTime, 323 mResponderReplyTime, 324 mInitiatorResponderTof, 325 mAnchorLocation, 326 mActiveRangingRounds); 327 } 328 } 329 } 330