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 46 @Override getBundleVersion()47 public int getBundleVersion() { 48 return BUNDLE_VERSION_CURRENT; 49 } 50 getDtpcmRepetition()51 public byte getDtpcmRepetition() { 52 return mDtpcmRepetition; 53 } 54 getDataTransferControl()55 public byte getDataTransferControl() { 56 return mDataTransferControl; 57 } 58 getDataTransferPhaseManagementList()59 public List<FiraDataTransferPhaseManagementList> getDataTransferPhaseManagementList() { 60 return mDataTransferPhaseManagementList; 61 } 62 FiraDataTransferPhaseConfig(byte dtpcmRepetition, byte dataTransferControl, List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList)63 private FiraDataTransferPhaseConfig(byte dtpcmRepetition, byte dataTransferControl, 64 List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList) { 65 mDtpcmRepetition = dtpcmRepetition; 66 mDataTransferControl = dataTransferControl; 67 mDataTransferPhaseManagementList = dataTransferPhaseManagementList; 68 } 69 70 @Override toBundle()71 public PersistableBundle toBundle() { 72 PersistableBundle bundle = super.toBundle(); 73 bundle.putInt(KEY_BUNDLE_VERSION, getBundleVersion()); 74 bundle.putInt(KEY_DTPCM_REPETITION, mDtpcmRepetition); 75 bundle.putInt(KEY_DATA_TRANSFER_CONTROL, mDataTransferControl); 76 77 long[] macAddressList = new long[mDataTransferPhaseManagementList.size()]; 78 int i = 0; 79 ByteBuffer slotBitmapByteBuffer = ByteBuffer.allocate( 80 mDataTransferPhaseManagementList.size() 81 * (1 << ((mDataTransferControl & 0x0F) >> 1))); 82 83 slotBitmapByteBuffer.order(ByteOrder.LITTLE_ENDIAN); 84 85 for (FiraDataTransferPhaseManagementList dataTransferPhaseManagementList : 86 mDataTransferPhaseManagementList) { 87 macAddressList[i++] = uwbAddressToLong( 88 dataTransferPhaseManagementList.getUwbAddress()); 89 slotBitmapByteBuffer.put(dataTransferPhaseManagementList.getSlotBitMap()); 90 } 91 92 bundle.putLongArray(KEY_MAC_ADDRESS_LIST, macAddressList); 93 bundle.putIntArray(KEY_SLOT_BITMAP, byteArrayToIntArray(slotBitmapByteBuffer.array())); 94 95 return bundle; 96 } 97 98 @Nullable byteArrayToIntArray(@ullable byte[] bytes)99 protected static int[] byteArrayToIntArray(@Nullable byte[] bytes) { 100 if (bytes == null) { 101 return null; 102 } 103 104 int[] values = new int[bytes.length]; 105 for (int i = 0; i < values.length; i++) { 106 values[i] = bytes[i]; 107 } 108 return values; 109 } 110 111 @Nullable intArrayToByteArray(@ullable int[] values)112 protected static byte[] intArrayToByteArray(@Nullable int[] values) { 113 if (values == null) { 114 return null; 115 } 116 byte[] bytes = new byte[values.length]; 117 for (int i = 0; i < values.length; i++) { 118 bytes[i] = (byte) values[i]; 119 } 120 return bytes; 121 } 122 fromBundle(PersistableBundle bundle)123 public static FiraDataTransferPhaseConfig fromBundle(PersistableBundle bundle) { 124 switch (bundle.getInt(KEY_BUNDLE_VERSION)) { 125 case BUNDLE_VERSION_1: 126 return parseVersion1(bundle); 127 default: 128 throw new IllegalArgumentException("Invalid bundle version"); 129 } 130 } 131 parseVersion1(PersistableBundle bundle)132 private static FiraDataTransferPhaseConfig parseVersion1(PersistableBundle bundle) { 133 FiraDataTransferPhaseConfig.Builder builder = new FiraDataTransferPhaseConfig.Builder(); 134 135 builder.setDtpcmRepetition((byte) bundle.getInt(KEY_DTPCM_REPETITION)); 136 byte dataTransferControl = (byte) bundle.getInt(KEY_DATA_TRANSFER_CONTROL); 137 builder.setMacAddressMode((byte) (dataTransferControl & 0x01)); 138 builder.setSlotBitmapSize((byte) ((dataTransferControl & 0x0F) >> 1)); 139 140 List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList = 141 new ArrayList<>(); 142 List<UwbAddress> macAddressList = new ArrayList<>(); 143 List<byte[]> slotBitmapList = new ArrayList<>(); 144 145 long[] macAddress = bundle.getLongArray(KEY_MAC_ADDRESS_LIST); 146 for (int i = 0; i < macAddress.length; i++) { 147 macAddressList.add(longToUwbAddress(macAddress[i], 148 ((dataTransferControl & 0x01) == SHORT_MAC_ADDRESS) 149 ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH 150 : UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH)); 151 } 152 153 byte[] buffer = intArrayToByteArray(bundle.getIntArray(KEY_SLOT_BITMAP)); 154 ByteBuffer slotBitmapByteBuffer = ByteBuffer.wrap(buffer); 155 int chunkBufferSize = 1 << (dataTransferControl >> 1); 156 157 while (slotBitmapByteBuffer.hasRemaining()) { 158 byte[] data = new byte[chunkBufferSize]; 159 int bytesToRead = Math.min(chunkBufferSize, slotBitmapByteBuffer.remaining()); 160 slotBitmapByteBuffer.get(data, 0, bytesToRead); 161 slotBitmapList.add(data); 162 } 163 164 for (int i = 0; i < macAddressList.size(); i++) { 165 mDataTransferPhaseManagementList.add(new FiraDataTransferPhaseManagementList( 166 macAddressList.get(i), slotBitmapList.get(i))); 167 } 168 169 builder.setDataTransferPhaseManagementList(mDataTransferPhaseManagementList); 170 171 return builder.build(); 172 } 173 174 /** Defines parameters for data transfer phase management list */ 175 public static class FiraDataTransferPhaseManagementList { 176 private final UwbAddress mUwbAddress; 177 private final byte[] mSlotBitMap; 178 FiraDataTransferPhaseManagementList(UwbAddress uwbAddress, byte[] slotBitmap)179 public FiraDataTransferPhaseManagementList(UwbAddress uwbAddress, byte[] slotBitmap) { 180 mUwbAddress = uwbAddress; 181 mSlotBitMap = slotBitmap; 182 } 183 getUwbAddress()184 public UwbAddress getUwbAddress() { 185 return mUwbAddress; 186 } 187 getSlotBitMap()188 public byte[] getSlotBitMap() { 189 return mSlotBitMap; 190 } 191 } 192 193 /** Builder */ 194 public static class Builder { 195 private byte mDtpcmRepetition; 196 private byte mMacAddressMode; 197 private byte mSlotBitMapSize; 198 private List<FiraDataTransferPhaseManagementList> mDataTransferPhaseManagementList = 199 new ArrayList<>(); 200 setDtpcmRepetition(byte dtpcmRepetition)201 public FiraDataTransferPhaseConfig.Builder setDtpcmRepetition(byte dtpcmRepetition) { 202 mDtpcmRepetition = dtpcmRepetition; 203 return this; 204 } 205 setMacAddressMode(byte macAddressMode)206 public FiraDataTransferPhaseConfig.Builder setMacAddressMode(byte macAddressMode) { 207 mMacAddressMode = macAddressMode; 208 return this; 209 } 210 setSlotBitmapSize(byte slotBitmapSize)211 public FiraDataTransferPhaseConfig.Builder setSlotBitmapSize(byte slotBitmapSize) { 212 mSlotBitMapSize = slotBitmapSize; 213 return this; 214 } 215 setDataTransferPhaseManagementList( List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList)216 public FiraDataTransferPhaseConfig.Builder setDataTransferPhaseManagementList( 217 List<FiraDataTransferPhaseManagementList> dataTransferPhaseManagementList) { 218 mDataTransferPhaseManagementList = dataTransferPhaseManagementList; 219 return this; 220 } 221 build()222 public FiraDataTransferPhaseConfig build() { 223 return new FiraDataTransferPhaseConfig( 224 mDtpcmRepetition, 225 (byte) ((mSlotBitMapSize << 1) | (mMacAddressMode & 0x01)), 226 mDataTransferPhaseManagementList); 227 } 228 } 229 } 230