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