1 /* 2 * Copyright (C) 2017 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 com.android.car.vehiclehal; 18 19 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 20 import android.util.JsonReader; 21 import android.util.Log; 22 import android.util.SparseArray; 23 import com.android.car.vehiclehal.Utils.SparseArrayIterator; 24 import java.io.IOException; 25 import java.util.Objects; 26 import java.util.Optional; 27 28 public class DiagnosticJson { 29 public final String type; 30 public final long timestamp; 31 public final SparseArray<Integer> intValues; 32 public final SparseArray<Float> floatValues; 33 public final String dtc; 34 DiagnosticJson( String type, long timestamp, SparseArray<Integer> intValues, SparseArray<Float> floatValues, String dtc)35 DiagnosticJson( 36 String type, 37 long timestamp, 38 SparseArray<Integer> intValues, 39 SparseArray<Float> floatValues, 40 String dtc) { 41 this.type = type; 42 this.timestamp = timestamp; 43 this.intValues = Objects.requireNonNull(intValues); 44 this.floatValues = Objects.requireNonNull(floatValues); 45 this.dtc = dtc; 46 } 47 build(DiagnosticEventBuilder builder)48 VehiclePropValue build(DiagnosticEventBuilder builder) { 49 new SparseArrayIterator<>(intValues) 50 .forEach( 51 (SparseArrayIterator.SparseArrayEntry<Integer> entry) -> 52 builder.addIntSensor(entry.key, entry.value)); 53 new SparseArrayIterator<>(floatValues) 54 .forEach( 55 (SparseArrayIterator.SparseArrayEntry<Float> entry) -> 56 builder.addFloatSensor(entry.key, entry.value)); 57 builder.setDTC(dtc); 58 VehiclePropValue vehiclePropValue = builder.build(timestamp); 59 builder.clear(); 60 return vehiclePropValue; 61 } 62 63 static class Builder { 64 public static final String TAG = Builder.class.getSimpleName(); 65 66 static class WriteOnce<T> { 67 private Optional<T> mValue = Optional.empty(); 68 write(T value)69 void write(T value) { 70 if (mValue.isPresent()) throw new IllegalStateException("WriteOnce already stored"); 71 mValue = Optional.of(value); 72 } 73 get()74 T get() { 75 if (!mValue.isPresent()) throw new IllegalStateException("WriteOnce never stored"); 76 return mValue.get(); 77 } 78 get(T defaultValue)79 T get(T defaultValue) { 80 return mValue.isPresent() ? mValue.get() : defaultValue; 81 } 82 } 83 84 final WriteOnce<String> mType = new WriteOnce<>(); 85 final WriteOnce<Long> mTimestamp = new WriteOnce<>(); 86 final SparseArray<Integer> mIntValues = new SparseArray<>(); 87 final SparseArray<Float> mFloatValues = new SparseArray<>(); 88 final WriteOnce<String> mDtc = new WriteOnce<>(); 89 readIntValues(JsonReader jsonReader)90 private void readIntValues(JsonReader jsonReader) throws IOException { 91 while (jsonReader.hasNext()) { 92 int id = 0; 93 int value = 0; 94 jsonReader.beginObject(); 95 while (jsonReader.hasNext()) { 96 String name = jsonReader.nextName(); 97 if (name.equals("id")) id = jsonReader.nextInt(); 98 else if (name.equals("value")) value = jsonReader.nextInt(); 99 } 100 jsonReader.endObject(); 101 mIntValues.put(id, value); 102 } 103 } 104 readFloatValues(JsonReader jsonReader)105 private void readFloatValues(JsonReader jsonReader) throws IOException { 106 while (jsonReader.hasNext()) { 107 int id = 0; 108 float value = 0.0f; 109 jsonReader.beginObject(); 110 while (jsonReader.hasNext()) { 111 String name = jsonReader.nextName(); 112 if (name.equals("id")) id = jsonReader.nextInt(); 113 else if (name.equals("value")) value = (float) jsonReader.nextDouble(); 114 } 115 jsonReader.endObject(); 116 mFloatValues.put(id, value); 117 } 118 } 119 Builder(JsonReader jsonReader)120 Builder(JsonReader jsonReader) throws IOException { 121 jsonReader.beginObject(); 122 while (jsonReader.hasNext()) { 123 String name = jsonReader.nextName(); 124 switch (name) { 125 case "type": 126 mType.write(jsonReader.nextString()); 127 break; 128 case "timestamp": 129 mTimestamp.write(jsonReader.nextLong()); 130 break; 131 case "intValues": 132 jsonReader.beginArray(); 133 readIntValues(jsonReader); 134 jsonReader.endArray(); 135 break; 136 case "floatValues": 137 jsonReader.beginArray(); 138 readFloatValues(jsonReader); 139 jsonReader.endArray(); 140 break; 141 case "stringValue": 142 mDtc.write(jsonReader.nextString()); 143 break; 144 default: 145 Log.w(TAG, "Unknown name in diagnostic JSON: " + name); 146 } 147 } 148 jsonReader.endObject(); 149 } 150 build()151 DiagnosticJson build() { 152 return new DiagnosticJson( 153 mType.get(), mTimestamp.get(), mIntValues, mFloatValues, mDtc.get(null)); 154 } 155 } 156 build(JsonReader jsonReader)157 public static DiagnosticJson build(JsonReader jsonReader) throws IOException { 158 return new Builder(jsonReader).build(); 159 } 160 } 161