1 /* 2 * Copyright (C) 2015 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.android.car.hal; 17 18 import static com.android.car.hal.CarPropertyUtils.toCarPropertyValue; 19 import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue; 20 import static java.lang.Integer.toHexString; 21 22 import android.car.hardware.CarPropertyConfig; 23 import android.car.hardware.CarPropertyValue; 24 import android.car.hardware.hvac.CarHvacEvent; 25 import android.car.hardware.hvac.CarHvacManager.HvacPropertyId; 26 import android.os.ServiceSpecificException; 27 import android.util.Log; 28 import android.util.SparseIntArray; 29 30 import com.android.car.CarLog; 31 import com.android.car.vehiclenetwork.VehicleNetworkConsts; 32 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig; 33 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; 34 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.HashMap; 38 import java.util.LinkedList; 39 import java.util.List; 40 41 public class HvacHalService extends HalServiceBase { 42 private static final boolean DBG = true; 43 private static final String TAG = CarLog.TAG_HVAC + ".HvacHalService"; 44 private HvacHalListener mListener; 45 private final VehicleHal mVehicleHal; 46 47 private final HashMap<Integer, CarPropertyConfig<?>> mProps = new HashMap<>(); 48 private final SparseIntArray mHalPropToValueType = new SparseIntArray(); 49 50 public interface HvacHalListener { onPropertyChange(CarHvacEvent event)51 void onPropertyChange(CarHvacEvent event); onError(int zone, int property)52 void onError(int zone, int property); 53 } 54 HvacHalService(VehicleHal vehicleHal)55 public HvacHalService(VehicleHal vehicleHal) { 56 mVehicleHal = vehicleHal; 57 if (DBG) { 58 Log.d(TAG, "started HvacHalService!"); 59 } 60 } 61 setListener(HvacHalListener listener)62 public void setListener(HvacHalListener listener) { 63 synchronized (this) { 64 mListener = listener; 65 } 66 } 67 getHvacProperties()68 public List<CarPropertyConfig> getHvacProperties() { 69 List<CarPropertyConfig> propList; 70 synchronized (mProps) { 71 propList = new ArrayList<>(mProps.values()); 72 } 73 return propList; 74 } 75 getHvacProperty(int hvacPropertyId, int areaId)76 public CarPropertyValue getHvacProperty(int hvacPropertyId, int areaId) { 77 int halProp = hvacToHalPropId(hvacPropertyId); 78 79 VehiclePropValue value = null; 80 try { 81 VehiclePropValue valueRequest = VehiclePropValue.newBuilder() 82 .setProp(halProp) 83 .setZone(areaId) 84 .setValueType(mHalPropToValueType.get(halProp)) 85 .build(); 86 87 value = mVehicleHal.getVehicleNetwork().getProperty(valueRequest); 88 } catch (ServiceSpecificException e) { 89 Log.e(CarLog.TAG_HVAC, "property not ready 0x" + toHexString(halProp), e); 90 } 91 92 return value == null ? null : toCarPropertyValue(value, hvacPropertyId); 93 } 94 setHvacProperty(CarPropertyValue prop)95 public void setHvacProperty(CarPropertyValue prop) { 96 VehiclePropValue halProp = toVehiclePropValue(prop, hvacToHalPropId(prop.getPropertyId())); 97 mVehicleHal.getVehicleNetwork().setProperty(halProp); 98 } 99 100 @Override init()101 public void init() { 102 if (DBG) { 103 Log.d(TAG, "init()"); 104 } 105 synchronized (mProps) { 106 // Subscribe to each of the HVAC properties 107 for (Integer prop : mProps.keySet()) { 108 mVehicleHal.subscribeProperty(this, prop, 0); 109 } 110 } 111 } 112 113 @Override release()114 public void release() { 115 if (DBG) { 116 Log.d(TAG, "release()"); 117 } 118 synchronized (mProps) { 119 for (Integer prop : mProps.keySet()) { 120 mVehicleHal.unsubscribeProperty(this, prop); 121 } 122 123 // Clear the property list 124 mProps.clear(); 125 } 126 mListener = null; 127 } 128 129 @Override takeSupportedProperties( List<VehiclePropConfig> allProperties)130 public synchronized List<VehiclePropConfig> takeSupportedProperties( 131 List<VehiclePropConfig> allProperties) { 132 List<VehiclePropConfig> taken = new LinkedList<>(); 133 134 for (VehiclePropConfig p : allProperties) { 135 int hvacPropId; 136 try { 137 hvacPropId = halToHvacPropId(p.getProp()); 138 } catch (IllegalArgumentException e) { 139 Log.i(TAG, "Property not supported by HVAC: 0x" + toHexString(p.getProp())); 140 continue; 141 } 142 CarPropertyConfig hvacConfig = CarPropertyUtils.toCarPropertyConfig(p, hvacPropId); 143 144 taken.add(p); 145 mProps.put(p.getProp(), hvacConfig); 146 mHalPropToValueType.put(p.getProp(), p.getValueType()); 147 148 if (DBG) { 149 Log.d(TAG, "takeSupportedProperties: " + toHexString(p.getProp())); 150 } 151 } 152 return taken; 153 } 154 155 @Override handleHalEvents(List<VehiclePropValue> values)156 public void handleHalEvents(List<VehiclePropValue> values) { 157 HvacHalListener listener; 158 synchronized (this) { 159 listener = mListener; 160 } 161 if (listener != null) { 162 dispatchEventToListener(listener, values); 163 } 164 } 165 dispatchEventToListener(HvacHalListener listener, List<VehiclePropValue> values)166 private void dispatchEventToListener(HvacHalListener listener, List<VehiclePropValue> values) { 167 for (VehiclePropValue v : values) { 168 int prop = v.getProp(); 169 170 int hvacPropId; 171 try { 172 hvacPropId = halToHvacPropId(prop); 173 } catch (IllegalArgumentException ex) { 174 Log.e(TAG, "Property is not supported: 0x" + toHexString(prop), ex); 175 continue; 176 } 177 178 CarHvacEvent event; 179 CarPropertyValue<?> hvacProperty = toCarPropertyValue(v, hvacPropId); 180 event = new CarHvacEvent(CarHvacEvent.HVAC_EVENT_PROPERTY_CHANGE, hvacProperty); 181 182 listener.onPropertyChange(event); 183 if (DBG) { 184 Log.d(TAG, "handleHalEvents event: " + event); 185 } 186 } 187 } 188 189 @Override dump(PrintWriter writer)190 public void dump(PrintWriter writer) { 191 writer.println("*HVAC HAL*"); 192 writer.println(" Properties available:"); 193 for (CarPropertyConfig prop : mProps.values()) { 194 writer.println(" " + prop.toString()); 195 } 196 } 197 198 // Convert the HVAC public API property ID to HAL property ID hvacToHalPropId(int hvacPropId)199 private static int hvacToHalPropId(int hvacPropId) { 200 switch (hvacPropId) { 201 case HvacPropertyId.ZONED_FAN_SPEED_SETPOINT: 202 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_SPEED; 203 case HvacPropertyId.ZONED_FAN_POSITION: 204 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_DIRECTION; 205 case HvacPropertyId.ZONED_TEMP_ACTUAL: 206 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT; 207 case HvacPropertyId.ZONED_TEMP_SETPOINT: 208 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET; 209 case HvacPropertyId.WINDOW_DEFROSTER_ON: 210 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_DEFROSTER; 211 case HvacPropertyId.ZONED_AC_ON: 212 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_AC_ON; 213 case HvacPropertyId.ZONED_AIR_RECIRCULATION_ON: 214 return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_RECIRC_ON; 215 default: 216 throw new IllegalArgumentException("hvacPropId " + hvacPropId + " is not supported"); 217 } 218 } 219 220 // Convert he HAL specific property ID to HVAC public API halToHvacPropId(int halPropId)221 private static int halToHvacPropId(int halPropId) { 222 switch (halPropId) { 223 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_SPEED: 224 return HvacPropertyId.ZONED_FAN_SPEED_SETPOINT; 225 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_DIRECTION: 226 return HvacPropertyId.ZONED_FAN_POSITION; 227 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT: 228 return HvacPropertyId.ZONED_TEMP_ACTUAL; 229 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET: 230 return HvacPropertyId.ZONED_TEMP_SETPOINT; 231 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_DEFROSTER: 232 return HvacPropertyId.WINDOW_DEFROSTER_ON; 233 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_AC_ON: 234 return HvacPropertyId.ZONED_AC_ON; 235 case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_RECIRC_ON: 236 return HvacPropertyId.ZONED_AIR_RECIRCULATION_ON; 237 default: 238 throw new IllegalArgumentException("halPropId " + halPropId + " is not supported"); 239 } 240 } 241 } 242