1 /* 2 * Copyright (C) 2021 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.android.car.hal; 18 19 import android.annotation.Nullable; 20 import android.car.VehicleAreaType; 21 import android.car.feature.Flags; 22 import android.car.hardware.CarPropertyConfig; 23 import android.car.hardware.property.AreaIdConfig; 24 import android.hardware.automotive.vehicle.VehicleArea; 25 import android.hardware.automotive.vehicle.VehicleProperty; 26 import android.hardware.automotive.vehicle.VehiclePropertyAccess; 27 import android.hardware.automotive.vehicle.VehiclePropertyChangeMode; 28 import android.hardware.automotive.vehicle.VehiclePropertyType; 29 30 import com.android.car.hal.property.PropertyHalServiceConfigs; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Set; 35 36 /** 37 * HalPropConfig represents a vehicle property config. 38 */ 39 public abstract class HalPropConfig { 40 private static final Set<Integer> CONFIG_ARRAY_DEFINES_SUPPORTED_ENUM_VALUES = 41 Set.of( 42 VehicleProperty.GEAR_SELECTION, 43 VehicleProperty.CURRENT_GEAR, 44 VehicleProperty.DISTANCE_DISPLAY_UNITS, 45 VehicleProperty.EV_BATTERY_DISPLAY_UNITS, 46 VehicleProperty.TIRE_PRESSURE_DISPLAY_UNITS, 47 VehicleProperty.FUEL_VOLUME_DISPLAY_UNITS, 48 VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, 49 VehicleProperty.VEHICLE_SPEED_DISPLAY_UNITS); 50 51 /** 52 * Get the property ID. 53 */ getPropId()54 public abstract int getPropId(); 55 56 /** 57 * Get the access mode. 58 */ getAccess()59 public abstract int getAccess(); 60 61 /** 62 * Get the change mode. 63 */ getChangeMode()64 public abstract int getChangeMode(); 65 66 /** 67 * Get the area configs. 68 */ getAreaConfigs()69 public abstract HalAreaConfig[] getAreaConfigs(); 70 71 /** 72 * Get the config array. 73 */ getConfigArray()74 public abstract int[] getConfigArray(); 75 76 /** 77 * Get the config string. 78 */ getConfigString()79 public abstract String getConfigString(); 80 81 /** 82 * Get the min sample rate. 83 */ getMinSampleRate()84 public abstract float getMinSampleRate(); 85 86 /** 87 * Get the max sample rate. 88 */ getMaxSampleRate()89 public abstract float getMaxSampleRate(); 90 91 /** 92 * Converts to AIDL or HIDL VehiclePropConfig. 93 */ toVehiclePropConfig()94 public abstract Object toVehiclePropConfig(); 95 96 /** 97 * Converts {@link HalPropConfig} to {@link CarPropertyConfig}. 98 * 99 * @param mgrPropertyId The Property ID used by Car Property Manager, different from the 100 * property ID used by VHAL. 101 */ toCarPropertyConfig(int mgrPropertyId, PropertyHalServiceConfigs propertyHalServiceConfigs)102 public CarPropertyConfig<?> toCarPropertyConfig(int mgrPropertyId, 103 PropertyHalServiceConfigs propertyHalServiceConfigs) { 104 int propId = getPropId(); 105 int areaType = getVehicleAreaType(propId & VehicleArea.MASK); 106 Class<?> clazz = CarPropertyUtils.getJavaClass(propId & VehiclePropertyType.MASK); 107 108 int access = getAccess(); 109 CarPropertyConfig.Builder carPropertyConfigBuilder = CarPropertyConfig.newBuilder(clazz, 110 mgrPropertyId, areaType).setAccess(access).setChangeMode( 111 getChangeMode()).setConfigString(getConfigString()); 112 113 float maxSampleRate = 0f; 114 float minSampleRate = 0f; 115 if (getChangeMode() == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) { 116 maxSampleRate = getMaxSampleRate(); 117 minSampleRate = getMinSampleRate(); 118 } 119 carPropertyConfigBuilder.setMinSampleRate(minSampleRate).setMaxSampleRate(maxSampleRate); 120 121 int[] configIntArray = getConfigArray(); 122 ArrayList<Integer> configArray = new ArrayList<>(configIntArray.length); 123 long[] supportedEnumValues = null; 124 boolean shouldConfigArrayDefineSupportedEnumValues = 125 CONFIG_ARRAY_DEFINES_SUPPORTED_ENUM_VALUES.contains(propId); 126 if (shouldConfigArrayDefineSupportedEnumValues) { 127 supportedEnumValues = new long[configIntArray.length]; 128 } 129 for (int i = 0; i < configIntArray.length; i++) { 130 configArray.add(configIntArray[i]); 131 if (shouldConfigArrayDefineSupportedEnumValues) { 132 supportedEnumValues[i] = (long) configIntArray[i]; 133 } 134 } 135 carPropertyConfigBuilder.setConfigArray(configArray); 136 137 HalAreaConfig[] halAreaConfigs = getAreaConfigs(); 138 var allPossibleEnumValues = propertyHalServiceConfigs 139 .getAllPossibleSupportedEnumValues(getPropId()); 140 if (halAreaConfigs.length == 0) { 141 carPropertyConfigBuilder.addAreaIdConfig(generateAreaIdConfig(clazz, 142 allPossibleEnumValues, /* areaId= */ 0, 143 /* minInt32Value= */ 0, /* maxInt32Value= */ 0, 144 /* minFloatValue= */ 0, /* maxFloatValue= */ 0, 145 /* minInt64Value= */ 0, /* maxInt64Value= */ 0, 146 supportedEnumValues, /* supportVariableUpdateRate= */ false, access)); 147 } else { 148 for (HalAreaConfig halAreaConfig : halAreaConfigs) { 149 if (!shouldConfigArrayDefineSupportedEnumValues) { 150 supportedEnumValues = halAreaConfig.getSupportedEnumValues(); 151 } 152 int areaAccess = (halAreaConfig.getAccess() == VehiclePropertyAccess.NONE) 153 ? access : halAreaConfig.getAccess(); 154 carPropertyConfigBuilder.addAreaIdConfig( 155 generateAreaIdConfig(clazz, allPossibleEnumValues, 156 halAreaConfig.getAreaId(), 157 halAreaConfig.getMinInt32Value(), halAreaConfig.getMaxInt32Value(), 158 halAreaConfig.getMinFloatValue(), halAreaConfig.getMaxFloatValue(), 159 halAreaConfig.getMinInt64Value(), halAreaConfig.getMaxInt64Value(), 160 supportedEnumValues, halAreaConfig.isVariableUpdateRateSupported(), 161 areaAccess)); 162 } 163 } 164 return carPropertyConfigBuilder.build(); 165 } 166 generateAreaIdConfig(Class<?> clazz, @Nullable Set<Integer> allPossibleEnumValues, int areaId, int minInt32Value, int maxInt32Value, float minFloatValue, float maxFloatValue, long minInt64Value, long maxInt64Value, long[] supportedEnumValues, boolean supportVariableUpdateRate, int access)167 private AreaIdConfig generateAreaIdConfig(Class<?> clazz, 168 @Nullable Set<Integer> allPossibleEnumValues, int areaId, int minInt32Value, 169 int maxInt32Value, float minFloatValue, float maxFloatValue, long minInt64Value, 170 long maxInt64Value, long[] supportedEnumValues, boolean supportVariableUpdateRate, 171 int access) { 172 AreaIdConfig.Builder areaIdConfigBuilder = Flags.areaIdConfigAccess() 173 ? new AreaIdConfig.Builder(access, areaId) 174 : new AreaIdConfig.Builder(areaId); 175 if (classMatched(Integer.class, clazz)) { 176 if ((minInt32Value != 0 || maxInt32Value != 0)) { 177 areaIdConfigBuilder.setMinValue(minInt32Value).setMaxValue(maxInt32Value); 178 } 179 // The supported enum values for {@code HVAC_FAN_DIRECTION} are specified by 180 // {@code HVAC_FAN_DIRECTION_AVAILABLE} and the supportedEnumValues are never populated. 181 if (getChangeMode() == VehiclePropertyChangeMode.ON_CHANGE && 182 getPropId() != VehicleProperty.HVAC_FAN_DIRECTION) { 183 if (supportedEnumValues != null && supportedEnumValues.length > 0) { 184 List<Integer> managerSupportedEnumValues = new ArrayList<>( 185 supportedEnumValues.length); 186 for (int i = 0; i < supportedEnumValues.length; i++) { 187 managerSupportedEnumValues.add((int) supportedEnumValues[i]); 188 } 189 areaIdConfigBuilder.setSupportedEnumValues(managerSupportedEnumValues); 190 } else if (allPossibleEnumValues != null) { 191 areaIdConfigBuilder.setSupportedEnumValues( 192 new ArrayList(allPossibleEnumValues)); 193 } 194 } 195 } else if (classMatched(Float.class, clazz) && (minFloatValue != 0 || maxFloatValue != 0)) { 196 areaIdConfigBuilder.setMinValue(minFloatValue).setMaxValue(maxFloatValue); 197 } else if (classMatched(Long.class, clazz) && (minInt64Value != 0 || maxInt64Value != 0)) { 198 areaIdConfigBuilder.setMinValue(minInt64Value).setMaxValue(maxInt64Value); 199 } 200 areaIdConfigBuilder.setSupportVariableUpdateRate(supportVariableUpdateRate); 201 return areaIdConfigBuilder.build(); 202 } 203 getVehicleAreaType(int halArea)204 private static @VehicleAreaType.VehicleAreaTypeValue int getVehicleAreaType(int halArea) { 205 switch (halArea) { 206 case VehicleArea.GLOBAL: 207 return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL; 208 case VehicleArea.SEAT: 209 return VehicleAreaType.VEHICLE_AREA_TYPE_SEAT; 210 case VehicleArea.DOOR: 211 return VehicleAreaType.VEHICLE_AREA_TYPE_DOOR; 212 case VehicleArea.WINDOW: 213 return VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW; 214 case VehicleArea.MIRROR: 215 return VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR; 216 case VehicleArea.WHEEL: 217 return VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL; 218 default: 219 if (Flags.androidVicVehicleProperties()) { 220 if (halArea == VehicleArea.VENDOR) { 221 return VehicleAreaType.VEHICLE_AREA_TYPE_VENDOR; 222 } 223 } 224 throw new RuntimeException("Unsupported area type " + halArea); 225 } 226 } 227 classMatched(Class<?> class1, Class<?> class2)228 private static boolean classMatched(Class<?> class1, Class<?> class2) { 229 return class1 == class2 || class1.getComponentType() == class2; 230 } 231 } 232