blob: a4fd77d2e44b5d1231b732f7a1a5561911fbfe37 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.hal;
import static java.lang.Integer.toHexString;
import android.annotation.Nullable;
import android.car.hardware.CarSensorEvent;
import android.car.hardware.CarSensorManager;
import android.hardware.automotive.vehicle.V2_0.VehicleGear;
import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.car.CarLog;
import com.android.car.CarSensorEventFactory;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;
/**
* Sensor HAL implementation for physical sensors in car.
*/
public class SensorHalService extends SensorHalServiceBase {
private static final String TAG = CarLog.concatTag(CarLog.TAG_SENSOR, SensorHalService.class);
private static final boolean DBG_EVENTS = false;
/**
* Listener for monitoring sensor event. Only sensor service will implement this.
*/
public interface SensorListener {
/**
* Sensor events are available.
* @param events
*/
void onSensorEvents(List<CarSensorEvent> events);
}
// Manager property Id to HAL property Id mapping.
private final static ManagerToHalPropIdMap mManagerToHalPropIdMap =
ManagerToHalPropIdMap.create(
CarSensorManager.SENSOR_TYPE_CAR_SPEED, VehicleProperty.PERF_VEHICLE_SPEED,
CarSensorManager.SENSOR_TYPE_RPM, VehicleProperty.ENGINE_RPM,
CarSensorManager.SENSOR_TYPE_ODOMETER, VehicleProperty.PERF_ODOMETER,
CarSensorManager.SENSOR_TYPE_GEAR, VehicleProperty.GEAR_SELECTION,
CarSensorManager.SENSOR_TYPE_NIGHT, VehicleProperty.NIGHT_MODE,
CarSensorManager.SENSOR_TYPE_PARKING_BRAKE, VehicleProperty.PARKING_BRAKE_ON,
CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, VehicleProperty.DRIVING_STATUS,
CarSensorManager.SENSOR_TYPE_FUEL_LEVEL, VehicleProperty.FUEL_LEVEL_LOW,
CarSensorManager.SENSOR_TYPE_IGNITION_STATE, VehicleProperty.IGNITION_STATE);
private final static SparseIntArray mMgrGearToHalMap = initSparseIntArray(
VehicleGear.GEAR_NEUTRAL, CarSensorEvent.GEAR_NEUTRAL,
VehicleGear.GEAR_REVERSE, CarSensorEvent.GEAR_REVERSE,
VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK,
VehicleGear.GEAR_DRIVE, CarSensorEvent.GEAR_DRIVE,
VehicleGear.GEAR_LOW, CarSensorEvent.GEAR_FIRST, // Also GEAR_1 - the value is the same.
VehicleGear.GEAR_2, CarSensorEvent.GEAR_SECOND,
VehicleGear.GEAR_3, CarSensorEvent.GEAR_THIRD,
VehicleGear.GEAR_4, CarSensorEvent.GEAR_FOURTH,
VehicleGear.GEAR_5, CarSensorEvent.GEAR_FIFTH,
VehicleGear.GEAR_6, CarSensorEvent.GEAR_SIXTH,
VehicleGear.GEAR_7, CarSensorEvent.GEAR_SEVENTH,
VehicleGear.GEAR_8, CarSensorEvent.GEAR_EIGHTH,
VehicleGear.GEAR_9, CarSensorEvent.GEAR_NINTH);
private final static SparseIntArray mMgrIgnitionStateToHalMap = initSparseIntArray(
VehicleIgnitionState.UNDEFINED, CarSensorEvent.IGNITION_STATE_UNDEFINED,
VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK,
VehicleIgnitionState.OFF, CarSensorEvent.IGNITION_STATE_OFF,
VehicleIgnitionState.ACC, CarSensorEvent.IGNITION_STATE_ACC,
VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON,
VehicleIgnitionState.START, CarSensorEvent.IGNITION_STATE_START);
private SensorListener mSensorListener;
public SensorHalService(VehicleHal hal) {
super(hal);
}
public synchronized void registerSensorListener(SensorListener listener) {
mSensorListener = listener;
}
@Override
protected int getTokenForProperty(VehiclePropConfig halProperty) {
int sensor = mManagerToHalPropIdMap.getManagerPropId(halProperty.prop);
if (sensor != SENSOR_TYPE_INVALID
&& halProperty.changeMode != VehiclePropertyChangeMode.STATIC
&& ((halProperty.access & VehiclePropertyAccess.READ) != 0)) {
return sensor;
}
return SENSOR_TYPE_INVALID;
}
// Should be used only inside handleHalEvents method.
private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<>();
@Override
public void handleHalEvents(List<VehiclePropValue> values) {
for (VehiclePropValue v : values) {
CarSensorEvent event = createCarSensorEvent(v);
if (event != null) {
mEventsToDispatch.add(event);
}
}
SensorListener sensorListener;
synchronized (this) {
sensorListener = mSensorListener;
}
if (DBG_EVENTS) Log.d(TAG, "handleHalEvents, listener: " + sensorListener);
if (sensorListener != null) {
sensorListener.onSensorEvents(mEventsToDispatch);
}
mEventsToDispatch.clear();
}
@Nullable
private Integer mapHalEnumValueToMgr(int propId, int halValue) {
int mgrValue = halValue;
switch (propId) {
case VehicleProperty.GEAR_SELECTION:
mgrValue = mMgrGearToHalMap.get(halValue, -1);
break;
case VehicleProperty.IGNITION_STATE:
mgrValue = mMgrIgnitionStateToHalMap.get(halValue, -1);
default:
break; // Do nothing
}
return mgrValue == -1 ? null : mgrValue;
}
@Nullable
private CarSensorEvent createCarSensorEvent(VehiclePropValue v) {
int property = v.prop;
int sensorType = mManagerToHalPropIdMap.getManagerPropId(property);
if (sensorType == SENSOR_TYPE_INVALID) {
throw new RuntimeException("no sensor defined for property 0x" + toHexString(property));
}
int dataType = property & VehiclePropertyType.MASK;
CarSensorEvent event = null;
switch (dataType) {
case VehiclePropertyType.BOOLEAN:
event = CarSensorEventFactory.createBooleanEvent(sensorType, v.timestamp,
v.value.int32Values.get(0) == 1);
break;
case VehiclePropertyType.INT32:
Integer mgrVal = mapHalEnumValueToMgr(property, v.value.int32Values.get(0));
event = mgrVal == null ? null
: CarSensorEventFactory.createIntEvent(sensorType, v.timestamp, mgrVal);
break;
case VehiclePropertyType.FLOAT: {
event = CarSensorEventFactory.createFloatEvent(sensorType, v.timestamp,
v.value.floatValues.get(0));
break;
}
default:
Log.w(TAG, "createCarSensorEvent: unsupported type: 0x" + toHexString(dataType));
}
if (DBG_EVENTS) Log.i(TAG, "Sensor event created: " + event);
return event;
}
@Nullable
public CarSensorEvent getCurrentSensorValue(int sensorType) {
VehiclePropValue propValue = getCurrentSensorVehiclePropValue(sensorType);
return (null != propValue) ? createCarSensorEvent(propValue) : null;
}
@Override
protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) {
switch (prop.changeMode) {
case VehiclePropertyChangeMode.ON_CHANGE:
case VehiclePropertyChangeMode.ON_SET:
return 0;
}
float rate = 1.0f;
switch (carSensorManagerRate) {
case CarSensorManager.SENSOR_RATE_FASTEST:
rate = prop.maxSampleRate;
break;
case CarSensorManager.SENSOR_RATE_FAST:
rate = 10f; // every 100ms
break;
case CarSensorManager.SENSOR_RATE_UI:
rate = 5f; // every 200ms
break;
default: // fall back to default.
break;
}
if (rate > prop.maxSampleRate) {
rate = prop.maxSampleRate;
}
if (rate < prop.minSampleRate) {
rate = prop.minSampleRate;
}
return rate;
}
@Override
public void dump(PrintWriter writer) {
writer.println("*Sensor HAL*");
writer.println("**Supported properties**");
for (int i = 0; i < mSensorToPropConfig.size(); i++) {
writer.println(mSensorToPropConfig.valueAt(i).toString());
}
}
private static SparseIntArray initSparseIntArray(int... keyValuePairs) {
int inputLength = keyValuePairs.length;
if (inputLength % 2 != 0) {
throw new IllegalArgumentException("Odd number of key-value elements");
}
SparseIntArray map = new SparseIntArray(inputLength / 2);
for (int i = 0; i < keyValuePairs.length; i += 2) {
map.put(keyValuePairs[i], keyValuePairs[i + 1]);
}
return map;
}
}