blob: e161258558ae4c5a9adfd0b4b33f88d8493fc93c [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
Enrico Granatad20ed362017-03-30 11:12:26 -070071 def suffix(self, theSensors):
Enrico Granata6988f002017-02-13 12:07:52 -080072 """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 Granata3b0f5b72017-07-31 14:04:50 -0700112 s = \
113"/*\n" + \
114" * Copyright (C) 2017 The Android Open Source Project\n" + \
115" *\n" + \
116" * Licensed under the Apache License, Version 2.0 (the \"License\");\n" + \
117" * you may not use this file except in compliance with the License.\n" + \
118" * You may obtain a copy of the License at\n" + \
119" *\n" + \
120" * http://www.apache.org/licenses/LICENSE-2.0\n" + \
121" *\n" + \
122" * Unless required by applicable law or agreed to in writing, software\n" + \
123" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" + \
124" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + \
125" * See the License for the specific language governing permissions and\n" + \
126" * limitations under the License.\n" + \
127"*/\n" + \
128"\n" + \
Enrico Granata25e89462017-08-02 11:41:31 -0700129"package android.car.diagnostic;\n" + \
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700130"\n" + \
131"import android.annotation.IntDef;\n" + \
132"import android.annotation.SystemApi;\n" + \
133"import java.lang.annotation.Retention;\n" + \
134"import java.lang.annotation.RetentionPolicy;\n" + \
135"\n" + \
136"/**\n" + \
137" * This class is a container for the indices of diagnostic sensors. The values are extracted by\n" + \
138" * running packages/services/Car/tools/update-obd2-sensors.py against types.hal.\n" + \
139" *\n" + \
140" * DO NOT EDIT MANUALLY\n" + \
141" *\n" + \
142" * @hide\n" + \
143" */\n" + \
144"@SystemApi\n" + \
145"public final class %sSensorIndex {\n" % theSensors.descriptor + \
146" private %sSensorIndex() {}\n" % theSensors.descriptor
147
Enrico Granata6988f002017-02-13 12:07:52 -0800148 return s
149
Enrico Granata6988f002017-02-13 12:07:52 -0800150 def indent(self):
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700151 return 4
Enrico Granata6988f002017-02-13 12:07:52 -0800152
Enrico Granatad20ed362017-03-30 11:12:26 -0700153class PythonSensorPolicy(SensorPolicy):
154 """The sensor policy that emits Python sensor descriptions."""
155 def sensor(self, theSensor, theSensors):
Enrico Granata976cee42017-07-25 17:23:45 -0700156 return "DIAGNOSTIC_SENSOR_%s_%s = %s" % (
Enrico Granatad20ed362017-03-30 11:12:26 -0700157 theSensors.descriptor.upper(),
158 theSensor.name.upper(),
159 self.adjustSensorId(theSensors.descriptor.upper(), str(theSensor.id))
160 )
161
162 def adjustSensorId(self, descriptor, sensorId):
163 if sensorId.isdigit(): return sensorId
Enrico Granata976cee42017-07-25 17:23:45 -0700164 return "DIAGNOSTIC_SENSOR_%s_%s" % (descriptor, sensorId.upper())
Enrico Granatad20ed362017-03-30 11:12:26 -0700165
Enrico Granata6988f002017-02-13 12:07:52 -0800166class IntDefSensorPolicy(SensorPolicy):
167 """The sensor policy that emits @IntDef sensor descriptions."""
168 def sensor(self, theSensor, theSensors):
169 sensorName = theSensor.name.replace("_INDEX", "")
Enrico Granata976cee42017-07-25 17:23:45 -0700170 return "%sSensorIndex.%s," % (theSensors.descriptor,sensorName)
Enrico Granata6988f002017-02-13 12:07:52 -0800171
172 def prefix(self, theSensors):
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700173 return " /** @hide */\n @Retention(RetentionPolicy.SOURCE)\n @IntDef({"
Enrico Granata4c43add2017-03-15 18:01:34 -0700174
175 def indent(self):
176 return 8
Enrico Granata6988f002017-02-13 12:07:52 -0800177
178 def suffix(self, theSensors):
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700179 return " })\n public @interface SensorIndex {}"
Enrico Granata6988f002017-02-13 12:07:52 -0800180
181class SensorMeta(type):
182 """Metaclass for sensor classes."""
183 def __new__(cls, name, parents, dct):
184 sensorList = dct['sensorList']
185 class SensorBase(object):
186 def __init__(self, name, comment=None, id=None):
187 self.name = name
188 self.comment = comment if comment else ""
189 if id: self.id = id
190 sensorList.addSensor(self)
191 def __repr__(self):
192 s = ""
193 if self.comment:
194 s = s + self.comment + "\n"
195 s = s + self.name + " = " + str(self.id)
196 return s
197
198 newClass = super().__new__(cls, name, (SensorBase,), dct)
199 sensorList.sensorClass = newClass
200 return newClass
201
202intSensors = SensorList(descriptor="Integer")
203floatSensors = SensorList(descriptor="Float")
204
205class intSensor(metaclass=SensorMeta):
206 sensorList = intSensors
207
208class floatSensor(metaclass=SensorMeta):
209 sensorList = floatSensors
210
Enrico Granata4c43add2017-03-15 18:01:34 -0700211def applyPolicy(policy, destfile):
Enrico Granata6988f002017-02-13 12:07:52 -0800212 """Given a sensor policy, apply it to all known sensor types"""
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700213 applyIntPolicy(policy, destfile)
214 applyFloatPolicy(policy, destfile)
215
216def applyIntPolicy(policy, destfile):
217 "Given a sensor policy, apply it to integer sensors"
Enrico Granata4c43add2017-03-15 18:01:34 -0700218 print(policy.sensors(intSensors), file=destfile)
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700219
220def applyFloatPolicy(policy, destfile):
221 "Given a sensor policy, apply it to float sensors"
Enrico Granata4c43add2017-03-15 18:01:34 -0700222 print(policy.sensors(floatSensors), file=destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800223
Enrico Granata4c43add2017-03-15 18:01:34 -0700224def java(destfile):
225 applyPolicy(JavaSensorPolicy(), destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800226
Enrico Granata4c43add2017-03-15 18:01:34 -0700227def intdef(destfile):
228 applyPolicy(IntDefSensorPolicy(), destfile)
Enrico Granata6988f002017-02-13 12:07:52 -0800229
Enrico Granatad20ed362017-03-30 11:12:26 -0700230def python(destfile):
231 applyPolicy(PythonSensorPolicy(), destfile)
232
233def generateJava(filepath):
234 """Generate Java code for all sensors."""
Enrico Granata3b0f5b72017-07-31 14:04:50 -0700235 intfile = open(os.path.join(filepath, "IntegerSensorIndex.java"), "w")
236 floatfile = open(os.path.join(filepath, "FloatSensorIndex.java"), "w")
237 javaPolicy = JavaSensorPolicy()
238 intdefPolicy = IntDefSensorPolicy()
239 applyIntPolicy(javaPolicy, intfile)
240 applyIntPolicy(intdefPolicy, intfile)
241 applyFloatPolicy(javaPolicy, floatfile)
242 applyFloatPolicy(intdefPolicy, floatfile)
243 print("}", file=intfile)
244 print("}", file=floatfile)
245 intfile.close()
246 floatfile.close()
Enrico Granata6988f002017-02-13 12:07:52 -0800247
Enrico Granatad20ed362017-03-30 11:12:26 -0700248def generatePython(filepath):
249 """Generate Python code for all sensors."""
250 destfile = open(filepath, "w")
251 print("#!/usr/bin/env python3", file=destfile)
252 print("#", file=destfile)
253 print("# Copyright (C) 2017 The Android Open Source Project", file=destfile)
254 print("#", file=destfile)
255 print("# Licensed under the Apache License, Version 2.0 (the \"License\");", file=destfile)
256 print("# you may not use this file except in compliance with the License.", file=destfile)
257 print("# You may obtain a copy of the License at", file=destfile)
258 print("#", file=destfile)
259 print("# http://www.apache.org/licenses/LICENSE-2.0", file=destfile)
260 print("#", file=destfile)
261 print("# Unless required by applicable law or agreed to in writing, software", file=destfile)
262 print("# distributed under the License is distributed on an \"AS IS\" BASIS,", file=destfile)
263 print("# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", file=destfile)
264 print("# See the License for the specific language governing permissions and", file=destfile)
265 print("# limitations under the License.", file=destfile)
266 print("#", file=destfile)
267 print("# This file is generated by types.hal by packages/services/Car/tools/update-obd2-sensors.py", file=destfile)
268 print("# DO NOT EDIT MANUALLY", file=destfile)
269 python(destfile)
270
Enrico Granata4c43add2017-03-15 18:01:34 -0700271def load(filepath):
272 """Load sensor data from Vehicle HAL."""
273 ast = hidl_parser.parser.parse(filepath)
Enrico Granata976cee42017-07-25 17:23:45 -0700274 integerSensors = ast['enums']['DiagnosticIntegerSensorIndex']
275 floatSensors = ast['enums']['DiagnosticFloatSensorIndex']
Enrico Granata4c43add2017-03-15 18:01:34 -0700276 for case in integerSensors.cases:
277 intSensor(name=case.name, id=case.value)
278 for case in floatSensors.cases:
279 floatSensor(name=case.name, id=case.value)
Enrico Granata6988f002017-02-13 12:07:52 -0800280
Enrico Granata4c43add2017-03-15 18:01:34 -0700281import os
Enrico Granata6988f002017-02-13 12:07:52 -0800282
Enrico Granatad20ed362017-03-30 11:12:26 -0700283if len(sys.argv) != 4:
Enrico Granata25e89462017-08-02 11:41:31 -0700284 print('syntax: update-obd2-sensors.py <path/to/types.hal> <path/to/android.car.diagnostic> <path/to/diagnostic_sensors.py>')
Enrico Granatad20ed362017-03-30 11:12:26 -0700285 print('This script will parse types.hal, and use the resulting', end='')
Enrico Granata25e89462017-08-02 11:41:31 -0700286 print('parse tree to generate Java and Python lists of sensor identifiers.')
Enrico Granata4c43add2017-03-15 18:01:34 -0700287 sys.exit(1)
288load(sys.argv[1])
Enrico Granatad20ed362017-03-30 11:12:26 -0700289generateJava(sys.argv[2])
290generatePython(sys.argv[3])