You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
10 KiB
291 lines
10 KiB
4 months ago
|
#!/usr/bin/env python3.4
|
||
|
#
|
||
|
# Copyright (C) 2017 The Android Open Source Project
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
#
|
||
|
|
||
|
# This script generates useful Java representations for the OBD2 sensors
|
||
|
# defined in Vehicle HAL. It is meant to be as an easy way to update the
|
||
|
# list of diagnostic sensors and get all downstream users of that information
|
||
|
# updated in a consistent fashion.
|
||
|
|
||
|
import sys
|
||
|
sys.dont_write_bytecode = True
|
||
|
|
||
|
import hidl_parser.parser
|
||
|
|
||
|
class SensorList(object):
|
||
|
"""A list of sensors ordered by a unique identifier."""
|
||
|
def __init__(self, descriptor):
|
||
|
self.sensors = []
|
||
|
self.id = -1
|
||
|
self.descriptor = descriptor
|
||
|
|
||
|
def addSensor(self, sensor):
|
||
|
"""Add a new sensor to the list."""
|
||
|
if not hasattr(sensor, 'id'):
|
||
|
self.id += 1
|
||
|
sensor.id = self.id
|
||
|
self.sensors.append(sensor)
|
||
|
|
||
|
def finalizeList(self):
|
||
|
"""Complete the list, adding well-known sensor information."""
|
||
|
self.id -= 1
|
||
|
vendorStartSensor = self.sensorClass("VENDOR_START_INDEX",
|
||
|
id="LAST_SYSTEM_INDEX + 1")
|
||
|
# make calling finalizeList idempotent
|
||
|
self.finalizeList = lambda: self
|
||
|
return self
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
return self.sensors.__getitem__(key)
|
||
|
|
||
|
class SensorPolicy(object):
|
||
|
"""A formatter object that does processing on sensor data."""
|
||
|
@classmethod
|
||
|
def indentLines(cls, string, numSpaces):
|
||
|
indent = ' ' * numSpaces
|
||
|
parts = string.split('\n')
|
||
|
parts = [indent + part for part in parts]
|
||
|
return '\n'.join(parts) + "\n"
|
||
|
|
||
|
def sensor(self, theSensor, theSensors):
|
||
|
"""Produce output for a sensor."""
|
||
|
pass
|
||
|
|
||
|
def prefix(self, theSensors):
|
||
|
"""Prefix string before any sensor data is generated."""
|
||
|
return ""
|
||
|
|
||
|
def suffix(self, theSensors):
|
||
|
"""Suffix string after all sensor data is generated."""
|
||
|
return ""
|
||
|
|
||
|
def indent(self):
|
||
|
"""Indentation level for individual sensor data."""
|
||
|
return 0
|
||
|
|
||
|
def separator(self):
|
||
|
"""Separator between individual sensor data entries."""
|
||
|
return ""
|
||
|
|
||
|
def description(self):
|
||
|
"""A description of this policy."""
|
||
|
return "A sensor policy."
|
||
|
|
||
|
def sensors(self, theSensors):
|
||
|
"""Produce output for all sensors."""
|
||
|
theSensors = theSensors.finalizeList()
|
||
|
s = self.prefix(theSensors) + "\n"
|
||
|
first = True
|
||
|
for theSensor in theSensors:
|
||
|
if first:
|
||
|
first = False
|
||
|
else:
|
||
|
s += self.separator()
|
||
|
sensorLine = SensorPolicy.indentLines(self.sensor(theSensor,
|
||
|
theSensors), self.indent())
|
||
|
s += sensorLine
|
||
|
s += self.suffix(theSensors) + "\n"
|
||
|
return s
|
||
|
|
||
|
class JavaSensorPolicy(SensorPolicy):
|
||
|
"""The sensor policy that emits Java sensor descriptions."""
|
||
|
def sensor(self, theSensor, theSensors):
|
||
|
sensorName = theSensor.name.replace("_INDEX", "")
|
||
|
sensorId = str(theSensor.id).replace("_INDEX", "")
|
||
|
return "public static final int " + sensorName + " = " + \
|
||
|
str(sensorId) + ";"
|
||
|
|
||
|
def prefix(self, theSensors):
|
||
|
s = \
|
||
|
"/*\n" + \
|
||
|
" * Copyright (C) 2017 The Android Open Source Project\n" + \
|
||
|
" *\n" + \
|
||
|
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n" + \
|
||
|
" * you may not use this file except in compliance with the License.\n" + \
|
||
|
" * You may obtain a copy of the License at\n" + \
|
||
|
" *\n" + \
|
||
|
" * http://www.apache.org/licenses/LICENSE-2.0\n" + \
|
||
|
" *\n" + \
|
||
|
" * Unless required by applicable law or agreed to in writing, software\n" + \
|
||
|
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" + \
|
||
|
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + \
|
||
|
" * See the License for the specific language governing permissions and\n" + \
|
||
|
" * limitations under the License.\n" + \
|
||
|
"*/\n" + \
|
||
|
"\n" + \
|
||
|
"package android.car.diagnostic;\n" + \
|
||
|
"\n" + \
|
||
|
"import android.annotation.IntDef;\n" + \
|
||
|
"import android.annotation.SystemApi;\n" + \
|
||
|
"import java.lang.annotation.Retention;\n" + \
|
||
|
"import java.lang.annotation.RetentionPolicy;\n" + \
|
||
|
"\n" + \
|
||
|
"/**\n" + \
|
||
|
" * This class is a container for the indices of diagnostic sensors. The values are extracted by\n" + \
|
||
|
" * running packages/services/Car/tools/update-obd2-sensors.py against types.hal.\n" + \
|
||
|
" *\n" + \
|
||
|
" * DO NOT EDIT MANUALLY\n" + \
|
||
|
" *\n" + \
|
||
|
" * @hide\n" + \
|
||
|
" */\n" + \
|
||
|
"@SystemApi\n" + \
|
||
|
"public final class %sSensorIndex {\n" % theSensors.descriptor + \
|
||
|
" private %sSensorIndex() {}\n" % theSensors.descriptor
|
||
|
|
||
|
return s
|
||
|
|
||
|
def indent(self):
|
||
|
return 4
|
||
|
|
||
|
class PythonSensorPolicy(SensorPolicy):
|
||
|
"""The sensor policy that emits Python sensor descriptions."""
|
||
|
def sensor(self, theSensor, theSensors):
|
||
|
return "DIAGNOSTIC_SENSOR_%s_%s = %s" % (
|
||
|
theSensors.descriptor.upper(),
|
||
|
theSensor.name.upper(),
|
||
|
self.adjustSensorId(theSensors.descriptor.upper(), str(theSensor.id))
|
||
|
)
|
||
|
|
||
|
def adjustSensorId(self, descriptor, sensorId):
|
||
|
if sensorId.isdigit(): return sensorId
|
||
|
return "DIAGNOSTIC_SENSOR_%s_%s" % (descriptor, sensorId.upper())
|
||
|
|
||
|
class IntDefSensorPolicy(SensorPolicy):
|
||
|
"""The sensor policy that emits @IntDef sensor descriptions."""
|
||
|
def sensor(self, theSensor, theSensors):
|
||
|
sensorName = theSensor.name.replace("_INDEX", "")
|
||
|
return "%sSensorIndex.%s," % (theSensors.descriptor,sensorName)
|
||
|
|
||
|
def prefix(self, theSensors):
|
||
|
return " /** @hide */\n @Retention(RetentionPolicy.SOURCE)\n @IntDef({"
|
||
|
|
||
|
def indent(self):
|
||
|
return 8
|
||
|
|
||
|
def suffix(self, theSensors):
|
||
|
return " })\n public @interface SensorIndex {}"
|
||
|
|
||
|
class SensorMeta(type):
|
||
|
"""Metaclass for sensor classes."""
|
||
|
def __new__(cls, name, parents, dct):
|
||
|
sensorList = dct['sensorList']
|
||
|
class SensorBase(object):
|
||
|
def __init__(self, name, comment=None, id=None):
|
||
|
self.name = name
|
||
|
self.comment = comment if comment else ""
|
||
|
if id: self.id = id
|
||
|
sensorList.addSensor(self)
|
||
|
def __repr__(self):
|
||
|
s = ""
|
||
|
if self.comment:
|
||
|
s = s + self.comment + "\n"
|
||
|
s = s + self.name + " = " + str(self.id)
|
||
|
return s
|
||
|
|
||
|
newClass = super().__new__(cls, name, (SensorBase,), dct)
|
||
|
sensorList.sensorClass = newClass
|
||
|
return newClass
|
||
|
|
||
|
intSensors = SensorList(descriptor="Integer")
|
||
|
floatSensors = SensorList(descriptor="Float")
|
||
|
|
||
|
class intSensor(metaclass=SensorMeta):
|
||
|
sensorList = intSensors
|
||
|
|
||
|
class floatSensor(metaclass=SensorMeta):
|
||
|
sensorList = floatSensors
|
||
|
|
||
|
def applyPolicy(policy, destfile):
|
||
|
"""Given a sensor policy, apply it to all known sensor types"""
|
||
|
applyIntPolicy(policy, destfile)
|
||
|
applyFloatPolicy(policy, destfile)
|
||
|
|
||
|
def applyIntPolicy(policy, destfile):
|
||
|
"Given a sensor policy, apply it to integer sensors"
|
||
|
print(policy.sensors(intSensors), file=destfile)
|
||
|
|
||
|
def applyFloatPolicy(policy, destfile):
|
||
|
"Given a sensor policy, apply it to float sensors"
|
||
|
print(policy.sensors(floatSensors), file=destfile)
|
||
|
|
||
|
def java(destfile):
|
||
|
applyPolicy(JavaSensorPolicy(), destfile)
|
||
|
|
||
|
def intdef(destfile):
|
||
|
applyPolicy(IntDefSensorPolicy(), destfile)
|
||
|
|
||
|
def python(destfile):
|
||
|
applyPolicy(PythonSensorPolicy(), destfile)
|
||
|
|
||
|
def generateJava(filepath):
|
||
|
"""Generate Java code for all sensors."""
|
||
|
intfile = open(os.path.join(filepath, "IntegerSensorIndex.java"), "w")
|
||
|
floatfile = open(os.path.join(filepath, "FloatSensorIndex.java"), "w")
|
||
|
javaPolicy = JavaSensorPolicy()
|
||
|
intdefPolicy = IntDefSensorPolicy()
|
||
|
applyIntPolicy(javaPolicy, intfile)
|
||
|
applyIntPolicy(intdefPolicy, intfile)
|
||
|
applyFloatPolicy(javaPolicy, floatfile)
|
||
|
applyFloatPolicy(intdefPolicy, floatfile)
|
||
|
print("}", file=intfile)
|
||
|
print("}", file=floatfile)
|
||
|
intfile.close()
|
||
|
floatfile.close()
|
||
|
|
||
|
def generatePython(filepath):
|
||
|
"""Generate Python code for all sensors."""
|
||
|
destfile = open(filepath, "w")
|
||
|
print("#!/usr/bin/env python3", file=destfile)
|
||
|
print("#", file=destfile)
|
||
|
print("# Copyright (C) 2017 The Android Open Source Project", file=destfile)
|
||
|
print("#", file=destfile)
|
||
|
print("# Licensed under the Apache License, Version 2.0 (the \"License\");", file=destfile)
|
||
|
print("# you may not use this file except in compliance with the License.", file=destfile)
|
||
|
print("# You may obtain a copy of the License at", file=destfile)
|
||
|
print("#", file=destfile)
|
||
|
print("# http://www.apache.org/licenses/LICENSE-2.0", file=destfile)
|
||
|
print("#", file=destfile)
|
||
|
print("# Unless required by applicable law or agreed to in writing, software", file=destfile)
|
||
|
print("# distributed under the License is distributed on an \"AS IS\" BASIS,", file=destfile)
|
||
|
print("# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", file=destfile)
|
||
|
print("# See the License for the specific language governing permissions and", file=destfile)
|
||
|
print("# limitations under the License.", file=destfile)
|
||
|
print("#", file=destfile)
|
||
|
print("# This file is generated by types.hal by packages/services/Car/tools/update-obd2-sensors.py", file=destfile)
|
||
|
print("# DO NOT EDIT MANUALLY", file=destfile)
|
||
|
python(destfile)
|
||
|
|
||
|
def load(filepath):
|
||
|
"""Load sensor data from Vehicle HAL."""
|
||
|
ast = hidl_parser.parser.parse(filepath)
|
||
|
integerSensors = ast['enums']['DiagnosticIntegerSensorIndex']
|
||
|
floatSensors = ast['enums']['DiagnosticFloatSensorIndex']
|
||
|
for case in integerSensors.cases:
|
||
|
intSensor(name=case.name, id=case.value)
|
||
|
for case in floatSensors.cases:
|
||
|
floatSensor(name=case.name, id=case.value)
|
||
|
|
||
|
import os
|
||
|
|
||
|
if len(sys.argv) != 4:
|
||
|
print('syntax: update-obd2-sensors.py <path/to/types.hal> <path/to/android.car.diagnostic> <path/to/diagnostic_sensors.py>')
|
||
|
print('This script will parse types.hal, and use the resulting', end='')
|
||
|
print('parse tree to generate Java and Python lists of sensor identifiers.')
|
||
|
sys.exit(1)
|
||
|
load(sys.argv[1])
|
||
|
generateJava(sys.argv[2])
|
||
|
generatePython(sys.argv[3])
|