DiagnosticHalService.java revision 14b5d561eade5964288da907a4cf21b17dfd1381
1/* 2 * Copyright (C) 2017 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 17package com.android.car.hal; 18 19import android.annotation.Nullable; 20import android.car.annotation.FutureFeature; 21import android.car.hardware.CarDiagnosticEvent; 22import android.car.hardware.CarDiagnosticManager; 23import android.car.hardware.CarSensorManager; 24import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 25import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 26import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode; 27import android.hardware.automotive.vehicle.V2_1.Obd2FloatSensorIndex; 28import android.hardware.automotive.vehicle.V2_1.Obd2IntegerSensorIndex; 29import android.hardware.automotive.vehicle.V2_1.VehicleProperty; 30import android.util.Log; 31import android.util.SparseArray; 32import com.android.car.CarLog; 33import com.android.car.CarServiceUtils; 34import com.android.car.vehiclehal.VehiclePropValueBuilder; 35import java.io.PrintWriter; 36import java.util.BitSet; 37import java.util.LinkedList; 38import java.util.List; 39import java.util.concurrent.CopyOnWriteArraySet; 40 41/** 42 * Diagnostic HAL service supporting gathering diagnostic info from VHAL and translating it into 43 * higher-level semantic information 44 */ 45@FutureFeature 46public class DiagnosticHalService extends SensorHalServiceBase { 47 public static class DiagnosticCapabilities { 48 private final CopyOnWriteArraySet<Integer> mProperties = new CopyOnWriteArraySet<>(); 49 50 void setSupported(int propertyId) { 51 mProperties.add(propertyId); 52 } 53 54 boolean isSupported(int propertyId) { 55 return mProperties.contains(propertyId); 56 } 57 58 public boolean isLiveFrameSupported() { 59 return isSupported(VehicleProperty.OBD2_LIVE_FRAME); 60 } 61 62 public boolean isFreezeFrameSupported() { 63 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME); 64 } 65 66 public boolean isFreezeFrameInfoSupported() { 67 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME_INFO); 68 } 69 70 public boolean isFreezeFrameClearSupported() { 71 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME_CLEAR); 72 } 73 74 void clear() { 75 mProperties.clear(); 76 } 77 } 78 79 private final DiagnosticCapabilities mDiagnosticCapabilities = new DiagnosticCapabilities(); 80 private DiagnosticListener mDiagnosticListener; 81 protected final SparseArray<VehiclePropConfig> mVehiclePropertyToConfig = new SparseArray<>(); 82 83 public DiagnosticHalService(VehicleHal hal) { 84 super(hal); 85 } 86 87 @Override 88 protected int getTokenForProperty(VehiclePropConfig propConfig) { 89 switch (propConfig.prop) { 90 case VehicleProperty.OBD2_LIVE_FRAME: 91 mDiagnosticCapabilities.setSupported(propConfig.prop); 92 mVehiclePropertyToConfig.put(propConfig.prop, propConfig); 93 Log.i(CarLog.TAG_DIAGNOSTIC, String.format("configArray for OBD2_LIVE_FRAME is %s", 94 propConfig.configArray)); 95 return CarDiagnosticManager.FRAME_TYPE_FLAG_LIVE; 96 case VehicleProperty.OBD2_FREEZE_FRAME: 97 mDiagnosticCapabilities.setSupported(propConfig.prop); 98 mVehiclePropertyToConfig.put(propConfig.prop, propConfig); 99 Log.i(CarLog.TAG_DIAGNOSTIC, String.format("configArray for OBD2_FREEZE_FRAME is %s", 100 propConfig.configArray)); 101 return CarDiagnosticManager.FRAME_TYPE_FLAG_FREEZE; 102 case VehicleProperty.OBD2_FREEZE_FRAME_INFO: 103 mDiagnosticCapabilities.setSupported(propConfig.prop); 104 return propConfig.prop; 105 case VehicleProperty.OBD2_FREEZE_FRAME_CLEAR: 106 mDiagnosticCapabilities.setSupported(propConfig.prop); 107 return propConfig.prop; 108 default: 109 return SENSOR_TYPE_INVALID; 110 } 111 } 112 113 @Override 114 public synchronized void release() { 115 super.release(); 116 mDiagnosticCapabilities.clear(); 117 } 118 119 private VehiclePropConfig getPropConfig(int halPropId) { 120 return mVehiclePropertyToConfig.get(halPropId, null); 121 } 122 123 private int getNumIntegerSensors(int halPropId) { 124 int count = Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + 1; 125 count = count + getPropConfig(halPropId).configArray.get(0); 126 return count; 127 } 128 129 private int getNumFloatSensors(int halPropId) { 130 int count = Obd2FloatSensorIndex.LAST_SYSTEM_INDEX + 1; 131 count = count + getPropConfig(halPropId).configArray.get(1); 132 return count; 133 } 134 135 private CarDiagnosticEvent createCarDiagnosticEvent(VehiclePropValue value) { 136 if (null == value) 137 return null; 138 139 final boolean isFreezeFrame = value.prop == VehicleProperty.OBD2_FREEZE_FRAME; 140 141 CarDiagnosticEvent.Builder builder = 142 (isFreezeFrame 143 ? CarDiagnosticEvent.Builder.newFreezeFrameBuilder() 144 : CarDiagnosticEvent.Builder.newLiveFrameBuilder()) 145 .atTimestamp(value.timestamp); 146 147 BitSet bitset = BitSet.valueOf(CarServiceUtils.toByteArray(value.value.bytes)); 148 149 int numIntegerProperties = getNumIntegerSensors(value.prop); 150 int numFloatProperties = getNumFloatSensors(value.prop); 151 152 for (int i = 0; i < numIntegerProperties; ++i) { 153 if (bitset.get(i)) { 154 builder.withIntValue(i, value.value.int32Values.get(i)); 155 } 156 } 157 158 for (int i = 0; i < numFloatProperties; ++i) { 159 if (bitset.get(numIntegerProperties + i)) { 160 builder.withFloatValue(i, value.value.floatValues.get(i)); 161 } 162 } 163 164 builder.withDTC(value.value.stringValue); 165 166 return builder.build(); 167 } 168 169 /** Listener for monitoring diagnostic event. */ 170 public interface DiagnosticListener { 171 /** 172 * Diagnostic events are available. 173 * 174 * @param events 175 */ 176 void onDiagnosticEvents(List<CarDiagnosticEvent> events); 177 } 178 179 // Should be used only inside handleHalEvents method. 180 private final LinkedList<CarDiagnosticEvent> mEventsToDispatch = new LinkedList<>(); 181 182 @Override 183 public void handleHalEvents(List<VehiclePropValue> values) { 184 for (VehiclePropValue value : values) { 185 CarDiagnosticEvent event = createCarDiagnosticEvent(value); 186 if (event != null) { 187 mEventsToDispatch.add(event); 188 } 189 } 190 191 DiagnosticListener listener = null; 192 synchronized (this) { 193 listener = mDiagnosticListener; 194 } 195 if (listener != null) { 196 listener.onDiagnosticEvents(mEventsToDispatch); 197 } 198 mEventsToDispatch.clear(); 199 } 200 201 public synchronized void setDiagnosticListener(DiagnosticListener listener) { 202 mDiagnosticListener = listener; 203 } 204 205 public DiagnosticListener getDiagnosticListener() { 206 return mDiagnosticListener; 207 } 208 209 @Override 210 public void dump(PrintWriter writer) { 211 writer.println("*Diagnostic HAL*"); 212 } 213 214 @Override 215 protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) { 216 //TODO(egranata): tweak this for diagnostics 217 switch (prop.changeMode) { 218 case VehiclePropertyChangeMode.ON_CHANGE: 219 case VehiclePropertyChangeMode.ON_SET: 220 return 0; 221 } 222 float rate = 1.0f; 223 switch (carSensorManagerRate) { 224 case CarSensorManager.SENSOR_RATE_FASTEST: 225 case CarSensorManager.SENSOR_RATE_FAST: 226 rate = 10f; 227 break; 228 case CarSensorManager.SENSOR_RATE_UI: 229 rate = 5f; 230 break; 231 default: // fall back to default. 232 break; 233 } 234 if (rate > prop.maxSampleRate) { 235 rate = prop.maxSampleRate; 236 } 237 if (rate < prop.minSampleRate) { 238 rate = prop.minSampleRate; 239 } 240 return rate; 241 } 242 243 public DiagnosticCapabilities getDiagnosticCapabilities() { 244 return mDiagnosticCapabilities; 245 } 246 247 @Nullable 248 public CarDiagnosticEvent getCurrentLiveFrame() { 249 try { 250 VehiclePropValue value = mHal.get(VehicleProperty.OBD2_LIVE_FRAME); 251 return createCarDiagnosticEvent(value); 252 } catch (PropertyTimeoutException e) { 253 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_LIVE_FRAME"); 254 return null; 255 } catch (IllegalArgumentException e) { 256 Log.e(CarLog.TAG_DIAGNOSTIC, "illegal argument trying to read OBD2_LIVE_FRAME", e); 257 return null; 258 } 259 } 260 261 @Nullable 262 public long[] getFreezeFrameTimestamps() { 263 try { 264 VehiclePropValue value = mHal.get(VehicleProperty.OBD2_FREEZE_FRAME_INFO); 265 long[] timestamps = new long[value.value.int64Values.size()]; 266 for (int i = 0; i < timestamps.length; ++i) { 267 timestamps[i] = value.value.int64Values.get(i); 268 } 269 return timestamps; 270 } catch (PropertyTimeoutException e) { 271 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_FREEZE_FRAME_INFO"); 272 return null; 273 } catch (IllegalArgumentException e) { 274 Log.e(CarLog.TAG_DIAGNOSTIC, 275 "illegal argument trying to read OBD2_FREEZE_FRAME_INFO", e); 276 return null; 277 } 278 } 279 280 @Nullable 281 public CarDiagnosticEvent getFreezeFrame(long timestamp) { 282 VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder( 283 VehicleProperty.OBD2_FREEZE_FRAME); 284 builder.setInt64Value(timestamp); 285 try { 286 VehiclePropValue value = mHal.get(builder.build()); 287 return createCarDiagnosticEvent(value); 288 } catch (PropertyTimeoutException e) { 289 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_DTC_INFO"); 290 return null; 291 } catch (IllegalArgumentException e) { 292 Log.e(CarLog.TAG_DIAGNOSTIC, 293 "illegal argument trying to read OBD2_FREEZE_FRAME", e); 294 return null; 295 } 296 } 297 298 public void clearFreezeFrames(long... timestamps) { 299 VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder( 300 VehicleProperty.OBD2_FREEZE_FRAME_CLEAR); 301 builder.setInt64Value(timestamps); 302 try { 303 mHal.set(builder.build()); 304 } catch (PropertyTimeoutException e) { 305 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to write OBD2_FREEZE_FRAME_CLEAR"); 306 } catch (IllegalArgumentException e) { 307 Log.e(CarLog.TAG_DIAGNOSTIC, 308 "illegal argument trying to write OBD2_FREEZE_FRAME_CLEAR", e); 309 } 310 } 311} 312