| /* |
| * Copyright (C) 2017 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 android.car.diagnostic; |
| |
| import android.annotation.IntDef; |
| import android.annotation.Nullable; |
| import android.annotation.SystemApi; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.JsonWriter; |
| import android.util.SparseArray; |
| import android.util.SparseIntArray; |
| |
| import java.io.IOException; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.Objects; |
| |
| /** |
| * A CarDiagnosticEvent object corresponds to a single diagnostic event frame coming from the car. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class CarDiagnosticEvent implements Parcelable { |
| /** Whether this frame represents a live or a freeze frame */ |
| public final int frameType; |
| |
| /** |
| * When this data was acquired in car or received from car. It is elapsed real-time of data |
| * reception from car in nanoseconds since system boot. |
| */ |
| public final long timestamp; |
| |
| /** |
| * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for |
| * integer valued properties |
| */ |
| private final SparseIntArray mIntValues; |
| |
| /** |
| * Sparse array that contains the mapping of OBD2 diagnostic properties to their values for |
| * float valued properties |
| */ |
| private final SparseArray<Float> mFloatValues; |
| |
| /** |
| * Diagnostic Troubleshooting Code (DTC) that was detected and caused this frame to be stored |
| * (if a freeze frame). Always null for a live frame. |
| */ |
| public final String dtc; |
| |
| public CarDiagnosticEvent(Parcel in) { |
| frameType = in.readInt(); |
| timestamp = in.readLong(); |
| int len = in.readInt(); |
| mFloatValues = new SparseArray<>(len); |
| for (int i = 0; i < len; ++i) { |
| int key = in.readInt(); |
| float value = in.readFloat(); |
| mFloatValues.put(key, value); |
| } |
| len = in.readInt(); |
| mIntValues = new SparseIntArray(len); |
| for (int i = 0; i < len; ++i) { |
| int key = in.readInt(); |
| int value = in.readInt(); |
| mIntValues.put(key, value); |
| } |
| dtc = (String) in.readValue(String.class.getClassLoader()); |
| // version 1 up to here |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(frameType); |
| dest.writeLong(timestamp); |
| dest.writeInt(mFloatValues.size()); |
| for (int i = 0; i < mFloatValues.size(); ++i) { |
| int key = mFloatValues.keyAt(i); |
| dest.writeInt(key); |
| dest.writeFloat(mFloatValues.get(key)); |
| } |
| dest.writeInt(mIntValues.size()); |
| for (int i = 0; i < mIntValues.size(); ++i) { |
| int key = mIntValues.keyAt(i); |
| dest.writeInt(key); |
| dest.writeInt(mIntValues.get(key)); |
| } |
| dest.writeValue(dtc); |
| } |
| |
| /** |
| * Store the contents of this diagnostic event in a JsonWriter. |
| * |
| * The data is stored as a JSON object, with these fields: |
| * type: either "live" or "freeze" depending on the type of frame; |
| * timestamp: the timestamp at which this frame was generated; |
| * intValues: an array of objects each of which has two elements: |
| * id: the integer identifier of the sensor; |
| * value: the integer value of the sensor; |
| * floatValues: an array of objects each of which has two elements: |
| * id: the integer identifier of the sensor; |
| * value: the floating-point value of the sensor; |
| * stringValue: the DTC for a freeze frame, omitted for a live frame |
| */ |
| public void writeToJson(JsonWriter jsonWriter) throws IOException { |
| jsonWriter.beginObject(); |
| |
| jsonWriter.name("type"); |
| switch (frameType) { |
| case CarDiagnosticManager.FRAME_TYPE_LIVE: |
| jsonWriter.value("live"); |
| break; |
| case CarDiagnosticManager.FRAME_TYPE_FREEZE: |
| jsonWriter.value("freeze"); |
| break; |
| default: |
| throw new IllegalStateException("unknown frameType " + frameType); |
| } |
| |
| jsonWriter.name("timestamp").value(timestamp); |
| |
| jsonWriter.name("intValues").beginArray(); |
| for (int i = 0; i < mIntValues.size(); ++i) { |
| jsonWriter.beginObject(); |
| jsonWriter.name("id").value(mIntValues.keyAt(i)); |
| jsonWriter.name("value").value(mIntValues.valueAt(i)); |
| jsonWriter.endObject(); |
| } |
| jsonWriter.endArray(); |
| |
| jsonWriter.name("floatValues").beginArray(); |
| for (int i = 0; i < mFloatValues.size(); ++i) { |
| jsonWriter.beginObject(); |
| jsonWriter.name("id").value(mFloatValues.keyAt(i)); |
| jsonWriter.name("value").value(mFloatValues.valueAt(i)); |
| jsonWriter.endObject(); |
| } |
| jsonWriter.endArray(); |
| |
| if (dtc != null) { |
| jsonWriter.name("stringValue").value(dtc); |
| } |
| |
| jsonWriter.endObject(); |
| } |
| |
| public static final Parcelable.Creator<CarDiagnosticEvent> CREATOR = |
| new Parcelable.Creator<CarDiagnosticEvent>() { |
| public CarDiagnosticEvent createFromParcel(Parcel in) { |
| return new CarDiagnosticEvent(in); |
| } |
| |
| public CarDiagnosticEvent[] newArray(int size) { |
| return new CarDiagnosticEvent[size]; |
| } |
| }; |
| |
| private CarDiagnosticEvent( |
| int frameType, |
| long timestamp, |
| SparseArray<Float> floatValues, |
| SparseIntArray intValues, |
| String dtc) { |
| this.frameType = frameType; |
| this.timestamp = timestamp; |
| mFloatValues = floatValues; |
| mIntValues = intValues; |
| this.dtc = dtc; |
| } |
| |
| /** |
| * This class can be used to incrementally construct a CarDiagnosticEvent. |
| * CarDiagnosticEvent instances are immutable once built. |
| */ |
| public static class Builder { |
| private int mType = CarDiagnosticManager.FRAME_TYPE_LIVE; |
| private long mTimestamp = 0; |
| private SparseArray<Float> mFloatValues = new SparseArray<>(); |
| private SparseIntArray mIntValues = new SparseIntArray(); |
| private String mDtc = null; |
| |
| private Builder(int type) { |
| mType = type; |
| } |
| |
| /** Returns a new Builder for a live frame */ |
| public static Builder newLiveFrameBuilder() { |
| return new Builder(CarDiagnosticManager.FRAME_TYPE_LIVE); |
| } |
| |
| /** Returns a new Builder for a freeze frame */ |
| public static Builder newFreezeFrameBuilder() { |
| return new Builder(CarDiagnosticManager.FRAME_TYPE_FREEZE); |
| } |
| |
| /** |
| * Sets the timestamp for the frame being built |
| * @deprecated Use {@link Builder#setTimeStamp(long)} instead. |
| */ |
| @Deprecated |
| public Builder atTimestamp(long timestamp) { |
| mTimestamp = timestamp; |
| return this; |
| } |
| |
| /** |
| * Sets the timestamp for the frame being built |
| * @param timeStamp timeStamp for CarDiagnosticEvent |
| * @return Builder |
| */ |
| public Builder setTimeStamp(long timeStamp) { |
| mTimestamp = timeStamp; |
| return this; |
| } |
| |
| /** |
| * Adds an integer-valued sensor to the frame being built |
| * @deprecated Use {@link Builder#setIntValue(int, int)} instead. |
| */ |
| @Deprecated |
| public Builder withIntValue(int key, int value) { |
| mIntValues.put(key, value); |
| return this; |
| } |
| |
| /** |
| * Adds an integer-valued sensor to the frame being built |
| * @param key key of integer value |
| * @param value int value |
| * @return Builder |
| */ |
| public Builder setIntValue(int key, int value) { |
| mIntValues.put(key, value); |
| return this; |
| } |
| |
| /** |
| * Adds a float-valued sensor to the frame being built |
| * @deprecated Use {@link Builder#setFloatValue(int, float)} instead. |
| */ |
| @Deprecated |
| public Builder withFloatValue(int key, float value) { |
| mFloatValues.put(key, value); |
| return this; |
| } |
| |
| /** |
| * Adds a float-valued sensor to the frame being built |
| * @param key key of float value |
| * @param value float value |
| * @return Builder |
| */ |
| public Builder setFloatValue(int key, float value) { |
| mFloatValues.put(key, value); |
| return this; |
| } |
| |
| /** |
| * Sets the DTC for the frame being built |
| * @deprecated Use {@link Builder#setDtc(String)} instead. |
| */ |
| @Deprecated |
| public Builder withDtc(String dtc) { |
| mDtc = dtc; |
| return this; |
| } |
| |
| /** |
| * Sets the DTC for the frame being built |
| * @param dtc string value of CarDiagnosticEvent |
| * @return Builder |
| */ |
| public Builder setDtc(String dtc) { |
| mDtc = dtc; |
| return this; |
| } |
| |
| /** Builds and returns the CarDiagnosticEvent */ |
| public CarDiagnosticEvent build() { |
| return new CarDiagnosticEvent(mType, mTimestamp, mFloatValues, mIntValues, mDtc); |
| } |
| } |
| |
| /** |
| * Returns a copy of this CarDiagnosticEvent with all vendor-specific sensors removed. |
| * |
| * @hide |
| */ |
| public CarDiagnosticEvent withVendorSensorsRemoved() { |
| SparseIntArray newIntValues = mIntValues.clone(); |
| SparseArray<Float> newFloatValues = mFloatValues.clone(); |
| for (int i = 0; i < mIntValues.size(); ++i) { |
| int key = mIntValues.keyAt(i); |
| if (key >= android.car.diagnostic.IntegerSensorIndex.LAST_SYSTEM) { |
| newIntValues.delete(key); |
| } |
| } |
| for (int i = 0; i < mFloatValues.size(); ++i) { |
| int key = mFloatValues.keyAt(i); |
| if (key >= android.car.diagnostic.FloatSensorIndex.LAST_SYSTEM) { |
| newFloatValues.delete(key); |
| } |
| } |
| return new CarDiagnosticEvent(frameType, timestamp, newFloatValues, newIntValues, dtc); |
| } |
| |
| /** Returns true if this object is a live frame, false otherwise */ |
| public boolean isLiveFrame() { |
| return CarDiagnosticManager.FRAME_TYPE_LIVE == frameType; |
| } |
| |
| /** Returns true if this object is a freeze frame, false otherwise */ |
| public boolean isFreezeFrame() { |
| return CarDiagnosticManager.FRAME_TYPE_FREEZE == frameType; |
| } |
| |
| /** @hide */ |
| public boolean isEmptyFrame() { |
| boolean empty = (0 == mIntValues.size()); |
| empty &= (0 == mFloatValues.size()); |
| if (isFreezeFrame()) empty &= dtc.isEmpty(); |
| return empty; |
| } |
| |
| /** @hide */ |
| public CarDiagnosticEvent checkLiveFrame() { |
| if (!isLiveFrame()) throw new IllegalStateException("frame is not a live frame"); |
| return this; |
| } |
| |
| /** @hide */ |
| public CarDiagnosticEvent checkFreezeFrame() { |
| if (!isFreezeFrame()) throw new IllegalStateException("frame is not a freeze frame"); |
| return this; |
| } |
| |
| /** @hide */ |
| public boolean isEarlierThan(CarDiagnosticEvent otherEvent) { |
| Objects.requireNonNull(otherEvent); |
| return (timestamp < otherEvent.timestamp); |
| } |
| |
| @Override |
| public boolean equals(Object otherObject) { |
| if (this == otherObject) { |
| return true; |
| } |
| if (null == otherObject) { |
| return false; |
| } |
| if (!(otherObject instanceof CarDiagnosticEvent)) { |
| return false; |
| } |
| CarDiagnosticEvent otherEvent = (CarDiagnosticEvent) otherObject; |
| if (otherEvent.frameType != frameType) { |
| return false; |
| } |
| if (otherEvent.timestamp != timestamp) { |
| return false; |
| } |
| if (otherEvent.mIntValues.size() != mIntValues.size()) { |
| return false; |
| } |
| if (otherEvent.mFloatValues.size() != mFloatValues.size()) { |
| return false; |
| } |
| if (!Objects.equals(dtc, otherEvent.dtc)) { |
| return false; |
| } |
| for (int i = 0; i < mIntValues.size(); ++i) { |
| int key = mIntValues.keyAt(i); |
| int otherKey = otherEvent.mIntValues.keyAt(i); |
| if (key != otherKey) { |
| return false; |
| } |
| int value = mIntValues.valueAt(i); |
| int otherValue = otherEvent.mIntValues.valueAt(i); |
| if (value != otherValue) { |
| return false; |
| } |
| } |
| for (int i = 0; i < mFloatValues.size(); ++i) { |
| int key = mFloatValues.keyAt(i); |
| int otherKey = otherEvent.mFloatValues.keyAt(i); |
| if (key != otherKey) { |
| return false; |
| } |
| float value = mFloatValues.valueAt(i); |
| float otherValue = otherEvent.mFloatValues.valueAt(i); |
| if (value != otherValue) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| Integer[] intKeys = new Integer[mIntValues.size()]; |
| Integer[] floatKeys = new Integer[mFloatValues.size()]; |
| Integer[] intValues = new Integer[intKeys.length]; |
| Float[] floatValues = new Float[floatKeys.length]; |
| for (int i = 0; i < intKeys.length; ++i) { |
| intKeys[i] = mIntValues.keyAt(i); |
| intValues[i] = mIntValues.valueAt(i); |
| } |
| for (int i = 0; i < floatKeys.length; ++i) { |
| floatKeys[i] = mFloatValues.keyAt(i); |
| floatValues[i] = mFloatValues.valueAt(i); |
| } |
| int intKeysHash = Objects.hash((Object[]) intKeys); |
| int intValuesHash = Objects.hash((Object[]) intValues); |
| int floatKeysHash = Objects.hash((Object[]) floatKeys); |
| int floatValuesHash = Objects.hash((Object[]) floatValues); |
| return Objects.hash(frameType, |
| timestamp, |
| dtc, |
| intKeysHash, |
| intValuesHash, |
| floatKeysHash, |
| floatValuesHash); |
| } |
| |
| @Override |
| public String toString() { |
| return String.format( |
| "%s diagnostic frame {\n" |
| + "\ttimestamp: %d, " |
| + "DTC: %s\n" |
| + "\tmIntValues: %s\n" |
| + "\tmFloatValues: %s\n}", |
| isLiveFrame() ? "live" : "freeze", |
| timestamp, |
| dtc, |
| mIntValues.toString(), |
| mFloatValues.toString()); |
| } |
| |
| /** |
| * Returns the value of the given integer sensor, if present in this frame. |
| * Returns defaultValue otherwise. |
| */ |
| public int getSystemIntegerSensor( |
| @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor, int defaultValue) { |
| return mIntValues.get(sensor, defaultValue); |
| } |
| |
| /** |
| * Returns the value of the given float sensor, if present in this frame. |
| * Returns defaultValue otherwise. |
| */ |
| public float getSystemFloatSensor( |
| @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor, float defaultValue) { |
| return mFloatValues.get(sensor, defaultValue); |
| } |
| |
| /** |
| * Returns the value of the given integer sensor, if present in this frame. |
| * Returns defaultValue otherwise. |
| */ |
| public int getVendorIntegerSensor(int sensor, int defaultValue) { |
| return mIntValues.get(sensor, defaultValue); |
| } |
| |
| /** |
| * Returns the value of the given float sensor, if present in this frame. |
| * Returns defaultValue otherwise. |
| */ |
| public float getVendorFloatSensor(int sensor, float defaultValue) { |
| return mFloatValues.get(sensor, defaultValue); |
| } |
| |
| /** |
| * Returns the value of the given integer sensor, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable Integer getSystemIntegerSensor( |
| @android.car.diagnostic.IntegerSensorIndex.SensorIndex int sensor) { |
| int index = mIntValues.indexOfKey(sensor); |
| if (index < 0) return null; |
| return mIntValues.valueAt(index); |
| } |
| |
| /** |
| * Returns the value of the given float sensor, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable Float getSystemFloatSensor( |
| @android.car.diagnostic.FloatSensorIndex.SensorIndex int sensor) { |
| int index = mFloatValues.indexOfKey(sensor); |
| if (index < 0) return null; |
| return mFloatValues.valueAt(index); |
| } |
| |
| /** |
| * Returns the value of the given integer sensor, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable Integer getVendorIntegerSensor(int sensor) { |
| int index = mIntValues.indexOfKey(sensor); |
| if (index < 0) return null; |
| return mIntValues.valueAt(index); |
| } |
| |
| /** |
| * Returns the value of the given float sensor, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable Float getVendorFloatSensor(int sensor) { |
| int index = mFloatValues.indexOfKey(sensor); |
| if (index < 0) return null; |
| return mFloatValues.valueAt(index); |
| } |
| |
| /** |
| * Represents possible states of the fuel system; see {@link |
| * android.car.diagnostic.IntegerSensorIndex#FUEL_SYSTEM_STATUS} |
| */ |
| public static final class FuelSystemStatus { |
| private FuelSystemStatus() {} |
| |
| public static final int OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1; |
| public static final int CLOSED_LOOP = 2; |
| public static final int OPEN_ENGINE_LOAD_OR_DECELERATION = 4; |
| public static final int OPEN_SYSTEM_FAILURE = 8; |
| public static final int CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16; |
| |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({ |
| OPEN_INSUFFICIENT_ENGINE_TEMPERATURE, |
| CLOSED_LOOP, |
| OPEN_ENGINE_LOAD_OR_DECELERATION, |
| OPEN_SYSTEM_FAILURE, |
| CLOSED_LOOP_BUT_FEEDBACK_FAULT |
| }) |
| public @interface Status {} |
| } |
| |
| /** |
| * Represents possible states of the secondary air system; see {@link |
| * android.car.diagnostic.IntegerSensorIndex#COMMANDED_SECONDARY_AIR_STATUS} |
| */ |
| public static final class SecondaryAirStatus { |
| private SecondaryAirStatus() {} |
| |
| public static final int UPSTREAM = 1; |
| public static final int DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2; |
| public static final int FROM_OUTSIDE_OR_OFF = 4; |
| public static final int PUMP_ON_FOR_DIAGNOSTICS = 8; |
| |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({ |
| UPSTREAM, |
| DOWNSTREAM_OF_CATALYCIC_CONVERTER, |
| FROM_OUTSIDE_OR_OFF, |
| PUMP_ON_FOR_DIAGNOSTICS |
| }) |
| public @interface Status {} |
| } |
| |
| /** |
| * Represents possible types of fuel; see {@link |
| * android.car.diagnostic.IntegerSensorIndex#FUEL_TYPE} |
| */ |
| public static final class FuelType { |
| private FuelType() {} |
| |
| public static final int NOT_AVAILABLE = 0; |
| public static final int GASOLINE = 1; |
| public static final int METHANOL = 2; |
| public static final int ETHANOL = 3; |
| public static final int DIESEL = 4; |
| public static final int LPG = 5; |
| public static final int CNG = 6; |
| public static final int PROPANE = 7; |
| public static final int ELECTRIC = 8; |
| public static final int BIFUEL_RUNNING_GASOLINE = 9; |
| public static final int BIFUEL_RUNNING_METHANOL = 10; |
| public static final int BIFUEL_RUNNING_ETHANOL = 11; |
| public static final int BIFUEL_RUNNING_LPG = 12; |
| public static final int BIFUEL_RUNNING_CNG = 13; |
| public static final int BIFUEL_RUNNING_PROPANE = 14; |
| public static final int BIFUEL_RUNNING_ELECTRIC = 15; |
| public static final int BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16; |
| public static final int HYBRID_GASOLINE = 17; |
| public static final int HYBRID_ETHANOL = 18; |
| public static final int HYBRID_DIESEL = 19; |
| public static final int HYBRID_ELECTRIC = 20; |
| public static final int HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21; |
| public static final int HYBRID_REGENERATIVE = 22; |
| public static final int BIFUEL_RUNNING_DIESEL = 23; |
| |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({ |
| NOT_AVAILABLE, |
| GASOLINE, |
| METHANOL, |
| ETHANOL, |
| DIESEL, |
| LPG, |
| CNG, |
| PROPANE, |
| ELECTRIC, |
| BIFUEL_RUNNING_GASOLINE, |
| BIFUEL_RUNNING_METHANOL, |
| BIFUEL_RUNNING_ETHANOL, |
| BIFUEL_RUNNING_LPG, |
| BIFUEL_RUNNING_CNG, |
| BIFUEL_RUNNING_PROPANE, |
| BIFUEL_RUNNING_ELECTRIC, |
| BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION, |
| HYBRID_GASOLINE, |
| HYBRID_ETHANOL, |
| HYBRID_DIESEL, |
| HYBRID_ELECTRIC, |
| HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION, |
| HYBRID_REGENERATIVE, |
| BIFUEL_RUNNING_DIESEL |
| }) |
| public @interface Type {} |
| } |
| |
| /** |
| * Represents the state of an ignition monitor on a vehicle. |
| */ |
| public static final class IgnitionMonitor { |
| public final boolean available; |
| public final boolean incomplete; |
| |
| IgnitionMonitor(boolean available, boolean incomplete) { |
| this.available = available; |
| this.incomplete = incomplete; |
| } |
| |
| /** @hide */ |
| public static final class Decoder { |
| private final int mAvailableBitmask; |
| private final int mIncompleteBitmask; |
| |
| Decoder(int availableBitmask, int incompleteBitmask) { |
| mAvailableBitmask = availableBitmask; |
| mIncompleteBitmask = incompleteBitmask; |
| } |
| |
| /** |
| * Returns the {@link IgnitionMonitor} associated with the value passed as parameter. |
| */ |
| public IgnitionMonitor fromValue(int value) { |
| boolean available = (0 != (value & mAvailableBitmask)); |
| boolean incomplete = (0 != (value & mIncompleteBitmask)); |
| |
| return new IgnitionMonitor(available, incomplete); |
| } |
| } |
| } |
| |
| /** |
| * Contains information about ignition monitors common to all vehicle types. |
| */ |
| public static class CommonIgnitionMonitors { |
| public final IgnitionMonitor components; |
| public final IgnitionMonitor fuelSystem; |
| public final IgnitionMonitor misfire; |
| |
| /** @hide */ |
| public static final int COMPONENTS_AVAILABLE = 0x1 << 0; |
| /** @hide */ |
| public static final int COMPONENTS_INCOMPLETE = 0x1 << 1; |
| |
| /** @hide */ |
| public static final int FUEL_SYSTEM_AVAILABLE = 0x1 << 2; |
| /** @hide */ |
| public static final int FUEL_SYSTEM_INCOMPLETE = 0x1 << 3; |
| |
| /** @hide */ |
| public static final int MISFIRE_AVAILABLE = 0x1 << 4; |
| /** @hide */ |
| public static final int MISFIRE_INCOMPLETE = 0x1 << 5; |
| |
| static final IgnitionMonitor.Decoder COMPONENTS_DECODER = |
| new IgnitionMonitor.Decoder(COMPONENTS_AVAILABLE, COMPONENTS_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder FUEL_SYSTEM_DECODER = |
| new IgnitionMonitor.Decoder(FUEL_SYSTEM_AVAILABLE, FUEL_SYSTEM_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder MISFIRE_DECODER = |
| new IgnitionMonitor.Decoder(MISFIRE_AVAILABLE, MISFIRE_INCOMPLETE); |
| |
| CommonIgnitionMonitors(int bitmask) { |
| components = COMPONENTS_DECODER.fromValue(bitmask); |
| fuelSystem = FUEL_SYSTEM_DECODER.fromValue(bitmask); |
| misfire = MISFIRE_DECODER.fromValue(bitmask); |
| } |
| |
| /** |
| * Returns data about ignition monitors specific to spark vehicles, if this |
| * object represents ignition monitors for a spark vehicle. |
| * Returns null otherwise. |
| */ |
| public @Nullable SparkIgnitionMonitors asSparkIgnitionMonitors() { |
| if (this instanceof SparkIgnitionMonitors) return (SparkIgnitionMonitors) this; |
| return null; |
| } |
| |
| /** |
| * Returns data about ignition monitors specific to compression vehicles, if this |
| * object represents ignition monitors for a compression vehicle. |
| * Returns null otherwise. |
| */ |
| public @Nullable CompressionIgnitionMonitors asCompressionIgnitionMonitors() { |
| if (this instanceof CompressionIgnitionMonitors) { |
| return (CompressionIgnitionMonitors) this; |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Contains information about ignition monitors specific to spark vehicles. |
| */ |
| public static final class SparkIgnitionMonitors extends CommonIgnitionMonitors { |
| public final IgnitionMonitor EGR; |
| public final IgnitionMonitor oxygenSensorHeater; |
| public final IgnitionMonitor oxygenSensor; |
| public final IgnitionMonitor ACRefrigerant; |
| public final IgnitionMonitor secondaryAirSystem; |
| public final IgnitionMonitor evaporativeSystem; |
| public final IgnitionMonitor heatedCatalyst; |
| public final IgnitionMonitor catalyst; |
| |
| /** @hide */ |
| public static final int EGR_AVAILABLE = 0x1 << 6; |
| /** @hide */ |
| public static final int EGR_INCOMPLETE = 0x1 << 7; |
| |
| /** @hide */ |
| public static final int OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8; |
| /** @hide */ |
| public static final int OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9; |
| |
| /** @hide */ |
| public static final int OXYGEN_SENSOR_AVAILABLE = 0x1 << 10; |
| /** @hide */ |
| public static final int OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11; |
| |
| /** @hide */ |
| public static final int AC_REFRIGERANT_AVAILABLE = 0x1 << 12; |
| /** @hide */ |
| public static final int AC_REFRIGERANT_INCOMPLETE = 0x1 << 13; |
| |
| /** @hide */ |
| public static final int SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14; |
| /** @hide */ |
| public static final int SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15; |
| |
| /** @hide */ |
| public static final int EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16; |
| /** @hide */ |
| public static final int EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17; |
| |
| /** @hide */ |
| public static final int HEATED_CATALYST_AVAILABLE = 0x1 << 18; |
| /** @hide */ |
| public static final int HEATED_CATALYST_INCOMPLETE = 0x1 << 19; |
| |
| /** @hide */ |
| public static final int CATALYST_AVAILABLE = 0x1 << 20; |
| /** @hide */ |
| public static final int CATALYST_INCOMPLETE = 0x1 << 21; |
| |
| static final IgnitionMonitor.Decoder EGR_DECODER = |
| new IgnitionMonitor.Decoder(EGR_AVAILABLE, EGR_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder OXYGEN_SENSOR_HEATER_DECODER = |
| new IgnitionMonitor.Decoder(OXYGEN_SENSOR_HEATER_AVAILABLE, |
| OXYGEN_SENSOR_HEATER_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder OXYGEN_SENSOR_DECODER = |
| new IgnitionMonitor.Decoder(OXYGEN_SENSOR_AVAILABLE, OXYGEN_SENSOR_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder AC_REFRIGERANT_DECODER = |
| new IgnitionMonitor.Decoder(AC_REFRIGERANT_AVAILABLE, |
| AC_REFRIGERANT_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder SECONDARY_AIR_SYSTEM_DECODER = |
| new IgnitionMonitor.Decoder(SECONDARY_AIR_SYSTEM_AVAILABLE, |
| SECONDARY_AIR_SYSTEM_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder EVAPORATIVE_SYSTEM_DECODER = |
| new IgnitionMonitor.Decoder(EVAPORATIVE_SYSTEM_AVAILABLE, |
| EVAPORATIVE_SYSTEM_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder HEATED_CATALYST_DECODER = |
| new IgnitionMonitor.Decoder(HEATED_CATALYST_AVAILABLE, |
| HEATED_CATALYST_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder CATALYST_DECODER = |
| new IgnitionMonitor.Decoder(CATALYST_AVAILABLE, CATALYST_INCOMPLETE); |
| |
| SparkIgnitionMonitors(int bitmask) { |
| super(bitmask); |
| EGR = EGR_DECODER.fromValue(bitmask); |
| oxygenSensorHeater = OXYGEN_SENSOR_HEATER_DECODER.fromValue(bitmask); |
| oxygenSensor = OXYGEN_SENSOR_DECODER.fromValue(bitmask); |
| ACRefrigerant = AC_REFRIGERANT_DECODER.fromValue(bitmask); |
| secondaryAirSystem = SECONDARY_AIR_SYSTEM_DECODER.fromValue(bitmask); |
| evaporativeSystem = EVAPORATIVE_SYSTEM_DECODER.fromValue(bitmask); |
| heatedCatalyst = HEATED_CATALYST_DECODER.fromValue(bitmask); |
| catalyst = CATALYST_DECODER.fromValue(bitmask); |
| } |
| } |
| |
| /** |
| * Contains information about ignition monitors specific to compression vehicles. |
| */ |
| public static final class CompressionIgnitionMonitors extends CommonIgnitionMonitors { |
| public final IgnitionMonitor EGROrVVT; |
| public final IgnitionMonitor PMFilter; |
| public final IgnitionMonitor exhaustGasSensor; |
| public final IgnitionMonitor boostPressure; |
| public final IgnitionMonitor NOxSCR; |
| public final IgnitionMonitor NMHCCatalyst; |
| |
| /** @hide */ |
| public static final int EGR_OR_VVT_AVAILABLE = 0x1 << 6; |
| /** @hide */ |
| public static final int EGR_OR_VVT_INCOMPLETE = 0x1 << 7; |
| |
| /** @hide */ |
| public static final int PM_FILTER_AVAILABLE = 0x1 << 8; |
| /** @hide */ |
| public static final int PM_FILTER_INCOMPLETE = 0x1 << 9; |
| |
| /** @hide */ |
| public static final int EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10; |
| /** @hide */ |
| public static final int EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11; |
| |
| /** @hide */ |
| public static final int BOOST_PRESSURE_AVAILABLE = 0x1 << 12; |
| /** @hide */ |
| public static final int BOOST_PRESSURE_INCOMPLETE = 0x1 << 13; |
| |
| /** @hide */ |
| public static final int NOx_SCR_AVAILABLE = 0x1 << 14; |
| /** @hide */ |
| public static final int NOx_SCR_INCOMPLETE = 0x1 << 15; |
| |
| /** @hide */ |
| public static final int NMHC_CATALYST_AVAILABLE = 0x1 << 16; |
| /** @hide */ |
| public static final int NMHC_CATALYST_INCOMPLETE = 0x1 << 17; |
| |
| static final IgnitionMonitor.Decoder EGR_OR_VVT_DECODER = |
| new IgnitionMonitor.Decoder(EGR_OR_VVT_AVAILABLE, EGR_OR_VVT_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder PM_FILTER_DECODER = |
| new IgnitionMonitor.Decoder(PM_FILTER_AVAILABLE, PM_FILTER_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder EXHAUST_GAS_SENSOR_DECODER = |
| new IgnitionMonitor.Decoder(EXHAUST_GAS_SENSOR_AVAILABLE, |
| EXHAUST_GAS_SENSOR_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder BOOST_PRESSURE_DECODER = |
| new IgnitionMonitor.Decoder(BOOST_PRESSURE_AVAILABLE, |
| BOOST_PRESSURE_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder NOx_SCR_DECODER = |
| new IgnitionMonitor.Decoder(NOx_SCR_AVAILABLE, NOx_SCR_INCOMPLETE); |
| |
| static final IgnitionMonitor.Decoder NMHC_CATALYST_DECODER = |
| new IgnitionMonitor.Decoder(NMHC_CATALYST_AVAILABLE, NMHC_CATALYST_INCOMPLETE); |
| |
| CompressionIgnitionMonitors(int bitmask) { |
| super(bitmask); |
| EGROrVVT = EGR_OR_VVT_DECODER.fromValue(bitmask); |
| PMFilter = PM_FILTER_DECODER.fromValue(bitmask); |
| exhaustGasSensor = EXHAUST_GAS_SENSOR_DECODER.fromValue(bitmask); |
| boostPressure = BOOST_PRESSURE_DECODER.fromValue(bitmask); |
| NOxSCR = NOx_SCR_DECODER.fromValue(bitmask); |
| NMHCCatalyst = NMHC_CATALYST_DECODER.fromValue(bitmask); |
| } |
| } |
| |
| /** |
| * Returns the state of the fuel system, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable @FuelSystemStatus.Status Integer getFuelSystemStatus() { |
| return getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.FUEL_SYSTEM_STATUS); |
| } |
| |
| /** |
| * Returns the state of the secondary air system, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable @SecondaryAirStatus.Status Integer getSecondaryAirStatus() { |
| return getSystemIntegerSensor( |
| android.car.diagnostic.IntegerSensorIndex.COMMANDED_SECONDARY_AIR_STATUS); |
| } |
| |
| /** |
| * Returns data about the ignition monitors, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable CommonIgnitionMonitors getIgnitionMonitors() { |
| Integer ignitionMonitorsType = |
| getSystemIntegerSensor( |
| android.car.diagnostic.IntegerSensorIndex.IGNITION_MONITORS_SUPPORTED); |
| Integer ignitionMonitorsBitmask = |
| getSystemIntegerSensor( |
| android.car.diagnostic.IntegerSensorIndex.IGNITION_SPECIFIC_MONITORS); |
| if (null == ignitionMonitorsType) return null; |
| if (null == ignitionMonitorsBitmask) return null; |
| switch (ignitionMonitorsType) { |
| case 0: |
| return new SparkIgnitionMonitors(ignitionMonitorsBitmask); |
| case 1: |
| return new CompressionIgnitionMonitors(ignitionMonitorsBitmask); |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the fuel type, if present in this frame. |
| * Returns null otherwise. |
| */ |
| public @Nullable @FuelType.Type Integer getFuelType() { |
| return getSystemIntegerSensor(android.car.diagnostic.IntegerSensorIndex.FUEL_TYPE); |
| } |
| } |