• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static java.lang.Integer.toHexString;
20 
21 import android.annotation.Nullable;
22 import android.car.hardware.CarSensorConfig;
23 import android.car.hardware.CarSensorEvent;
24 import android.car.hardware.CarSensorManager;
25 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
26 import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
27 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
28 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
29 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
30 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
31 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
32 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
33 import android.os.Bundle;
34 import android.util.Log;
35 import android.util.SparseIntArray;
36 import com.android.car.CarLog;
37 import com.android.car.CarSensorEventFactory;
38 import java.io.PrintWriter;
39 import java.util.ArrayList;
40 import java.util.LinkedList;
41 import java.util.List;
42 
43 /**
44  * Sensor HAL implementation for physical sensors in car.
45  */
46 public class SensorHalService extends SensorHalServiceBase {
47     private static final String TAG = CarLog.concatTag(CarLog.TAG_SENSOR, SensorHalService.class);
48     private static final boolean DBG_EVENTS = false;
49 
50     /**
51      * Listener for monitoring sensor event. Only sensor service will implement this.
52      */
53     public interface SensorListener {
54         /**
55          * Sensor events are available.
56          *
57          * @param events
58          */
onSensorEvents(List<CarSensorEvent> events)59         void onSensorEvents(List<CarSensorEvent> events);
60     }
61 
62     // Manager property Id to HAL property Id mapping.
63     private final static ManagerToHalPropIdMap mManagerToHalPropIdMap =
64         ManagerToHalPropIdMap.create(
65             CarSensorManager.SENSOR_TYPE_CAR_SPEED, VehicleProperty.PERF_VEHICLE_SPEED,
66             CarSensorManager.SENSOR_TYPE_RPM, VehicleProperty.ENGINE_RPM,
67             CarSensorManager.SENSOR_TYPE_ODOMETER, VehicleProperty.PERF_ODOMETER,
68             CarSensorManager.SENSOR_TYPE_GEAR, VehicleProperty.GEAR_SELECTION,
69             CarSensorManager.SENSOR_TYPE_NIGHT, VehicleProperty.NIGHT_MODE,
70             CarSensorManager.SENSOR_TYPE_PARKING_BRAKE, VehicleProperty.PARKING_BRAKE_ON,
71             CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, VehicleProperty.DRIVING_STATUS,
72             CarSensorManager.SENSOR_TYPE_FUEL_LEVEL, VehicleProperty.FUEL_LEVEL_LOW,
73             CarSensorManager.SENSOR_TYPE_IGNITION_STATE, VehicleProperty.IGNITION_STATE,
74             CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE, VehicleProperty.WHEEL_TICK,
75             CarSensorManager.SENSOR_TYPE_ABS_ACTIVE, VehicleProperty.ABS_ACTIVE,
76             CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
77             VehicleProperty.TRACTION_CONTROL_ACTIVE
78         );
79 
80     private final static SparseIntArray mMgrGearToHalMap = initSparseIntArray(
81         VehicleGear.GEAR_NEUTRAL, CarSensorEvent.GEAR_NEUTRAL,
82         VehicleGear.GEAR_REVERSE, CarSensorEvent.GEAR_REVERSE,
83         VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK,
84         VehicleGear.GEAR_DRIVE, CarSensorEvent.GEAR_DRIVE,
85         VehicleGear.GEAR_LOW, CarSensorEvent.GEAR_FIRST, // Also GEAR_1 - the value is the same.
86         VehicleGear.GEAR_2, CarSensorEvent.GEAR_SECOND,
87         VehicleGear.GEAR_3, CarSensorEvent.GEAR_THIRD,
88         VehicleGear.GEAR_4, CarSensorEvent.GEAR_FOURTH,
89         VehicleGear.GEAR_5, CarSensorEvent.GEAR_FIFTH,
90         VehicleGear.GEAR_6, CarSensorEvent.GEAR_SIXTH,
91         VehicleGear.GEAR_7, CarSensorEvent.GEAR_SEVENTH,
92         VehicleGear.GEAR_8, CarSensorEvent.GEAR_EIGHTH,
93         VehicleGear.GEAR_9, CarSensorEvent.GEAR_NINTH);
94 
95     private final static SparseIntArray mMgrIgnitionStateToHalMap = initSparseIntArray(
96         VehicleIgnitionState.UNDEFINED, CarSensorEvent.IGNITION_STATE_UNDEFINED,
97         VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK,
98         VehicleIgnitionState.OFF, CarSensorEvent.IGNITION_STATE_OFF,
99         VehicleIgnitionState.ACC, CarSensorEvent.IGNITION_STATE_ACC,
100         VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON,
101         VehicleIgnitionState.START, CarSensorEvent.IGNITION_STATE_START);
102 
103     private SensorListener mSensorListener;
104 
105     private int[] mMicrometersPerWheelTick = {0, 0, 0, 0};
106 
107     @Override
init()108     public void init() {
109         VehiclePropConfig config;
110         // Populate internal values if available
111         synchronized (this) {
112             config = mSensorToPropConfig.get(CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE);
113         }
114         if (config == null) {
115             Log.e(TAG, "init:  unable to get property config for SENSOR_TYPE_WHEEL_TICK_DISTANCE");
116         } else {
117             for (int i = 0; i < 4; i++) {
118                 mMicrometersPerWheelTick[i] = config.configArray.get(i +
119                     INDEX_WHEEL_DISTANCE_FRONT_LEFT);
120             }
121         }
122         super.init();
123     }
124 
SensorHalService(VehicleHal hal)125     public SensorHalService(VehicleHal hal) {
126         super(hal);
127     }
128 
registerSensorListener(SensorListener listener)129     public synchronized void registerSensorListener(SensorListener listener) {
130         mSensorListener = listener;
131     }
132 
133     @Override
getTokenForProperty(VehiclePropConfig halProperty)134     protected int getTokenForProperty(VehiclePropConfig halProperty) {
135         int sensor = mManagerToHalPropIdMap.getManagerPropId(halProperty.prop);
136         if (sensor != SENSOR_TYPE_INVALID
137             && halProperty.changeMode != VehiclePropertyChangeMode.STATIC
138             && ((halProperty.access & VehiclePropertyAccess.READ) != 0)) {
139             return sensor;
140         }
141         return SENSOR_TYPE_INVALID;
142     }
143 
144     // Should be used only inside handleHalEvents method.
145     private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<>();
146 
147     @Override
handleHalEvents(List<VehiclePropValue> values)148     public void handleHalEvents(List<VehiclePropValue> values) {
149         for (VehiclePropValue v : values) {
150             CarSensorEvent event = createCarSensorEvent(v);
151             if (event != null) {
152                 mEventsToDispatch.add(event);
153             }
154         }
155         SensorListener sensorListener;
156         synchronized (this) {
157             sensorListener = mSensorListener;
158         }
159         if (DBG_EVENTS) Log.d(TAG, "handleHalEvents, listener: " + sensorListener);
160         if (sensorListener != null) {
161             sensorListener.onSensorEvents(mEventsToDispatch);
162         }
163         mEventsToDispatch.clear();
164     }
165 
166     @Nullable
mapHalEnumValueToMgr(int propId, int halValue)167     private Integer mapHalEnumValueToMgr(int propId, int halValue) {
168         int mgrValue = halValue;
169 
170         switch (propId) {
171             case VehicleProperty.GEAR_SELECTION:
172                 mgrValue = mMgrGearToHalMap.get(halValue, -1);
173                 break;
174             case VehicleProperty.IGNITION_STATE:
175                 mgrValue = mMgrIgnitionStateToHalMap.get(halValue, -1);
176             default:
177                 break; // Do nothing
178         }
179         return mgrValue == -1 ? null : mgrValue;
180     }
181 
182     @Nullable
createCarSensorEvent(VehiclePropValue v)183     private CarSensorEvent createCarSensorEvent(VehiclePropValue v) {
184         int property = v.prop;
185         int sensorType = mManagerToHalPropIdMap.getManagerPropId(property);
186         if (sensorType == SENSOR_TYPE_INVALID) {
187             throw new RuntimeException("no sensor defined for property 0x" + toHexString(property));
188         }
189         // Handle the valid sensor
190         int dataType = property & VehiclePropertyType.MASK;
191         CarSensorEvent event = null;
192         switch (dataType) {
193             case VehiclePropertyType.BOOLEAN:
194                 event = CarSensorEventFactory.createBooleanEvent(sensorType, v.timestamp,
195                     v.value.int32Values.get(0) == 1);
196                 break;
197             case VehiclePropertyType.COMPLEX:
198                 event = CarSensorEventFactory.createComplexEvent(sensorType, v.timestamp, v);
199                 break;
200             case VehiclePropertyType.INT32:
201                 Integer mgrVal = mapHalEnumValueToMgr(property, v.value.int32Values.get(0));
202                 event = mgrVal == null ? null
203                     : CarSensorEventFactory.createIntEvent(sensorType, v.timestamp, mgrVal);
204                 break;
205             case VehiclePropertyType.FLOAT:
206                 event = CarSensorEventFactory.createFloatEvent(sensorType, v.timestamp,
207                     v.value.floatValues.get(0));
208                 break;
209             default:
210                 Log.w(TAG, "createCarSensorEvent: unsupported type: 0x" + toHexString(dataType));
211                 break;
212         }
213         // Perform property specific actions
214         switch (property) {
215             case VehicleProperty.WHEEL_TICK:
216                 // Apply the um/tick scaling factor, then divide by 1000 to generate mm
217                 for (int i = 0; i < 4; i++) {
218                     // ResetCounts is at longValues[0]
219                     if (event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] !=
220                         Long.MAX_VALUE) {
221                         event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] *=
222                             mMicrometersPerWheelTick[i];
223                         event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] /=
224                             1000;
225                     }
226                 }
227                 break;
228         }
229         if (DBG_EVENTS) Log.i(TAG, "Sensor event created: " + event);
230         return event;
231     }
232 
233     @Nullable
getCurrentSensorValue(int sensorType)234     public CarSensorEvent getCurrentSensorValue(int sensorType) {
235         VehiclePropValue propValue = getCurrentSensorVehiclePropValue(sensorType);
236         return (null != propValue) ? createCarSensorEvent(propValue) : null;
237     }
238 
239     @Override
fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate)240     protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) {
241         switch (prop.changeMode) {
242             case VehiclePropertyChangeMode.ON_CHANGE:
243             case VehiclePropertyChangeMode.ON_SET:
244                 return 0;
245         }
246         float rate = 1.0f;
247         switch (carSensorManagerRate) {
248             case CarSensorManager.SENSOR_RATE_FASTEST:
249                 rate = prop.maxSampleRate;
250                 break;
251             case CarSensorManager.SENSOR_RATE_FAST:
252                 rate = 10f;  // every 100ms
253                 break;
254             case CarSensorManager.SENSOR_RATE_UI:
255                 rate = 5f;   // every 200ms
256                 break;
257             default: // fall back to default.
258                 break;
259         }
260         if (rate > prop.maxSampleRate) {
261             rate = prop.maxSampleRate;
262         }
263         if (rate < prop.minSampleRate) {
264             rate = prop.minSampleRate;
265         }
266         return rate;
267     }
268 
269     @Override
dump(PrintWriter writer)270     public void dump(PrintWriter writer) {
271         writer.println("*Sensor HAL*");
272         writer.println("**Supported properties**");
273         for (int i = 0; i < mSensorToPropConfig.size(); i++) {
274             writer.println(mSensorToPropConfig.valueAt(i).toString());
275         }
276         for (int i = 0; i < mMicrometersPerWheelTick.length; i++) {
277             writer.println("mMicrometersPerWheelTick[" + i + "] = " + mMicrometersPerWheelTick[i]);
278         }
279     }
280 
initSparseIntArray(int... keyValuePairs)281     private static SparseIntArray initSparseIntArray(int... keyValuePairs) {
282         int inputLength = keyValuePairs.length;
283         if (inputLength % 2 != 0) {
284             throw new IllegalArgumentException("Odd number of key-value elements");
285         }
286 
287         SparseIntArray map = new SparseIntArray(inputLength / 2);
288         for (int i = 0; i < keyValuePairs.length; i += 2) {
289             map.put(keyValuePairs[i], keyValuePairs[i + 1]);
290         }
291         return map;
292     }
293 
294     private static final int INDEX_WHEEL_DISTANCE_ENABLE_FLAG = 0;
295     private static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
296     private static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
297     private static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
298     private static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
299     private static final int WHEEL_TICK_DISTANCE_BUNDLE_SIZE = 6;
300 
createWheelDistanceTickBundle(ArrayList<Integer> configArray)301     private Bundle createWheelDistanceTickBundle(ArrayList<Integer> configArray) {
302         Bundle b = new Bundle(WHEEL_TICK_DISTANCE_BUNDLE_SIZE);
303         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS,
304             configArray.get(INDEX_WHEEL_DISTANCE_ENABLE_FLAG));
305         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK,
306             configArray.get(INDEX_WHEEL_DISTANCE_FRONT_LEFT));
307         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK,
308             configArray.get(INDEX_WHEEL_DISTANCE_FRONT_RIGHT));
309         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK,
310             configArray.get(INDEX_WHEEL_DISTANCE_REAR_RIGHT));
311         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK,
312             configArray.get(INDEX_WHEEL_DISTANCE_REAR_LEFT));
313         return b;
314     }
315 
316 
getSensorConfig(int sensorType)317     public CarSensorConfig getSensorConfig(int sensorType) {
318         VehiclePropConfig cfg;
319         synchronized (this) {
320             cfg = mSensorToPropConfig.get(sensorType);
321         }
322         if (cfg == null) {
323             /* Invalid sensor type. */
324             throw new IllegalArgumentException("Unknown sensorType = " + sensorType);
325         } else {
326             Bundle b;
327             switch(sensorType) {
328                 case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
329                     b = createWheelDistanceTickBundle(cfg.configArray);
330                     break;
331                 default:
332                     /* Unhandled config.  Create empty bundle */
333                     b = Bundle.EMPTY;
334                     break;
335             }
336             return new CarSensorConfig(sensorType, b);
337         }
338     }
339 }