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.CarSensorEvent;
23 import android.car.hardware.CarSensorManager;
24 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
25 import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
26 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
27 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
28 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
29 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
30 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
31 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
32 import android.util.Log;
33 import android.util.SparseIntArray;
34 import com.android.car.CarLog;
35 import com.android.car.CarSensorEventFactory;
36 import java.io.PrintWriter;
37 import java.util.LinkedList;
38 import java.util.List;
39 
40 /**
41  * Sensor HAL implementation for physical sensors in car.
42  */
43 public class SensorHalService extends SensorHalServiceBase {
44     private static final String TAG = CarLog.concatTag(CarLog.TAG_SENSOR, SensorHalService.class);
45     private static final boolean DBG_EVENTS = false;
46 
47     /**
48      * Listener for monitoring sensor event. Only sensor service will implement this.
49      */
50     public interface SensorListener {
51         /**
52          * Sensor events are available.
53          * @param events
54          */
onSensorEvents(List<CarSensorEvent> events)55         void onSensorEvents(List<CarSensorEvent> events);
56     }
57 
58     // Manager property Id to HAL property Id mapping.
59     private final static ManagerToHalPropIdMap mManagerToHalPropIdMap =
60             ManagerToHalPropIdMap.create(
61                     CarSensorManager.SENSOR_TYPE_CAR_SPEED, VehicleProperty.PERF_VEHICLE_SPEED,
62                     CarSensorManager.SENSOR_TYPE_RPM, VehicleProperty.ENGINE_RPM,
63                     CarSensorManager.SENSOR_TYPE_ODOMETER, VehicleProperty.PERF_ODOMETER,
64                     CarSensorManager.SENSOR_TYPE_GEAR, VehicleProperty.GEAR_SELECTION,
65                     CarSensorManager.SENSOR_TYPE_NIGHT, VehicleProperty.NIGHT_MODE,
66                     CarSensorManager.SENSOR_TYPE_PARKING_BRAKE, VehicleProperty.PARKING_BRAKE_ON,
67                     CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, VehicleProperty.DRIVING_STATUS,
68                     CarSensorManager.SENSOR_TYPE_FUEL_LEVEL, VehicleProperty.FUEL_LEVEL_LOW,
69                     CarSensorManager.SENSOR_TYPE_IGNITION_STATE, VehicleProperty.IGNITION_STATE);
70 
71     private final static SparseIntArray mMgrGearToHalMap = initSparseIntArray(
72             VehicleGear.GEAR_NEUTRAL, CarSensorEvent.GEAR_NEUTRAL,
73             VehicleGear.GEAR_REVERSE, CarSensorEvent.GEAR_REVERSE,
74             VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK,
75             VehicleGear.GEAR_DRIVE, CarSensorEvent.GEAR_DRIVE,
76             VehicleGear.GEAR_LOW, CarSensorEvent.GEAR_FIRST, // Also GEAR_1 - the value is the same.
77             VehicleGear.GEAR_2, CarSensorEvent.GEAR_SECOND,
78             VehicleGear.GEAR_3, CarSensorEvent.GEAR_THIRD,
79             VehicleGear.GEAR_4, CarSensorEvent.GEAR_FOURTH,
80             VehicleGear.GEAR_5, CarSensorEvent.GEAR_FIFTH,
81             VehicleGear.GEAR_6, CarSensorEvent.GEAR_SIXTH,
82             VehicleGear.GEAR_7, CarSensorEvent.GEAR_SEVENTH,
83             VehicleGear.GEAR_8, CarSensorEvent.GEAR_EIGHTH,
84             VehicleGear.GEAR_9, CarSensorEvent.GEAR_NINTH);
85 
86     private final static SparseIntArray mMgrIgnitionStateToHalMap = initSparseIntArray(
87             VehicleIgnitionState.UNDEFINED, CarSensorEvent.IGNITION_STATE_UNDEFINED,
88             VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK,
89             VehicleIgnitionState.OFF, CarSensorEvent.IGNITION_STATE_OFF,
90             VehicleIgnitionState.ACC, CarSensorEvent.IGNITION_STATE_ACC,
91             VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON,
92             VehicleIgnitionState.START, CarSensorEvent.IGNITION_STATE_START);
93 
94     private SensorListener mSensorListener;
95 
SensorHalService(VehicleHal hal)96     public SensorHalService(VehicleHal hal) {
97         super(hal);
98     }
99 
registerSensorListener(SensorListener listener)100     public synchronized void registerSensorListener(SensorListener listener) {
101         mSensorListener = listener;
102     }
103 
104     @Override
getTokenForProperty(VehiclePropConfig halProperty)105     protected int getTokenForProperty(VehiclePropConfig halProperty) {
106         int sensor = mManagerToHalPropIdMap.getManagerPropId(halProperty.prop);
107         if (sensor != SENSOR_TYPE_INVALID
108             && halProperty.changeMode != VehiclePropertyChangeMode.STATIC
109             && ((halProperty.access & VehiclePropertyAccess.READ) != 0)) {
110             return sensor;
111         }
112         return SENSOR_TYPE_INVALID;
113     }
114 
115     // Should be used only inside handleHalEvents method.
116     private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<>();
117     @Override
handleHalEvents(List<VehiclePropValue> values)118     public void handleHalEvents(List<VehiclePropValue> values) {
119         for (VehiclePropValue v : values) {
120             CarSensorEvent event = createCarSensorEvent(v);
121             if (event != null) {
122                 mEventsToDispatch.add(event);
123             }
124         }
125         SensorListener sensorListener;
126         synchronized (this) {
127             sensorListener = mSensorListener;
128         }
129         if (DBG_EVENTS) Log.d(TAG, "handleHalEvents, listener: " + sensorListener);
130         if (sensorListener != null) {
131             sensorListener.onSensorEvents(mEventsToDispatch);
132         }
133         mEventsToDispatch.clear();
134     }
135 
136     @Nullable
mapHalEnumValueToMgr(int propId, int halValue)137     private Integer mapHalEnumValueToMgr(int propId, int halValue) {
138         int mgrValue = halValue;
139 
140         switch (propId) {
141             case VehicleProperty.GEAR_SELECTION:
142                 mgrValue = mMgrGearToHalMap.get(halValue, -1);
143                 break;
144             case VehicleProperty.IGNITION_STATE:
145                 mgrValue =  mMgrIgnitionStateToHalMap.get(halValue, -1);
146             default:
147                 break; // Do nothing
148         }
149         return mgrValue == -1 ? null : mgrValue;
150     }
151 
152     @Nullable
createCarSensorEvent(VehiclePropValue v)153     private CarSensorEvent createCarSensorEvent(VehiclePropValue v) {
154         int property = v.prop;
155         int sensorType = mManagerToHalPropIdMap.getManagerPropId(property);
156         if (sensorType == SENSOR_TYPE_INVALID) {
157             throw new RuntimeException("no sensor defined for property 0x" + toHexString(property));
158         }
159 
160         int dataType = property & VehiclePropertyType.MASK;
161 
162         CarSensorEvent event = null;
163         switch (dataType) {
164             case VehiclePropertyType.BOOLEAN:
165                 event = CarSensorEventFactory.createBooleanEvent(sensorType, v.timestamp,
166                         v.value.int32Values.get(0) == 1);
167                 break;
168             case VehiclePropertyType.INT32:
169                 Integer mgrVal = mapHalEnumValueToMgr(property, v.value.int32Values.get(0));
170                 event =  mgrVal == null ? null
171                         : CarSensorEventFactory.createIntEvent(sensorType, v.timestamp, mgrVal);
172                 break;
173             case VehiclePropertyType.FLOAT: {
174                 event = CarSensorEventFactory.createFloatEvent(sensorType, v.timestamp,
175                         v.value.floatValues.get(0));
176                 break;
177             }
178             default:
179                 Log.w(TAG, "createCarSensorEvent: unsupported type: 0x" + toHexString(dataType));
180         }
181         if (DBG_EVENTS) Log.i(TAG, "Sensor event created: " + event);
182         return event;
183     }
184 
185     @Nullable
getCurrentSensorValue(int sensorType)186     public CarSensorEvent getCurrentSensorValue(int sensorType) {
187         VehiclePropValue propValue = getCurrentSensorVehiclePropValue(sensorType);
188         return (null != propValue) ? createCarSensorEvent(propValue) : null;
189     }
190 
191     @Override
fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate)192     protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) {
193         switch (prop.changeMode) {
194             case VehiclePropertyChangeMode.ON_CHANGE:
195             case VehiclePropertyChangeMode.ON_SET:
196                 return 0;
197         }
198         float rate = 1.0f;
199         switch (carSensorManagerRate) {
200             case CarSensorManager.SENSOR_RATE_FASTEST:
201                 rate = prop.maxSampleRate;
202                 break;
203             case CarSensorManager.SENSOR_RATE_FAST:
204                 rate = 10f;  // every 100ms
205                 break;
206             case CarSensorManager.SENSOR_RATE_UI:
207                 rate = 5f;   // every 200ms
208                 break;
209             default: // fall back to default.
210                 break;
211         }
212         if (rate > prop.maxSampleRate) {
213             rate = prop.maxSampleRate;
214         }
215         if (rate < prop.minSampleRate) {
216             rate = prop.minSampleRate;
217         }
218         return rate;
219     }
220 
221     @Override
dump(PrintWriter writer)222     public void dump(PrintWriter writer) {
223         writer.println("*Sensor HAL*");
224         writer.println("**Supported properties**");
225         for (int i = 0; i < mSensorToPropConfig.size(); i++) {
226             writer.println(mSensorToPropConfig.valueAt(i).toString());
227         }
228     }
229 
initSparseIntArray(int... keyValuePairs)230     private static SparseIntArray initSparseIntArray(int... keyValuePairs) {
231         int inputLength = keyValuePairs.length;
232         if (inputLength % 2 != 0) {
233             throw new IllegalArgumentException("Odd number of key-value elements");
234         }
235 
236         SparseIntArray map = new SparseIntArray(inputLength / 2);
237         for (int i = 0; i < keyValuePairs.length; i += 2) {
238             map.put(keyValuePairs[i], keyValuePairs[i + 1]);
239         }
240         return map;
241     }
242 }
243