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