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.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
24 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
25 import android.util.Log;
26 import android.util.SparseArray;
27 import com.android.car.CarLog;
28 import java.util.Collection;
29 import java.util.LinkedList;
30 import java.util.List;
31 
32 /**
33  * Common base for all SensorHal implementation.
34  * It is wholly based on subscription and there is no explicit API for polling, but each sensor
35  * should report its initial state immediately after {@link #requestSensorStart(int, int)} call.
36  * It is ok to report sensor data {@link SensorListener#onSensorData(CarSensorEvent)} inside
37  * the {@link #requestSensorStart(int, int)} call.
38  */
39 public abstract class SensorHalServiceBase extends HalServiceBase implements SensorBase {
40     private static final String TAG = CarLog.concatTag(CarLog.TAG_SENSOR,
41                                                        SensorHalServiceBase.class);
42     protected static final boolean DBG = false;
43 
44     private boolean mIsReady = false;
45 
46     protected static final int SENSOR_TYPE_INVALID = NOT_SUPPORTED_PROPERTY;
47     protected final VehicleHal mHal;
48     protected final SparseArray<VehiclePropConfig> mSensorToPropConfig = new SparseArray<>();
49 
SensorHalServiceBase(VehicleHal hal)50     public SensorHalServiceBase(VehicleHal hal) {
51         mHal = hal;
52     }
53 
54 
55     @Override
takeSupportedProperties( Collection<VehiclePropConfig> allProperties)56     public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
57         Collection<VehiclePropConfig> allProperties) {
58         if (DBG) Log.d(TAG, "takeSupportedProperties");
59         LinkedList<VehiclePropConfig> supportedProperties = new LinkedList<>();
60         for (VehiclePropConfig halProperty : allProperties) {
61             int sensor = getTokenForProperty(halProperty);
62             boolean mapped = sensor != SENSOR_TYPE_INVALID;
63             if (DBG) {
64                 Log.d(TAG, "takeSupportedProperties, hal property "
65                         + " 0x" + toHexString(halProperty.prop) +
66                         (mapped ? (" mapped to " + sensor) : " ignored"));
67             }
68             if (mapped) {
69                 supportedProperties.add(halProperty);
70                 mSensorToPropConfig.append(sensor, halProperty);
71             }
72         }
73         return supportedProperties;
74     }
75 
76     @Override
init()77     public synchronized void init() {
78         mIsReady = true;
79     }
80 
81     @Override
release()82     public synchronized void release() {
83         mIsReady = false;
84     }
85 
86     /**
87      * Sensor HAL should be ready after init call.
88      * @return
89      */
90     @Override
isReady()91     public synchronized boolean isReady() {
92         return mIsReady;
93     }
94 
95     /**
96      * This should work after {@link #init()}.
97      * @return
98      */
99     @Override
getSupportedSensors()100     public synchronized int[] getSupportedSensors() {
101         int[] supportedSensors = new int[mSensorToPropConfig.size()];
102         for (int i = 0; i < supportedSensors.length; i++) {
103             supportedSensors[i] = mSensorToPropConfig.keyAt(i);
104         }
105         return supportedSensors;
106     }
107 
108     @Override
requestSensorStart(int sensorType, int rate)109     public synchronized boolean requestSensorStart(int sensorType, int rate) {
110         if (DBG) Log.d(TAG, "requestSensorStart, sensorType: " + sensorType + ", rate: " + rate);
111         VehiclePropConfig config = mSensorToPropConfig.get(sensorType);
112         if (config == null) {
113             Log.e(TAG, "requesting to start sensor " + sensorType + ", but VHAL config not found");
114             return false;
115         }
116         //TODO calculate sampling rate properly, bug: 32095903
117         mHal.subscribeProperty(this, config.prop, fixSamplingRateForProperty(config, rate));
118         return true;
119     }
120 
121     @Override
requestSensorStop(int sensorType)122     public synchronized void requestSensorStop(int sensorType) {
123         if (DBG) Log.d(TAG, "requestSensorStop, sensorType: " + sensorType);
124         VehiclePropConfig config = mSensorToPropConfig.get(sensorType);
125         if (config == null) {
126             return;
127         }
128         mHal.unsubscribeProperty(this, config.prop);
129     }
130 
131     @Nullable
getCurrentSensorVehiclePropValue(int sensorType)132     public VehiclePropValue getCurrentSensorVehiclePropValue(int sensorType) {
133         VehiclePropConfig config;
134         synchronized (this) {
135             config = mSensorToPropConfig.get(sensorType);
136         }
137         if (config == null) {
138             Log.e(TAG, "sensor type not available 0x" + toHexString(sensorType));
139             return null;
140         }
141         try {
142             return mHal.get(config.prop);
143         } catch (PropertyTimeoutException e) {
144             Log.e(TAG, "property not ready 0x" + toHexString(config.prop), e);
145             return null;
146         }
147     }
148 
149 
150     @Override
handleHalEvents(List<VehiclePropValue> values)151     public void handleHalEvents(List<VehiclePropValue> values) {
152         // default no-op impl. Necessary to not propagate this HAL specific event to logical
153         // sensor provider.
154         throw new RuntimeException("should not be called");
155     }
156 
fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate)157     protected abstract float fixSamplingRateForProperty(VehiclePropConfig prop,
158         int carSensorManagerRate);
159 
160     /**
161      * Returns a unique token to be used to map this property to a higher-level sensor
162      * This token will be stored in mSensorToPropConfig to allow callers to go from unique
163      * sensor identifiers to VehiclePropConfig objects
164      * @param config
165      * @return SENSOR_TYPE_INVALID or a locally unique token
166      */
getTokenForProperty(VehiclePropConfig config)167     protected abstract int getTokenForProperty(VehiclePropConfig config);
168 }
169