blob: fe80c54d52bb7ba2a1bae06c972c97661e56fd2d [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 android.car.hardware.CarSensorEvent;
import android.car.hardware.CarSensorManager;
import android.os.ServiceSpecificException;
import android.util.Log;
import android.util.SparseArray;
import com.android.car.CarLog;
import com.android.car.CarSensorEventFactory;
import com.android.car.vehiclenetwork.VehicleNetworkConsts;
import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
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 boolean DBG_EVENTS = false;
private static final int SENSOR_TYPE_INVALD = -1;
private final VehicleHal mHal;
private boolean mIsReady = false;
private SensorHalServiceBase.SensorListener mSensorListener;
private final SparseArray<VehiclePropConfig> mSensorToHalProperty =
new SparseArray<VehiclePropConfig>();
public SensorHalService(VehicleHal hal) {
mHal = hal;
}
@Override
public synchronized void init() {
mIsReady = true;
}
@Override
public synchronized List<VehiclePropConfig> takeSupportedProperties(
List<VehiclePropConfig> allProperties) {
LinkedList<VehiclePropConfig> supportedProperties = new LinkedList<VehiclePropConfig>();
for (VehiclePropConfig halProperty : allProperties) {
int sensor = getSensorTypeFromHalProperty(halProperty.getProp());
if (sensor != SENSOR_TYPE_INVALD &&
halProperty.getChangeMode() !=
VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC &&
(halProperty.getAccess() == VehiclePropAccess.VEHICLE_PROP_ACCESS_READ
|| halProperty.getAccess() ==
VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE)) {
supportedProperties.add(halProperty);
mSensorToHalProperty.append(sensor, halProperty);
}
}
return supportedProperties;
}
@Override
public synchronized void release() {
mSensorToHalProperty.clear();
mIsReady = false;
}
// should be used only insidehandleHalEvents.
private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<CarSensorEvent>();
@Override
public void handleHalEvents(List<VehiclePropValue> values) {
for (VehiclePropValue v : values) {
CarSensorEvent event = createCarSensorEvent(v);
if (event != null) {
mEventsToDispatch.add(event);
}
}
SensorHalServiceBase.SensorListener sensorListener = null;
synchronized (this) {
sensorListener = mSensorListener;
}
if (sensorListener != null) {
sensorListener.onSensorEvents(mEventsToDispatch);
}
mEventsToDispatch.clear();
}
private CarSensorEvent createCarSensorEvent(VehiclePropValue v) {
int property = v.getProp();
int sensorType = getSensorTypeFromHalProperty(property);
if (sensorType == SENSOR_TYPE_INVALD) {
throw new RuntimeException("handleBooleanHalEvent no sensor defined for property " +
property);
}
switch (property) {
// boolean
case VehicleNetworkConsts.VEHICLE_PROPERTY_NIGHT_MODE:
case VehicleNetworkConsts.VEHICLE_PROPERTY_PARKING_BRAKE_ON:
case VehicleNetworkConsts.VEHICLE_PROPERTY_FUEL_LEVEL_LOW: {
if (DBG_EVENTS) {
Log.i(CarLog.TAG_SENSOR, "boolean event, property:" +
Integer.toHexString(property) + " value:" + v.getInt32Values(0));
}
return CarSensorEventFactory.createBooleanEvent(sensorType, v.getTimestamp(),
v.getInt32Values(0) == 1);
}
// int
case VehicleNetworkConsts.VEHICLE_PROPERTY_GEAR_SELECTION:
case VehicleNetworkConsts.VEHICLE_PROPERTY_DRIVING_STATUS: {
if (DBG_EVENTS) {
Log.i(CarLog.TAG_SENSOR, "int event, property:" +
Integer.toHexString(property) + " value:" + v.getInt32Values(0));
}
return CarSensorEventFactory.createIntEvent(sensorType, v.getTimestamp(),
v.getInt32Values(0));
}
// float
case VehicleNetworkConsts.VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: {
if (DBG_EVENTS) {
Log.i(CarLog.TAG_SENSOR, "float event, property:" +
Integer.toHexString(property) + " value:" + v.getFloatValues(0));
}
return CarSensorEventFactory.createFloatEvent(sensorType, v.getTimestamp(),
v.getFloatValues(0));
}
}
return null;
}
@Override
public synchronized void registerSensorListener(SensorHalServiceBase.SensorListener listener) {
mSensorListener = listener;
}
@Override
public synchronized boolean isReady() {
return mIsReady;
}
@Override
public synchronized int[] getSupportedSensors() {
int[] supportedSensors = new int[mSensorToHalProperty.size()];
for (int i = 0; i < supportedSensors.length; i++) {
supportedSensors[i] = mSensorToHalProperty.keyAt(i);
}
return supportedSensors;
}
@Override
public synchronized boolean requestSensorStart(int sensorType, int rate) {
VehiclePropConfig config = mSensorToHalProperty.get(sensorType);
if (config == null) {
return false;
}
//TODO calculate sampling rate properly
mHal.subscribeProperty(this, config.getProp(), fixSamplingRateForProperty(config, rate));
return true;
}
public CarSensorEvent getCurrentSensorValue(int sensorType) {
VehiclePropConfig config;
synchronized (this) {
config = mSensorToHalProperty.get(sensorType);
}
if (config == null) {
Log.e(CarLog.TAG_SENSOR, "sensor type not available 0x" +
Integer.toHexString(sensorType));
return null;
}
try {
VehiclePropValue value = mHal.getVehicleNetwork().getProperty(config.getProp());
return createCarSensorEvent(value);
} catch (ServiceSpecificException e) {
Log.e(CarLog.TAG_SENSOR, "property not ready 0x" +
Integer.toHexString(config.getProp()), e);
return null;
}
}
private float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) {
switch (prop.getChangeMode()) {
case VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE:
case VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_SET:
return 0;
}
float rate = 1.0f;
switch (carSensorManagerRate) {
case CarSensorManager.SENSOR_RATE_FASTEST:
case CarSensorManager.SENSOR_RATE_FAST:
rate = 10f;
break;
case CarSensorManager.SENSOR_RATE_UI:
rate = 5f;
break;
default: // fall back to default.
break;
}
if (rate > prop.getSampleRateMax()) {
rate = prop.getSampleRateMax();
}
if (rate < prop.getSampleRateMin()) {
rate = prop.getSampleRateMin();
}
return rate;
}
@Override
public synchronized void requestSensorStop(int sensorType) {
VehiclePropConfig config = mSensorToHalProperty.get(sensorType);
if (config == null) {
return;
}
mHal.unsubscribeProperty(this, config.getProp());
}
/**
* Covert hal property to sensor type. This is also used to check if specific property
* is supported by sensor hal or not.
* @param halPropertyType
* @return
*/
static int getSensorTypeFromHalProperty(int halPropertyType) {
switch (halPropertyType) {
case VehicleNetworkConsts.VEHICLE_PROPERTY_PERF_VEHICLE_SPEED:
return CarSensorManager.SENSOR_TYPE_CAR_SPEED;
case VehicleNetworkConsts.VEHICLE_PROPERTY_GEAR_SELECTION:
return CarSensorManager.SENSOR_TYPE_GEAR;
case VehicleNetworkConsts.VEHICLE_PROPERTY_NIGHT_MODE:
return CarSensorManager.SENSOR_TYPE_NIGHT;
case VehicleNetworkConsts.VEHICLE_PROPERTY_PARKING_BRAKE_ON:
return CarSensorManager.SENSOR_TYPE_PARKING_BRAKE;
case VehicleNetworkConsts.VEHICLE_PROPERTY_DRIVING_STATUS:
return CarSensorManager.SENSOR_TYPE_DRIVING_STATUS;
case VehicleNetworkConsts.VEHICLE_PROPERTY_FUEL_LEVEL_LOW:
return CarSensorManager.SENSOR_TYPE_FUEL_LEVEL;
default:
return SENSOR_TYPE_INVALD;
}
}
@Override
public void dump(PrintWriter writer) {
writer.println("*Sensor HAL*");
writer.println("**Supported properties**");
for (int i = 0; i < mSensorToHalProperty.size(); i++) {
writer.println(mSensorToHalProperty.valueAt(i).toString());
}
}
}