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
17package com.android.car.obd2;
18
19import android.os.SystemClock;
20import android.util.JsonWriter;
21import android.util.Log;
22import com.android.car.obd2.Obd2Command.LiveFrameCommand;
23import java.io.IOException;
24import java.util.ArrayList;
25import java.util.List;
26import java.util.Optional;
27import java.util.Set;
28
29public class Obd2LiveFrameGenerator {
30    public static final String FRAME_TYPE_LIVE = "live";
31    public static final String TAG = Obd2LiveFrameGenerator.class.getSimpleName();
32
33    private final Obd2Connection mConnection;
34    private final List<LiveFrameCommand<Integer>> mIntegerCommands = new ArrayList<>();
35    private final List<LiveFrameCommand<Float>> mFloatCommands = new ArrayList<>();
36
37    public Obd2LiveFrameGenerator(Obd2Connection connection)
38            throws IOException, InterruptedException {
39        mConnection = connection;
40        Set<Integer> connectionPids = connection.getSupportedPIDs();
41        Set<Integer> apiIntegerPids = Obd2Command.getSupportedIntegerCommands();
42        Set<Integer> apiFloatPids = Obd2Command.getSupportedFloatCommands();
43        apiIntegerPids
44                .stream()
45                .filter(connectionPids::contains)
46                .forEach(
47                        (Integer pid) ->
48                                mIntegerCommands.add(
49                                        Obd2Command.getLiveFrameCommand(
50                                                Obd2Command.getIntegerCommand(pid))));
51        apiFloatPids
52                .stream()
53                .filter(connectionPids::contains)
54                .forEach(
55                        (Integer pid) ->
56                                mFloatCommands.add(
57                                        Obd2Command.getLiveFrameCommand(
58                                                Obd2Command.getFloatCommand(pid))));
59        Log.i(
60                TAG,
61                String.format(
62                        "connectionPids = %s\napiIntegerPids=%s\napiFloatPids = %s\n"
63                                + "mIntegerCommands = %s\nmFloatCommands = %s\n",
64                        connectionPids,
65                        apiIntegerPids,
66                        apiFloatPids,
67                        mIntegerCommands,
68                        mFloatCommands));
69    }
70
71    public JsonWriter generate(JsonWriter jsonWriter) throws IOException {
72        return generate(jsonWriter, SystemClock.elapsedRealtimeNanos());
73    }
74
75    public JsonWriter generate(JsonWriter jsonWriter, long timestamp) throws IOException {
76        jsonWriter.beginObject();
77        jsonWriter.name("type").value(FRAME_TYPE_LIVE);
78        jsonWriter.name("timestamp").value(timestamp);
79        jsonWriter.name("intValues").beginArray();
80        for (LiveFrameCommand<Integer> command : mIntegerCommands) {
81            try {
82                Optional<Integer> result = command.run(mConnection);
83                if (result.isPresent()) {
84                    jsonWriter.beginObject();
85                    jsonWriter.name("id").value(command.getPid());
86                    jsonWriter.name("value").value(result.get());
87                    jsonWriter.endObject();
88                }
89            } catch (IOException | InterruptedException e) {
90                Log.w(
91                        TAG,
92                        String.format(
93                                "unable to retrieve OBD2 pid %d due to exception: %s",
94                                command.getPid(), e));
95                // skip this entry
96            }
97        }
98        jsonWriter.endArray();
99
100        jsonWriter.name("floatValues").beginArray();
101        for (LiveFrameCommand<Float> command : mFloatCommands) {
102            try {
103                Optional<Float> result = command.run(mConnection);
104                if (result.isPresent()) {
105                    jsonWriter.beginObject();
106                    jsonWriter.name("id").value(command.getPid());
107                    jsonWriter.name("value").value(result.get());
108                    jsonWriter.endObject();
109                }
110            } catch (IOException | InterruptedException e) {
111                Log.w(
112                        TAG,
113                        String.format(
114                                "unable to retrieve OBD2 pid %d due to exception: %s",
115                                command.getPid(), e));
116                // skip this entry
117            }
118        }
119        jsonWriter.endArray();
120
121        return jsonWriter.endObject();
122    }
123}
124