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 17 package com.android.car.hal; 18 19 import android.car.hardware.CarSensorEvent; 20 import android.car.hardware.CarSensorManager; 21 import android.os.ServiceSpecificException; 22 import android.util.Log; 23 import android.util.SparseArray; 24 25 import com.android.car.CarLog; 26 import com.android.car.CarSensorEventFactory; 27 import com.android.car.vehiclenetwork.VehicleNetworkConsts; 28 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess; 29 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode; 30 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig; 31 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; 32 33 import java.io.PrintWriter; 34 import java.util.LinkedList; 35 import java.util.List; 36 37 /** 38 * Sensor HAL implementation for physical sensors in car. 39 */ 40 public class SensorHalService extends SensorHalServiceBase { 41 42 private static final boolean DBG_EVENTS = false; 43 44 private static final int SENSOR_TYPE_INVALD = -1; 45 46 private final VehicleHal mHal; 47 private boolean mIsReady = false; 48 private SensorHalServiceBase.SensorListener mSensorListener; 49 private final SparseArray<VehiclePropConfig> mSensorToHalProperty = 50 new SparseArray<VehiclePropConfig>(); 51 52 public SensorHalService(VehicleHal hal) { 53 mHal = hal; 54 } 55 56 @Override 57 public synchronized void init() { 58 //TODO 59 mIsReady = true; 60 } 61 62 @Override 63 public synchronized List<VehiclePropConfig> takeSupportedProperties( 64 List<VehiclePropConfig> allProperties) { 65 LinkedList<VehiclePropConfig> supportedProperties = new LinkedList<VehiclePropConfig>(); 66 for (VehiclePropConfig halProperty : allProperties) { 67 int sensor = getSensorTypeFromHalProperty(halProperty.getProp()); 68 if (sensor != SENSOR_TYPE_INVALD && 69 halProperty.getChangeMode() != 70 VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC && 71 (halProperty.getAccess() == VehiclePropAccess.VEHICLE_PROP_ACCESS_READ 72 || halProperty.getAccess() == 73 VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE)) { 74 supportedProperties.add(halProperty); 75 mSensorToHalProperty.append(sensor, halProperty); 76 } 77 } 78 return supportedProperties; 79 } 80 81 @Override 82 public synchronized void release() { 83 mSensorToHalProperty.clear(); 84 mIsReady = false; 85 } 86 87 // should be used only insidehandleHalEvents. 88 private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<CarSensorEvent>(); 89 @Override 90 public void handleHalEvents(List<VehiclePropValue> values) { 91 for (VehiclePropValue v : values) { 92 CarSensorEvent event = createCarSensorEvent(v); 93 if (event != null) { 94 mEventsToDispatch.add(event); 95 } 96 } 97 SensorHalServiceBase.SensorListener sensorListener = null; 98 synchronized (this) { 99 sensorListener = mSensorListener; 100 } 101 if (sensorListener != null) { 102 sensorListener.onSensorEvents(mEventsToDispatch); 103 } 104 mEventsToDispatch.clear(); 105 } 106 107 private CarSensorEvent createCarSensorEvent(VehiclePropValue v) { 108 int property = v.getProp(); 109 int sensorType = getSensorTypeFromHalProperty(property); 110 if (sensorType == SENSOR_TYPE_INVALD) { 111 throw new RuntimeException("handleBooleanHalEvent no sensor defined for property " + 112 property); 113 } 114 switch (property) { 115 // boolean 116 case VehicleNetworkConsts.VEHICLE_PROPERTY_NIGHT_MODE: 117 case VehicleNetworkConsts.VEHICLE_PROPERTY_PARKING_BRAKE_ON: 118 case VehicleNetworkConsts.VEHICLE_PROPERTY_FUEL_LEVEL_LOW: { 119 if (DBG_EVENTS) { 120 Log.i(CarLog.TAG_SENSOR, "boolean event, property:" + 121 Integer.toHexString(property) + " value:" + v.getInt32Values(0)); 122 } 123 return CarSensorEventFactory.createBooleanEvent(sensorType, v.getTimestamp(), 124 v.getInt32Values(0) == 1); 125 } 126 // int 127 case VehicleNetworkConsts.VEHICLE_PROPERTY_GEAR_SELECTION: 128 case VehicleNetworkConsts.VEHICLE_PROPERTY_DRIVING_STATUS: { 129 if (DBG_EVENTS) { 130 Log.i(CarLog.TAG_SENSOR, "int event, property:" + 131 Integer.toHexString(property) + " value:" + v.getInt32Values(0)); 132 } 133 return CarSensorEventFactory.createIntEvent(sensorType, v.getTimestamp(), 134 v.getInt32Values(0)); 135 } 136 // float 137 case VehicleNetworkConsts.VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: { 138 if (DBG_EVENTS) { 139 Log.i(CarLog.TAG_SENSOR, "float event, property:" + 140 Integer.toHexString(property) + " value:" + v.getFloatValues(0)); 141 } 142 return CarSensorEventFactory.createFloatEvent(sensorType, v.getTimestamp(), 143 v.getFloatValues(0)); 144 } 145 } 146 return null; 147 } 148 149 @Override 150 public synchronized void registerSensorListener(SensorHalServiceBase.SensorListener listener) { 151 mSensorListener = listener; 152 if (mIsReady) { 153 listener.onSensorHalReady(this); 154 } 155 } 156 157 @Override 158 public synchronized boolean isReady() { 159 return mIsReady; 160 } 161 162 @Override 163 public synchronized int[] getSupportedSensors() { 164 int[] supportedSensors = new int[mSensorToHalProperty.size()]; 165 for (int i = 0; i < supportedSensors.length; i++) { 166 supportedSensors[i] = mSensorToHalProperty.keyAt(i); 167 } 168 return supportedSensors; 169 } 170 171 @Override 172 public synchronized boolean requestSensorStart(int sensorType, int rate) { 173 VehiclePropConfig config = mSensorToHalProperty.get(sensorType); 174 if (config == null) { 175 return false; 176 } 177 //TODO calculate sampling rate properly 178 mHal.subscribeProperty(this, config.getProp(), fixSamplingRateForProperty(config, rate)); 179 return true; 180 } 181 182 public CarSensorEvent getCurrentSensorValue(int sensorType) { 183 VehiclePropConfig config; 184 synchronized (this) { 185 config = mSensorToHalProperty.get(sensorType); 186 } 187 if (config == null) { 188 return null; 189 } 190 try { 191 VehiclePropValue value = mHal.getVehicleNetwork().getProperty(config.getProp()); 192 return createCarSensorEvent(value); 193 } catch (ServiceSpecificException e) { 194 Log.e(CarLog.TAG_SENSOR, "property not ready 0x" + 195 Integer.toHexString(config.getProp()), e); 196 return null; 197 } 198 } 199 200 private float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) { 201 if (prop.getChangeMode() == VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) { 202 return 0; 203 } 204 float rate = 1.0f; 205 switch (carSensorManagerRate) { 206 case CarSensorManager.SENSOR_RATE_FASTEST: 207 case CarSensorManager.SENSOR_RATE_FAST: 208 rate = 10f; 209 break; 210 case CarSensorManager.SENSOR_RATE_UI: 211 rate = 5f; 212 break; 213 default: // fall back to default. 214 break; 215 } 216 if (rate > prop.getSampleRateMax()) { 217 rate = prop.getSampleRateMax(); 218 } 219 if (rate < prop.getSampleRateMin()) { 220 rate = prop.getSampleRateMin(); 221 } 222 return rate; 223 } 224 225 @Override 226 public synchronized void requestSensorStop(int sensorType) { 227 VehiclePropConfig config = mSensorToHalProperty.get(sensorType); 228 if (config == null) { 229 return; 230 } 231 mHal.unsubscribeProperty(this, config.getProp()); 232 } 233 234 /** 235 * Covert hal property to sensor type. This is also used to check if specific property 236 * is supported by sensor hal or not. 237 * @param halPropertyType 238 * @return 239 */ 240 static int getSensorTypeFromHalProperty(int halPropertyType) { 241 switch (halPropertyType) { 242 case VehicleNetworkConsts.VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: 243 return CarSensorManager.SENSOR_TYPE_CAR_SPEED; 244 case VehicleNetworkConsts.VEHICLE_PROPERTY_GEAR_SELECTION: 245 return CarSensorManager.SENSOR_TYPE_GEAR; 246 case VehicleNetworkConsts.VEHICLE_PROPERTY_NIGHT_MODE: 247 return CarSensorManager.SENSOR_TYPE_NIGHT; 248 case VehicleNetworkConsts.VEHICLE_PROPERTY_PARKING_BRAKE_ON: 249 return CarSensorManager.SENSOR_TYPE_PARKING_BRAKE; 250 case VehicleNetworkConsts.VEHICLE_PROPERTY_DRIVING_STATUS: 251 return CarSensorManager.SENSOR_TYPE_DRIVING_STATUS; 252 case VehicleNetworkConsts.VEHICLE_PROPERTY_FUEL_LEVEL_LOW: 253 return CarSensorManager.SENSOR_TYPE_FUEL_LEVEL; 254 default: 255 return SENSOR_TYPE_INVALD; 256 } 257 } 258 259 @Override 260 public void dump(PrintWriter writer) { 261 writer.println("*Sensor HAL*"); 262 writer.println("**Supported properties**"); 263 for (int i = 0; i < mSensorToHalProperty.size(); i++) { 264 writer.println(mSensorToHalProperty.valueAt(i).toString()); 265 } 266 } 267 } 268