blob: d0a89d48d08332186f6a157c0610e5674acc0930 [file] [log] [blame]
Enrico Granata6988f002017-02-13 12:07:52 -08001#!/usr/bin/env python3.4
2#
Enrico Granata4c43add2017-03-15 18:01:34 -07003# Copyright (C) 2017 The Android Open Source Project
Enrico Granata6988f002017-02-13 12:07:52 -08004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
Enrico Granata4c43add2017-03-15 18:01:34 -070018# This script generates useful Java representations for the OBD2 sensors
19# defined in Vehicle HAL. It is meant to be as an easy way to update the
20# list of diagnostic sensors and get all downstream users of that information
21# updated in a consistent fashion.
Enrico Granata6988f002017-02-13 12:07:52 -080022
Enrico Granata4c43add2017-03-15 18:01:34 -070023import sys
24sys.dont_write_bytecode = True
25
26import hidl_parser.parser
27
Enrico Granata6988f002017-02-13 12:07:52 -080028class SensorList(object):
29 """A list of sensors ordered by a unique identifier."""
30 def __init__(self, descriptor):
31 self.sensors = []
32 self.id = -1
33 self.descriptor = descriptor
34
35 def addSensor(self, sensor):
36 """Add a new sensor to the list."""
37 if not hasattr(sensor, 'id'):
38 self.id += 1
39 sensor.id = self.id
40 self.sensors.append(sensor)
41
42 def finalizeList(self):
43 """Complete the list, adding well-known sensor information."""
44 self.id -= 1
Enrico Granata6988f002017-02-13 12:07:52 -080045 vendorStartSensor = self.sensorClass("VENDOR_START_INDEX",
46 id="LAST_SYSTEM_INDEX + 1")
47 # make calling finalizeList idempotent
48 self.finalizeList = lambda: self
49 return self
50
51 def __getitem__(self, key):
52 return self.sensors.__getitem__(key)
53
54class SensorPolicy(object):
55 """A formatter object that does processing on sensor data."""
56 @classmethod
57 def indentLines(cls, string, numSpaces):
58 indent = ' ' * numSpaces
59 parts = string.split('\n')
60 parts = [indent + part for part in parts]
61 return '\n'.join(parts) + "\n"
62
63 def sensor(self, theSensor, theSensors):
64 """Produce output for a sensor."""
65 pass
66
67 def prefix(self, theSensors):
68 """Prefix string before any sensor data is generated."""
69 return ""
70
71 def suffix(self):
72 """Suffix string after all sensor data is generated."""
73 return ""
74
75 def indent(self):
76 """Indentation level for individual sensor data."""
77 return 0
78
79 def separator(self):
80 """Separator between individual sensor data entries."""
81 return ""
82
83 def description(self):
84 """A description of this policy."""
85 return "A sensor policy."
86
87 def sensors(self, theSensors):
88 """Produce output for all sensors."""
89 theSensors = theSensors.finalizeList()
90 s = self.prefix(theSensors) + "\n"
91 first = True
92 for theSensor in theSensors:
93 if first:
94 first = False
95 else:
96 s += self.separator()
97 sensorLine = SensorPolicy.indentLines(self.sensor(theSensor,
98 theSensors), self.indent())
99 s += sensorLine
100 s += self.suffix(theSensors) + "\n"
101 return s
102
Enrico Granata6988f002017-02-13 12:07:52 -0800103class JavaSensorPolicy(SensorPolicy):
104 """The sensor policy that emits Java sensor descriptions."""
105 def sensor(self, theSensor, theSensors):
106 sensorName = theSensor.name.replace("_INDEX", "")
107 sensorId = str(theSensor.id).replace("_INDEX", "")
108 return "public static final int " + sensorName + " = " + \
109 str(sensorId) + ";"
110
111 def prefix(self, theSensors):
Enrico Granata4c43add2017-03-15 18:01:34 -0700112 s = " public static final class Obd2%sSensorIndex {\n" % \
113 theSensors.descriptor
114 s += " private Obd2%sSensorIndex() {}\n" % \
115 theSensors.descriptor
Enrico Granata6988f002017-02-13 12:07:52 -0800116 return s
117
118 def suffix(self, theSensors):
Enrico Granata4c43add2017-03-15 18:01:34 -0700119 return " }"
Enrico Granata6988f002017-02-13 12:07:52 -0800120
121 def indent(self):
Enrico Granata4c43add2017-03-15 18:01:34 -0700122 return 8
Enrico Granata6988f002017-02-13 12:07:52 -0800123
124class IntDefSensorPolicy(SensorPolicy):
125 """The sensor policy that emits @IntDef sensor descriptions."""
126 def sensor(self, theSensor, theSensors):
127 sensorName = theSensor.name.replace("_INDEX", "")
128 return "Obd2%sSensorIndex.%s," % (theSensors.descriptor,sensorName)
129
130 def prefix(self, theSensors):
Enrico Granata4c43add2017-03-15 18:01:34 -0700131 return " @Retention(RetentionPolicy.SOURCE)\n @IntDef({"
132
133 def indent(self):
134 return 8
Enrico Granata6988f002017-02-13 12:07:52 -0800135
136 def suffix(self, theSensors):
Enrico Granata4c43add2017-03-15 18:01:34 -0700137 return " })\n public @interface %sSensorIndex {}" % \
138 theSensors.descriptor
Enrico Granata6988f002017-02-13 12:07:52 -0800139
140class SensorMeta(type):
141 """Metaclass for sensor classes."""
142 def __new__(cls, name, parents, dct):
143 sensorList = dct['sensorList']
144 class SensorBase(object):
145 def __init__(self, name, comment=None, id=None):
146 self.name = name
147 self.comment = comment if comment else ""
148 if id: self.id = id
149 sensorList.addSensor(self)
150 def __repr__(self):
151 s = ""
152 if self.comment:
153 s = s + self.comment + "\n"
154 s = s + self.name + " = " + str(self.id)
155 return s
156
157 newClass = super().__new__(cls, name, (SensorBase,), dct)
158 sensorList.sensorClass = newClass
159 return newClass
160
161intSensors = SensorList(descriptor="Integer")
162floatSensors = SensorList(descriptor="Float")
163
164class intSensor(metaclass=SensorMeta):
165 sensorList = intSensors
166
167class floatSensor(metaclass=SensorMeta):
168 sensorList = floatSensors
169
Enrico Granata4c43add2017-03-15 18:01:34 -0700170def applyPolicy(policy, destfile):
Enrico Granata6988f002017-02-13 12:07:52 -0800171 """Given a sensor policy, apply it to all known sensor types"""
Enrico Granata4c43add2017-03-15 18:01:34 -0700172 print(policy.sensors(intSensors), file=destfile)
173 print(policy.sensors(floatSensors), file=destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800174
Enrico Granata4c43add2017-03-15 18:01:34 -0700175def java(destfile):
176 applyPolicy(JavaSensorPolicy(), destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800177
Enrico Granata4c43add2017-03-15 18:01:34 -0700178def intdef(destfile):
179 applyPolicy(IntDefSensorPolicy(), destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800180
Enrico Granata4c43add2017-03-15 18:01:34 -0700181def generate(filepath):
Enrico Granata6988f002017-02-13 12:07:52 -0800182 """Generate data for all sensors."""
Enrico Granata4c43add2017-03-15 18:01:34 -0700183 destfile = open(filepath, "w")
184 print("/*", file=destfile)
185 print(" * Copyright (C) 2017 The Android Open Source Project", file=destfile)
186 print(" *", file=destfile)
187 print(" * Licensed under the Apache License, Version 2.0 (the \"License\");", file=destfile)
188 print(" * you may not use this file except in compliance with the License.", file=destfile)
189 print(" * You may obtain a copy of the License at", file=destfile)
190 print(" *", file=destfile)
191 print(" * http://www.apache.org/licenses/LICENSE-2.0", file=destfile)
192 print(" *", file=destfile)
193 print(" * Unless required by applicable law or agreed to in writing, software", file=destfile)
194 print(" * distributed under the License is distributed on an \"AS IS\" BASIS,", file=destfile)
195 print(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", file=destfile)
196 print(" * See the License for the specific language governing permissions and", file=destfile)
197 print(" * limitations under the License.", file=destfile)
198 print("*/", file=destfile)
199 print("", file=destfile)
200 print("package android.car.hardware;", file=destfile)
201 print("", file=destfile)
202 print("import android.annotation.IntDef;", file=destfile)
203 print("import java.lang.annotation.Retention;", file=destfile)
204 print("import java.lang.annotation.RetentionPolicy;", file=destfile)
205 print("", file=destfile)
206 print("/**", file=destfile)
207 print(" * This class is a container for the indices of integer and float diagnostic sensors.", file=destfile)
208 print(" * These values are extracted from types.hal by packages/services/Car/tools/update-obd2-sensors.py", file=destfile)
209 print(" *", file=destfile)
210 print(" * DO NOT EDIT MANUALLY", file=destfile)
211 print(" *", file=destfile)
212 print(" * @hide", file=destfile)
213 print(" */", file=destfile)
214 print("public final class CarDiagnosticSensorIndices {", file=destfile)
215 java(destfile)
216 intdef(destfile)
217 print("}", file=destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800218
Enrico Granata4c43add2017-03-15 18:01:34 -0700219def load(filepath):
220 """Load sensor data from Vehicle HAL."""
221 ast = hidl_parser.parser.parse(filepath)
222 integerSensors = ast['enums']['Obd2IntegerSensorIndex']
223 floatSensors = ast['enums']['Obd2FloatSensorIndex']
224 for case in integerSensors.cases:
225 intSensor(name=case.name, id=case.value)
226 for case in floatSensors.cases:
227 floatSensor(name=case.name, id=case.value)
Enrico Granata6988f002017-02-13 12:07:52 -0800228
Enrico Granata4c43add2017-03-15 18:01:34 -0700229import os
Enrico Granata6988f002017-02-13 12:07:52 -0800230
Enrico Granata4c43add2017-03-15 18:01:34 -0700231if len(sys.argv) != 3:
232 print('syntax: update-obd2-sensors.py <path/to/types.hal> <path/to/CarDiagnosticSensorIndices.java>')
233 print('This scrippt will parse types.hal, and use the resulting', end='')
234 print('parse tree to generate CarDiagnosticSensorIndices.java.')
235 sys.exit(1)
236load(sys.argv[1])
237generate(sys.argv[2])