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