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 
SensorHalService(VehicleHal hal)52     public SensorHalService(VehicleHal hal) {
53         mHal = hal;
54     }
55 
56     @Override
init()57     public synchronized void init() {
58         //TODO
59         mIsReady = true;
60     }
61 
62     @Override
takeSupportedProperties( List<VehiclePropConfig> allProperties)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
release()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
handleHalEvents(List<VehiclePropValue> values)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 
createCarSensorEvent(VehiclePropValue v)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
registerSensorListener(SensorHalServiceBase.SensorListener listener)150     public synchronized void registerSensorListener(SensorHalServiceBase.SensorListener listener) {
151         mSensorListener = listener;
152         if (mIsReady) {
153             listener.onSensorHalReady(this);
154         }
155     }
156 
157     @Override
isReady()158     public synchronized boolean isReady() {
159         return mIsReady;
160     }
161 
162     @Override
getSupportedSensors()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
requestSensorStart(int sensorType, int rate)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 
getCurrentSensorValue(int sensorType)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 
fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate)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
requestSensorStop(int sensorType)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      */
getSensorTypeFromHalProperty(int halPropertyType)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
dump(PrintWriter writer)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