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