1 /* 2 * Copyright (C) 2023 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 package com.google.uwb.support.fira; 17 18 import android.os.PersistableBundle; 19 import android.uwb.UwbAddress; 20 21 import androidx.annotation.Nullable; 22 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Uwb data transfer phase configuration 30 */ 31 public class FiraDataTransferPhaseConfig extends FiraParams { 32 private static final int BUNDLE_VERSION_1 = 1; 33 private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1; 34 private static final int SHORT_MAC_ADDRESS = 0; 35 36 private final byte mDtpcmRepetition; 37 private final byte mDataTransferControl; 38 private final List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList; 39 40 private static final String KEY_BUNDLE_VERSION = "bundle_version"; 41 private static final String KEY_DTPCM_REPETITION = "dtpcm_repetition"; 42 private static final String KEY_DATA_TRANSFER_CONTROL = "data_transfer_control"; 43 private static final String KEY_MAC_ADDRESS_LIST = "mac_address"; 44 private static final String KEY_SLOT_BITMAP = "slot_bitmap"; 45 private static final String KEY_STOP_DATA_TRANSFER = "stop_data_transfer"; 46 47 @Override getBundleVersion()48 public int getBundleVersion() { 49 return BUNDLE_VERSION_CURRENT; 50 } 51 getDtpcmRepetition()52 public byte getDtpcmRepetition() { 53 return mDtpcmRepetition; 54 } 55 getDataTransferControl()56 public byte getDataTransferControl() { 57 return mDataTransferControl; 58 } 59 getDataTransferPhaseManagementList()60 public List<FiraDataTransferPhaseManagementList> getDataTransferPhaseManagementList() { 61 return mDataTransferPhaseManagementList; 62 } 63 FiraDataTransferPhaseConfig(byte dtpcmRepetition, byte dataTransferControl, List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList)64 private FiraDataTransferPhaseConfig(byte dtpcmRepetition, byte dataTransferControl, 65 List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList) { 66 mDtpcmRepetition = dtpcmRepetition; 67 mDataTransferControl = dataTransferControl; 68 mDataTransferPhaseManagementList = dataTransferPhaseManagementList; 69 } 70 71 @Override toBundle()72 public PersistableBundle toBundle() { 73 PersistableBundle bundle = super.toBundle(); 74 bundle.putInt(KEY_BUNDLE_VERSION, getBundleVersion()); 75 bundle.putInt(KEY_DTPCM_REPETITION, mDtpcmRepetition); 76 bundle.putInt(KEY_DATA_TRANSFER_CONTROL, mDataTransferControl); 77 78 int dataTransferPhaseManagementListSize = mDataTransferPhaseManagementList.size(); 79 long[] macAddressList = new long[dataTransferPhaseManagementListSize]; 80 int i = 0; 81 ByteBuffer slotBitmapByteBuffer = ByteBuffer.allocate(dataTransferPhaseManagementListSize 82 * (1 << ((mDataTransferControl & 0x0F) >> 1))); 83 84 slotBitmapByteBuffer.order(ByteOrder.LITTLE_ENDIAN); 85 ByteBuffer stopDataTransferBuffer = 86 ByteBuffer.allocate(dataTransferPhaseManagementListSize); 87 88 for (FiraDataTransferPhaseManagementList dataTransferPhaseManagementList : 89 mDataTransferPhaseManagementList) { 90 macAddressList[i++] = uwbAddressToLong( 91 dataTransferPhaseManagementList.getUwbAddress()); 92 slotBitmapByteBuffer.put(dataTransferPhaseManagementList.getSlotBitMap()); 93 stopDataTransferBuffer.put(dataTransferPhaseManagementList.getStopDataTransfer()); 94 } 95 96 bundle.putLongArray(KEY_MAC_ADDRESS_LIST, macAddressList); 97 bundle.putIntArray(KEY_SLOT_BITMAP, byteArrayToIntArray(slotBitmapByteBuffer.array())); 98 bundle.putIntArray(KEY_STOP_DATA_TRANSFER, byteArrayToIntArray( 99 stopDataTransferBuffer.array())); 100 101 return bundle; 102 } 103 104 @Nullable byteArrayToIntArray(@ullable byte[] bytes)105 protected static int[] byteArrayToIntArray(@Nullable byte[] bytes) { 106 if (bytes == null) { 107 return null; 108 } 109 110 int[] values = new int[bytes.length]; 111 for (int i = 0; i < values.length; i++) { 112 values[i] = bytes[i]; 113 } 114 return values; 115 } 116 117 @Nullable intArrayToByteArray(@ullable int[] values)118 protected static byte[] intArrayToByteArray(@Nullable int[] values) { 119 if (values == null) { 120 return null; 121 } 122 byte[] bytes = new byte[values.length]; 123 for (int i = 0; i < values.length; i++) { 124 bytes[i] = (byte) values[i]; 125 } 126 return bytes; 127 } 128 fromBundle(PersistableBundle bundle)129 public static FiraDataTransferPhaseConfig fromBundle(PersistableBundle bundle) { 130 switch (bundle.getInt(KEY_BUNDLE_VERSION)) { 131 case BUNDLE_VERSION_1: 132 return parseVersion1(bundle); 133 default: 134 throw new IllegalArgumentException("Invalid bundle version"); 135 } 136 } 137 parseVersion1(PersistableBundle bundle)138 private static FiraDataTransferPhaseConfig parseVersion1(PersistableBundle bundle) { 139 FiraDataTransferPhaseConfig.Builder builder = new FiraDataTransferPhaseConfig.Builder(); 140 141 builder.setDtpcmRepetition((byte) bundle.getInt(KEY_DTPCM_REPETITION)); 142 byte dataTransferControl = (byte) bundle.getInt(KEY_DATA_TRANSFER_CONTROL); 143 builder.setMacAddressMode((byte) (dataTransferControl & 0x01)); 144 builder.setSlotBitmapSize((byte) ((dataTransferControl & 0x0F) >> 1)); 145 146 List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList = 147 new ArrayList<>(); 148 List<UwbAddress> macAddressList = new ArrayList<>(); 149 List<byte[]> slotBitmapList = new ArrayList<>(); 150 List<Byte> stopDataTransferList = new ArrayList<>(); 151 long[] macAddress = bundle.getLongArray(KEY_MAC_ADDRESS_LIST); 152 for (int i = 0; i < macAddress.length; i++) { 153 macAddressList.add(longToUwbAddress(macAddress[i], 154 ((dataTransferControl & 0x01) == SHORT_MAC_ADDRESS) 155 ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH 156 : UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH)); 157 } 158 159 byte[] buffer = intArrayToByteArray(bundle.getIntArray(KEY_SLOT_BITMAP)); 160 ByteBuffer slotBitmapByteBuffer = ByteBuffer.wrap(buffer); 161 int chunkBufferSize = 1 << (dataTransferControl >> 1); 162 163 while (slotBitmapByteBuffer.hasRemaining()) { 164 byte[] data = new byte[chunkBufferSize]; 165 int bytesToRead = Math.min(chunkBufferSize, slotBitmapByteBuffer.remaining()); 166 slotBitmapByteBuffer.get(data, 0, bytesToRead); 167 slotBitmapList.add(data); 168 } 169 170 byte[] stopBuffer = intArrayToByteArray(bundle.getIntArray(KEY_STOP_DATA_TRANSFER)); 171 for (int i = 0; i < stopBuffer.length; i++) { 172 stopDataTransferList.add(stopBuffer[i]); 173 } 174 175 176 for (int i = 0; i < macAddressList.size(); i++) { 177 mDataTransferPhaseManagementList.add(new FiraDataTransferPhaseManagementList( 178 macAddressList.get(i), slotBitmapList.get(i), stopDataTransferList.get(i))); 179 } 180 181 builder.setDataTransferPhaseManagementList(mDataTransferPhaseManagementList); 182 183 return builder.build(); 184 } 185 186 /** Defines parameters for data transfer phase management list */ 187 public static class FiraDataTransferPhaseManagementList { 188 private final UwbAddress mUwbAddress; 189 private final byte[] mSlotBitMap; 190 private final byte mStopDataTransfer; 191 FiraDataTransferPhaseManagementList(UwbAddress uwbAddress, byte[] slotBitmap, byte stopDataTransfer)192 public FiraDataTransferPhaseManagementList(UwbAddress uwbAddress, byte[] slotBitmap, 193 byte stopDataTransfer) { 194 mUwbAddress = uwbAddress; 195 mSlotBitMap = slotBitmap; 196 mStopDataTransfer = stopDataTransfer; 197 } 198 getUwbAddress()199 public UwbAddress getUwbAddress() { 200 return mUwbAddress; 201 } 202 getSlotBitMap()203 public byte[] getSlotBitMap() { 204 return mSlotBitMap; 205 } getStopDataTransfer()206 public byte getStopDataTransfer() { 207 return mStopDataTransfer; 208 } 209 } 210 211 /** Builder */ 212 public static class Builder { 213 private byte mDtpcmRepetition; 214 private byte mMacAddressMode; 215 private byte mSlotBitMapSize; 216 private List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList = 217 new ArrayList<>(); 218 setDtpcmRepetition(byte dtpcmRepetition)219 public FiraDataTransferPhaseConfig.Builder setDtpcmRepetition(byte dtpcmRepetition) { 220 mDtpcmRepetition = dtpcmRepetition; 221 return this; 222 } 223 setMacAddressMode(byte macAddressMode)224 public FiraDataTransferPhaseConfig.Builder setMacAddressMode(byte macAddressMode) { 225 mMacAddressMode = macAddressMode; 226 return this; 227 } 228 setSlotBitmapSize(byte slotBitmapSize)229 public FiraDataTransferPhaseConfig.Builder setSlotBitmapSize(byte slotBitmapSize) { 230 mSlotBitMapSize = slotBitmapSize; 231 return this; 232 } 233 setDataTransferPhaseManagementList( List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList)234 public FiraDataTransferPhaseConfig.Builder setDataTransferPhaseManagementList( 235 List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList) { 236 mDataTransferPhaseManagementList = dataTransferPhaseManagementList; 237 return this; 238 } 239 build()240 public FiraDataTransferPhaseConfig build() { 241 return new FiraDataTransferPhaseConfig( 242 mDtpcmRepetition, 243 (byte) ((mSlotBitMapSize << 1) | (mMacAddressMode & 0x01)), 244 mDataTransferPhaseManagementList); 245 } 246 } 247 } 248