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 17 package com.google.uwb.support.radar; 18 19 import android.os.PersistableBundle; 20 import android.uwb.RangingReport; 21 22 import com.google.uwb.support.base.RequiredParam; 23 import com.google.uwb.support.fira.FiraParams.StatusCode; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Radar data packet 30 * 31 * <p>This is passed as the mRangingReportMetadata bundle in the RangingReport. {@link 32 * RangingReport#getRangingReportMetadata()} This will be passed for Radar sessions only. 33 */ 34 public class RadarData extends RadarParams { 35 private static final int BUNDLE_VERSION_1 = 1; 36 private static final int BUNDLE_VERSION_CURRENT = BUNDLE_VERSION_1; 37 38 private static final String KEY_STATUS_CODE = "status_code"; 39 private static final String KEY_RADAR_DATA_TYPE = "radar_data_type"; 40 private static final String KEY_SAMPLES_PER_SWEEP = "samples_per_sweep"; 41 private static final String KEY_BITS_PER_SAMPLE = "bits_per_samples"; 42 private static final String KEY_SWEEP_OFFSET = "sweep_offset"; 43 private static final String KEY_SWEEP_DATA = "sweep_data"; 44 45 @StatusCode private final int mStatusCode; 46 @RadarDataType private final int mRadarDataType; 47 @SamplesPerSweep private final int mSamplesPerSweep; 48 @BitsPerSample private final int mBitsPerSample; 49 @SweepOffset private final int mSweepOffset; 50 private final List<RadarSweepData> mSweepData; 51 RadarData( @tatusCode int statusCode, @RadarDataType int radarDataType, @SamplesPerSweep int samplesPerSweep, @BitsPerSample int bitsPerSample, @SweepOffset int sweepOffset, List<RadarSweepData> sweepData)52 private RadarData( 53 @StatusCode int statusCode, 54 @RadarDataType int radarDataType, 55 @SamplesPerSweep int samplesPerSweep, 56 @BitsPerSample int bitsPerSample, 57 @SweepOffset int sweepOffset, 58 List<RadarSweepData> sweepData) { 59 mStatusCode = statusCode; 60 mRadarDataType = radarDataType; 61 mSamplesPerSweep = samplesPerSweep; 62 mBitsPerSample = bitsPerSample; 63 mSweepOffset = sweepOffset; 64 mSweepData = sweepData; 65 } 66 67 @Override getBundleVersion()68 protected int getBundleVersion() { 69 return BUNDLE_VERSION_CURRENT; 70 } 71 72 @Override toBundle()73 public PersistableBundle toBundle() { 74 PersistableBundle bundle = super.toBundle(); 75 bundle.putInt(KEY_STATUS_CODE, mStatusCode); 76 bundle.putInt(KEY_RADAR_DATA_TYPE, mRadarDataType); 77 bundle.putInt(KEY_SAMPLES_PER_SWEEP, mSamplesPerSweep); 78 bundle.putInt(KEY_BITS_PER_SAMPLE, mBitsPerSample); 79 bundle.putInt(KEY_SWEEP_OFFSET, mSweepOffset); 80 int sweep_index = 0; 81 for (RadarSweepData sweep : mSweepData) { 82 bundle.putPersistableBundle(KEY_SWEEP_DATA + sweep_index, sweep.toBundle()); 83 sweep_index++; 84 } 85 return bundle; 86 } 87 88 /** Unpack the {@link PersistableBundle} to a {@link RadarData} */ fromBundle(PersistableBundle bundle)89 public static RadarData fromBundle(PersistableBundle bundle) { 90 if (!isCorrectProtocol(bundle)) { 91 throw new IllegalArgumentException("Invalid protocol"); 92 } 93 94 switch (getBundleVersion(bundle)) { 95 case BUNDLE_VERSION_1: 96 return parseBundleVersion1(bundle); 97 98 default: 99 throw new IllegalArgumentException("unknown bundle version"); 100 } 101 } 102 parseBundleVersion1(PersistableBundle bundle)103 private static RadarData parseBundleVersion1(PersistableBundle bundle) { 104 RadarData.Builder builder = 105 new RadarData.Builder() 106 .setStatusCode(bundle.getInt(KEY_STATUS_CODE)) 107 .setRadarDataType(bundle.getInt(KEY_RADAR_DATA_TYPE)) 108 .setSamplesPerSweep(bundle.getInt(KEY_SAMPLES_PER_SWEEP)) 109 .setBitsPerSample(bundle.getInt(KEY_BITS_PER_SAMPLE)) 110 .setSweepOffset(bundle.getInt(KEY_SWEEP_OFFSET)); 111 112 int sweep_index = 0; 113 PersistableBundle sweepBundle = bundle.getPersistableBundle(KEY_SWEEP_DATA + sweep_index); 114 while (sweepBundle != null) { 115 builder.addSweepData(RadarSweepData.fromBundle(sweepBundle)); 116 sweep_index++; 117 sweepBundle = bundle.getPersistableBundle(KEY_SWEEP_DATA + sweep_index); 118 } 119 return builder.build(); 120 } 121 122 @StatusCode getStatusCode()123 public int getStatusCode() { 124 return mStatusCode; 125 } 126 127 @RadarDataType getRadarDataType()128 public int getRadarDataType() { 129 return mRadarDataType; 130 } 131 132 @SamplesPerSweep getSamplesPerSweep()133 public int getSamplesPerSweep() { 134 return mSamplesPerSweep; 135 } 136 137 @BitsPerSample getBitsPerSample()138 public int getBitsPerSample() { 139 return mBitsPerSample; 140 } 141 142 @SweepOffset getSweepOffset()143 public int getSweepOffset() { 144 return mSweepOffset; 145 } 146 getSweepData()147 public List<RadarSweepData> getSweepData() { 148 return mSweepData; 149 } 150 151 /** Builder */ 152 public static final class Builder { 153 @StatusCode private RequiredParam<Integer> mStatusCode = new RequiredParam<>(); 154 @RadarDataType private RequiredParam<Integer> mRadarDataType = new RequiredParam<>(); 155 @SamplesPerSweep private RequiredParam<Integer> mSamplesPerSweep = new RequiredParam<>(); 156 @BitsPerSample private RequiredParam<Integer> mBitsPerSample = new RequiredParam<>(); 157 @SweepOffset private RequiredParam<Integer> mSweepOffset = new RequiredParam<>(); 158 private List<RadarSweepData> mSweepData = new ArrayList<>(); 159 160 /** Sets status code */ setStatusCode(@tatusCode int statusCode)161 public RadarData.Builder setStatusCode(@StatusCode int statusCode) { 162 mStatusCode.set(statusCode); 163 return this; 164 } 165 166 /** Sets radar data type */ setRadarDataType(@adarDataType int radarDataType)167 public RadarData.Builder setRadarDataType(@RadarDataType int radarDataType) { 168 mRadarDataType.set(radarDataType); 169 return this; 170 } 171 172 /** Sets samples per sweep */ setSamplesPerSweep(@amplesPerSweep int samplesPerSweep)173 public RadarData.Builder setSamplesPerSweep(@SamplesPerSweep int samplesPerSweep) { 174 mSamplesPerSweep.set(samplesPerSweep); 175 return this; 176 } 177 178 /** Sets bits per sample */ setBitsPerSample(@itsPerSample int bitsPerSample)179 public RadarData.Builder setBitsPerSample(@BitsPerSample int bitsPerSample) { 180 mBitsPerSample.set(bitsPerSample); 181 return this; 182 } 183 184 /** Sets sweep offset */ setSweepOffset(@weepOffset int sweepOffset)185 public RadarData.Builder setSweepOffset(@SweepOffset int sweepOffset) { 186 mSweepOffset.set(sweepOffset); 187 return this; 188 } 189 190 /** Adds a list of {@link RadarSweepData} */ setSweepData(List<RadarSweepData> sweepData)191 public RadarData.Builder setSweepData(List<RadarSweepData> sweepData) { 192 mSweepData.addAll(sweepData); 193 return this; 194 } 195 196 /** Adds a single {@link RadarSweepData} */ addSweepData(RadarSweepData sweepData)197 public RadarData.Builder addSweepData(RadarSweepData sweepData) { 198 mSweepData.add(sweepData); 199 return this; 200 } 201 202 /** Build {@link RadarData} */ build()203 public RadarData build() { 204 if (mRadarDataType.get() == RadarParams.RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES 205 && mSweepData.size() == 0) { 206 throw new IllegalArgumentException("No radar sweep data"); 207 } 208 return new RadarData( 209 mStatusCode.get(), 210 mRadarDataType.get(), 211 mSamplesPerSweep.get(), 212 mBitsPerSample.get(), 213 mSweepOffset.get(), 214 mSweepData); 215 } 216 } 217 } 218