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 android.car.hardware;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 
23 /**
24  * A CarSensorEvent object corresponds to a single sensor event coming from the car. The sensor
25  * data is stored in a sensor-type specific format in the object's float and byte arrays.
26  *
27  * To aid unmarshalling the object's data arrays, this class provides static nested classes and
28  * conversion methods, for example {@link EnvironmentData} and {@link #getEnvironmentData}. The
29  * conversion methods each have an optional data parameter which, if not null, will be used and
30  * returned. This parameter should be used to avoid unnecessary object churn whenever possible.
31  * Additionally, calling a conversion method on a CarSensorEvent object with an inappropriate type
32  * will result in an {@code UnsupportedOperationException} being thrown.
33  */
34 public class CarSensorEvent implements Parcelable {
35 
36     /**
37      * Index in {@link #floatValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
38      * sensor. This value is fuel level in percentile.
39      */
40     public static final int INDEX_FUEL_LEVEL_IN_PERCENTILE = 0;
41     /**
42      * Index in {@link #floatValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
43      * sensor. This value is fuel level in coverable distance. The unit is Km.
44      */
45     public static final int INDEX_FUEL_LEVEL_IN_DISTANCE = 1;
46     /**
47      * Index in {@link #intValues} for {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL} type of
48      * sensor. This value is set to 1 if fuel low level warning is on.
49      */
50     public static final int INDEX_FUEL_LOW_WARNING = 0;
51 
52     /**
53      *  GEAR_* represents meaning of intValues[0] for {@link CarSensorManager#SENSOR_TYPE_GEAR}
54      *  sensor type.
55      *  GEAR_NEUTRAL means transmission gear is in neutral state, and the car may be moving.
56      */
57     public static final int GEAR_NEUTRAL    = 0;
58     /**
59      * intValues[0] from 1 to 99 represents transmission gear number for moving forward.
60      * GEAR_FIRST is for gear number 1.
61      */
62     public static final int GEAR_FIRST      = 1;
63     /** Gear number 2. */
64     public static final int GEAR_SECOND     = 2;
65     /** Gear number 3. */
66     public static final int GEAR_THIRD      = 3;
67     /** Gear number 4. */
68     public static final int GEAR_FOURTH     = 4;
69     /** Gear number 5. */
70     public static final int GEAR_FIFTH      = 5;
71     /** Gear number 6. */
72     public static final int GEAR_SIXTH      = 6;
73     /** Gear number 7. */
74     public static final int GEAR_SEVENTH    = 7;
75     /** Gear number 8. */
76     public static final int GEAR_EIGHTH     = 8;
77     /** Gear number 9. */
78     public static final int GEAR_NINTH      = 9;
79     /** Gear number 10. */
80     public static final int GEAR_TENTH      = 10;
81     /**
82      * This is for transmission without specific gear number for moving forward like CVT. It tells
83      * that car is in a transmission state to move it forward.
84      */
85     public static final int GEAR_DRIVE      = 100;
86     /** Gear in parking state */
87     public static final int GEAR_PARK       = 101;
88     /** Gear in reverse */
89     public static final int GEAR_REVERSE    = 102;
90 
91     /**
92      * Bitmask of driving restrictions.
93      */
94     /** No restrictions. */
95     public static final int DRIVE_STATUS_UNRESTRICTED = 0;
96     /** No video playback allowed. */
97     public static final int DRIVE_STATUS_NO_VIDEO = 0x1;
98     /** No keyboard or rotary controller input allowed. */
99     public static final int DRIVE_STATUS_NO_KEYBOARD_INPUT = 0x2;
100     /** No voice input allowed. */
101     public static final int DRIVE_STATUS_NO_VOICE_INPUT = 0x4;
102     /** No setup / configuration allowed. */
103     public static final int DRIVE_STATUS_NO_CONFIG = 0x8;
104     /** Limit displayed message length. */
105     public static final int DRIVE_STATUS_LIMIT_MESSAGE_LEN = 0x10;
106     /** represents case where all of the above items are restricted */
107     public static final int DRIVE_STATUS_FULLY_RESTRICTED = DRIVE_STATUS_NO_VIDEO |
108             DRIVE_STATUS_NO_KEYBOARD_INPUT | DRIVE_STATUS_NO_VOICE_INPUT | DRIVE_STATUS_NO_CONFIG |
109             DRIVE_STATUS_LIMIT_MESSAGE_LEN;
110 
111     /**
112      * Index for {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT} in floatValues.
113      * Temperature in Celsius degrees.
114      */
115     public static final int INDEX_ENVIRONMENT_TEMPERATURE = 0;
116     /**
117      * Index for {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT} in floatValues.
118      * Pressure in kPa.
119      */
120     public static final int INDEX_ENVIRONMENT_PRESSURE = 1;
121 
122     private static final long MILLI_IN_NANOS = 1000000L;
123 
124     /** Sensor type for this event like {@link CarSensorManager#SENSOR_TYPE_CAR_SPEED}. */
125     public int sensorType;
126 
127     /**
128      * When this data was acquired in car or received from car. It is elapsed real-time of data
129      * reception from car in nanoseconds since system boot.
130      */
131     public long timeStampNs;
132     /**
133      * array holding float type of sensor data. If the sensor has single value, only floatValues[0]
134      * should be used. */
135     public final float[] floatValues;
136     /** array holding int type of sensor data */
137     public final int[] intValues;
138 
CarSensorEvent(Parcel in)139     public CarSensorEvent(Parcel in) {
140         sensorType = in.readInt();
141         timeStampNs = in.readLong();
142         int len = in.readInt();
143         floatValues = new float[len];
144         in.readFloatArray(floatValues);
145         len = in.readInt();
146         intValues = new int[len];
147         in.readIntArray(intValues);
148         // version 1 up to here
149     }
150 
151     @Override
describeContents()152     public int describeContents() {
153         return 0;
154     }
155 
156     @Override
writeToParcel(Parcel dest, int flags)157     public void writeToParcel(Parcel dest, int flags) {
158         dest.writeInt(sensorType);
159         dest.writeLong(timeStampNs);
160         dest.writeInt(floatValues.length);
161         dest.writeFloatArray(floatValues);
162         dest.writeInt(intValues.length);
163         dest.writeIntArray(intValues);
164     }
165 
166     public static final Parcelable.Creator<CarSensorEvent> CREATOR
167     = new Parcelable.Creator<CarSensorEvent>() {
168         public CarSensorEvent createFromParcel(Parcel in) {
169             return new CarSensorEvent(in);
170         }
171 
172         public CarSensorEvent[] newArray(int size) {
173             return new CarSensorEvent[size];
174         }
175     };
176 
CarSensorEvent(int sensorType, long timeStampNs, int floatValueSize, int intValueSize)177     public CarSensorEvent(int sensorType, long timeStampNs, int floatValueSize, int intValueSize) {
178         this.sensorType = sensorType;
179         this.timeStampNs = timeStampNs;
180         floatValues = new float[floatValueSize];
181         intValues = new int[intValueSize];
182     }
183 
184     /** @hide */
CarSensorEvent(int sensorType, long timeStampNs, float[] floatValues, int[] intValues)185     CarSensorEvent(int sensorType, long timeStampNs, float[] floatValues, int[] intValues) {
186         this.sensorType = sensorType;
187         this.timeStampNs = timeStampNs;
188         this.floatValues = floatValues;
189         this.intValues = intValues;
190     }
191 
checkType(int type)192     private void checkType(int type) {
193         if (sensorType == type) {
194             return;
195         }
196         throw new UnsupportedOperationException(String.format(
197                 "Invalid sensor type: expected %d, got %d", type, sensorType));
198     }
199 
200     public static class EnvironmentData {
201         public long timeStampNs;
202         /** If unsupported by the car, this value is NaN. */
203         public float temperature;
204         /** If unsupported by the car, this value is NaN. */
205         public float pressure;
206     }
207 
208     /**
209      * Convenience method for obtaining an {@link EnvironmentData} object from a CarSensorEvent
210      * object with type {@link CarSensorManager#SENSOR_TYPE_ENVIRONMENT}.
211      *
212      * @param data an optional output parameter which, if non-null, will be used by this method
213      *     instead of a newly created object.
214      * @return an EnvironmentData object corresponding to the data contained in the CarSensorEvent.
215      */
getEnvironmentData(EnvironmentData data)216     public EnvironmentData getEnvironmentData(EnvironmentData data) {
217         checkType(CarSensorManager.SENSOR_TYPE_ENVIRONMENT);
218         if (data == null) {
219             data = new EnvironmentData();
220         }
221         data.timeStampNs = timeStampNs;
222         data.temperature = floatValues[INDEX_ENVIRONMENT_TEMPERATURE];
223         data.pressure = floatValues[INDEX_ENVIRONMENT_PRESSURE];
224         return data;
225     }
226 
227     public static class NightData {
228         public long timeStampNs;
229         public boolean isNightMode;
230     }
231 
232     /**
233      * Convenience method for obtaining a {@link NightData} object from a CarSensorEvent
234      * object with type {@link CarSensorManager#SENSOR_TYPE_NIGHT}.
235      *
236      * @param data an optional output parameter which, if non-null, will be used by this method
237      *     instead of a newly created object.
238      * @return a NightData object corresponding to the data contained in the CarSensorEvent.
239      */
getNightData(NightData data)240     public NightData getNightData(NightData data) {
241         checkType(CarSensorManager.SENSOR_TYPE_NIGHT);
242         if (data == null) {
243             data = new NightData();
244         }
245         data.timeStampNs = timeStampNs;
246         data.isNightMode = intValues[0] == 1;
247         return data;
248     }
249 
250     public static class GearData {
251         public long timeStampNs;
252         public int gear;
253     }
254 
255     /**
256      * Convenience method for obtaining a {@link GearData} object from a CarSensorEvent
257      * object with type {@link CarSensorManager#SENSOR_TYPE_GEAR}.
258      *
259      * @param data an optional output parameter which, if non-null, will be used by this method
260      *     instead of a newly created object.
261      * @return a GearData object corresponding to the data contained in the CarSensorEvent.
262      */
getGearData(GearData data)263     public GearData getGearData(GearData data) {
264         checkType(CarSensorManager.SENSOR_TYPE_GEAR);
265         if (data == null) {
266             data = new GearData();
267         }
268         data.timeStampNs = timeStampNs;
269         data.gear = intValues[0];
270         return data;
271     }
272 
273     public static class ParkingBrakeData {
274         public long timeStampNs;
275         public boolean isEngaged;
276     }
277 
278     /**
279      * Convenience method for obtaining a {@link ParkingBrakeData} object from a CarSensorEvent
280      * object with type {@link CarSensorManager#SENSOR_TYPE_PARKING_BRAKE}.
281      *
282      * @param data an optional output parameter which, if non-null, will be used by this method
283      *     instead of a newly created object.
284      * @return a ParkingBreakData object corresponding to the data contained in the CarSensorEvent.
285      */
getParkingBrakeData(ParkingBrakeData data)286     public ParkingBrakeData getParkingBrakeData(ParkingBrakeData data) {
287         checkType(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE);
288         if (data == null) {
289             data = new ParkingBrakeData();
290         }
291         data.timeStampNs = timeStampNs;
292         data.isEngaged = intValues[0] == 1;
293         return data;
294     }
295 
296     public static class FuelLevelData {
297         public long timeStampNs;
298         /** Fuel level in %. If unsupported by the car, this value is -1. */
299         public int level;
300         /** Fuel as possible range in Km. If unsupported by the car, this value is -1. */
301         public float range;
302         /** If unsupported by the car, this value is false. */
303         public boolean lowFuelWarning;
304     }
305 
306     /**
307      * Convenience method for obtaining a {@link FuelLevelData} object from a CarSensorEvent
308      * object with type {@link CarSensorManager#SENSOR_TYPE_FUEL_LEVEL}.
309      *
310      * @param data an optional output parameter which, if non-null, will be used by this method
311      *     instead of a newly created object.
312      * @return a FuelLevel object corresponding to the data contained in the CarSensorEvent.
313      */
getFuelLevelData(FuelLevelData data)314     public FuelLevelData getFuelLevelData(FuelLevelData data) {
315         checkType(CarSensorManager.SENSOR_TYPE_FUEL_LEVEL);
316         if (data == null) {
317             data = new FuelLevelData();
318         }
319         data.timeStampNs = timeStampNs;
320         if (floatValues == null) {
321             data.level = -1;
322             data.range = -1;
323         } else {
324             if (floatValues[INDEX_FUEL_LEVEL_IN_PERCENTILE] < 0) {
325                 data.level = -1;
326             } else {
327                 data.level = (int) floatValues[INDEX_FUEL_LEVEL_IN_PERCENTILE];
328             }
329             if (floatValues[INDEX_FUEL_LEVEL_IN_DISTANCE] < 0) {
330                 data.range = -1;
331             } else {
332                 data.range = floatValues[INDEX_FUEL_LEVEL_IN_DISTANCE];
333             }
334         }
335         data.lowFuelWarning = intValues[0] == 1;
336         return data;
337     }
338 
339     public static class OdometerData {
340         public long timeStampNs;
341         public float kms;
342     }
343 
344     /**
345      * Convenience method for obtaining an {@link OdometerData} object from a CarSensorEvent
346      * object with type {@link CarSensorManager#SENSOR_TYPE_ODOMETER}.
347      *
348      * @param data an optional output parameter which, if non-null, will be used by this method
349      *     instead of a newly created object.
350      * @return an OdometerData object corresponding to the data contained in the CarSensorEvent.
351      */
getOdometerData(OdometerData data)352     public OdometerData getOdometerData(OdometerData data) {
353         checkType(CarSensorManager.SENSOR_TYPE_ODOMETER);
354         if (data == null) {
355             data = new OdometerData();
356         }
357         data.timeStampNs = timeStampNs;
358         data.kms = floatValues[0];
359         return data;
360     }
361 
362     public static class RpmData {
363         public long timeStampNs;
364         public float rpm;
365     }
366 
367     /**
368      * Convenience method for obtaining a {@link RpmData} object from a CarSensorEvent
369      * object with type {@link CarSensorManager#SENSOR_TYPE_RPM}.
370      *
371      * @param data an optional output parameter which, if non-null, will be used by this method
372      *     instead of a newly created object.
373      * @return a RpmData object corresponding to the data contained in the CarSensorEvent.
374      */
getRpmData(RpmData data)375     public RpmData getRpmData(RpmData data) {
376         checkType(CarSensorManager.SENSOR_TYPE_RPM);
377         if (data == null) {
378             data = new RpmData();
379         }
380         data.timeStampNs = timeStampNs;
381         data.rpm = floatValues[0];
382         return data;
383     }
384 
385     public static class CarSpeedData {
386         public long timeStampNs;
387         public float carSpeed;
388     }
389 
390     /**
391      * Convenience method for obtaining a {@link CarSpeedData} object from a CarSensorEvent
392      * object with type {@link CarSensorManager#SENSOR_TYPE_CAR_SPEED}.
393      *
394      * @param data an optional output parameter which, if non-null, will be used by this method
395      *     instead of a newly created object.
396      * @return a CarSpeedData object corresponding to the data contained in the CarSensorEvent.
397      */
getCarSpeedData(CarSpeedData data)398     public CarSpeedData getCarSpeedData(CarSpeedData data) {
399         checkType(CarSensorManager.SENSOR_TYPE_CAR_SPEED);
400         if (data == null) {
401             data = new CarSpeedData();
402         }
403         data.timeStampNs = timeStampNs;
404         data.carSpeed = floatValues[0];
405         return data;
406     }
407 
408     public static class DrivingStatusData {
409         public long timeStampNs;
410         public int status;
411     }
412 
413     /**
414      * Convenience method for obtaining a {@link DrivingStatusData} object from a CarSensorEvent
415      * object with type {@link CarSensorManager#SENSOR_TYPE_DRIVING_STATUS}.
416      *
417      * @param data an optional output parameter which, if non-null, will be used by this method
418      *     instead of a newly created object.
419      * @return a DrivingStatusData object corresponding to the data contained in the CarSensorEvent.
420      */
getDrivingStatusData(DrivingStatusData data)421     public DrivingStatusData getDrivingStatusData(DrivingStatusData data) {
422         checkType(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS);
423         if (data == null) {
424             data = new DrivingStatusData();
425         }
426         data.status = intValues[0];
427         return data;
428     }
429 
430     /** @hide */
431     @Override
toString()432     public String toString() {
433         StringBuilder sb = new StringBuilder();
434         sb.append(getClass().getName() + "[");
435         sb.append("type:" + Integer.toHexString(sensorType));
436         if (floatValues != null && floatValues.length > 0) {
437             sb.append(" float values:");
438             for (float v: floatValues) {
439                 sb.append(" " + v);
440             }
441         }
442         if (intValues != null && intValues.length > 0) {
443             sb.append(" int values:");
444             for (int v: intValues) {
445                 sb.append(" " + v);
446             }
447         }
448         sb.append("]");
449         return sb.toString();
450     }
451 }
452