1 /*
2  * Copyright (C) 2018 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 package android.car.cluster.sensors;
17 
18 import android.car.VehiclePropertyIds;
19 import android.car.VehiclePropertyType;
20 import android.car.hardware.CarPropertyValue;
21 import android.car.hardware.CarSensorEvent;
22 
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.function.Function;
29 
30 /**
31  * The collection of all sensors supported by this application.
32  */
33 public class Sensors {
34     /** Area identifier used for sensors corresponding to global VHAL properties */
35     public static final int GLOBAL_AREA_ID = -1;
36 
37     private static Sensors sInstance;
38     private static List<Sensor<?>> sSensors = new ArrayList<>();
39     private Map<Integer, List<Sensor<?>>> mSensorsByPropertyId = new HashMap<>();
40 
41     /** Possible values of the {@link #SENSOR_GEAR} sensor */
42     public enum Gear {
43         NEUTRAL,
44         REVERSE,
45         DRIVE,
46         PARK,
47     }
48 
49     /** Fuel of the car, measured in millimeters */
50     public static final Sensor<Float> SENSOR_FUEL = registerSensor(
51             "Fuel", VehiclePropertyIds.FUEL_LEVEL, GLOBAL_AREA_ID, VehiclePropertyType.FLOAT,
52             value -> (Float) value.getValue());
53     /** Fuel capacity of the car, measured in millimeters */
54     public static final Sensor<Float> SENSOR_FUEL_CAPACITY = registerSensor(
55             "Fuel Capacity", VehiclePropertyIds.INFO_FUEL_CAPACITY, GLOBAL_AREA_ID,
56             VehiclePropertyType.FLOAT,
57             value -> (Float) value.getValue());
58     /** RPMs */
59     public static final Sensor<Float> SENSOR_RPM = registerSensor(
60             "RPM", VehiclePropertyIds.ENGINE_RPM, GLOBAL_AREA_ID,
61             VehiclePropertyType.FLOAT,
62             value -> (Float) value.getValue());
63     /** Fuel range in meters */
64     public static final Sensor<Float> SENSOR_FUEL_RANGE = registerSensor(
65             "Fuel Range", VehiclePropertyIds.RANGE_REMAINING, GLOBAL_AREA_ID,
66             VehiclePropertyType.FLOAT,
67             value -> (Float) value.getValue());
68     /** Speed in meters per second */
69     public static final Sensor<Float> SENSOR_SPEED = registerSensor(
70             "Speed", VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID,
71             VehiclePropertyType.FLOAT,
72             value -> (Float) value.getValue());
73     /** Current gear of the car */
74     public static final Sensor<Gear> SENSOR_GEAR = registerSensor(
75             "Gear", VehiclePropertyIds.GEAR_SELECTION, GLOBAL_AREA_ID, VehiclePropertyType.INT32,
76             value -> {
77                 if (value == null) {
78                     return null;
79                 }
80                 Integer gear = (Integer) value.getValue();
81                 if ((gear & CarSensorEvent.GEAR_REVERSE) != 0) {
82                     return Gear.REVERSE;
83                 } else if ((gear & CarSensorEvent.GEAR_NEUTRAL) != 0) {
84                     return Gear.NEUTRAL;
85                 } else if ((gear & CarSensorEvent.GEAR_DRIVE) != 0) {
86                     return Gear.DRIVE;
87                 } else if ((gear & CarSensorEvent.GEAR_PARK) != 0) {
88                     return Gear.PARK;
89                 } else {
90                     return null;
91                 }
92             });
93 
registerSensor(String propertyName, int propertyId, int areaId, int expectedPropertyType, Function<CarPropertyValue<?>, T> adapter)94     private static <T> Sensor<T> registerSensor(String propertyName, int propertyId, int areaId,
95             int expectedPropertyType, Function<CarPropertyValue<?>, T> adapter) {
96         Sensor<T> sensor = new Sensor<>(propertyName, propertyId, areaId, expectedPropertyType,
97                 adapter);
98         sSensors.add(sensor);
99         return sensor;
100     }
101 
102     /**
103      * Obtains the singleton instance of this class
104      */
getInstance()105     public static Sensors getInstance() {
106         if (sInstance == null) {
107             sInstance = new Sensors();
108         }
109         return sInstance;
110     }
111 
Sensors()112     private Sensors() {
113         initializeSensorsMap();
114     }
115 
initializeSensorsMap()116     private void initializeSensorsMap() {
117         for (Sensor<?> sensorId : getSensors()) {
118             mSensorsByPropertyId
119                     .computeIfAbsent(sensorId.mPropertyId, (id) -> new ArrayList<>())
120                     .add(sensorId);
121         }
122     }
123 
124     /**
125      * Returns all sensors.
126      */
getSensors()127     public List<Sensor<?>> getSensors() {
128         return sSensors;
129     }
130 
131     /**
132      * Returns all sensors associated to the given VHAL property id.
133      */
getSensorsForPropertyId(int propertyId)134     public List<Sensor<?>> getSensorsForPropertyId(int propertyId) {
135         return mSensorsByPropertyId.get(propertyId);
136     }
137 
138     /**
139      * Returns all property ids we care about.
140      */
getPropertyIds()141     public Set<Integer> getPropertyIds() {
142         return mSensorsByPropertyId.keySet();
143     }
144 }
145