Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3.4 |
| 2 | # |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 3 | # Copyright (C) 2017 The Android Open Source Project |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 4 | # |
| 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 Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 18 | # 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 Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 22 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 23 | import sys |
| 24 | sys.dont_write_bytecode = True |
| 25 | |
| 26 | import hidl_parser.parser |
| 27 | |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 28 | class 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 Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 45 | 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 | |
| 54 | class 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 Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 103 | class 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 Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 112 | s = " public static final class Obd2%sSensorIndex {\n" % \ |
| 113 | theSensors.descriptor |
| 114 | s += " private Obd2%sSensorIndex() {}\n" % \ |
| 115 | theSensors.descriptor |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 116 | return s |
| 117 | |
| 118 | def suffix(self, theSensors): |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 119 | return " }" |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 120 | |
| 121 | def indent(self): |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 122 | return 8 |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 123 | |
| 124 | class 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 Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 131 | return " @Retention(RetentionPolicy.SOURCE)\n @IntDef({" |
| 132 | |
| 133 | def indent(self): |
| 134 | return 8 |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 135 | |
| 136 | def suffix(self, theSensors): |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 137 | return " })\n public @interface %sSensorIndex {}" % \ |
| 138 | theSensors.descriptor |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 139 | |
| 140 | class 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 | |
| 161 | intSensors = SensorList(descriptor="Integer") |
| 162 | floatSensors = SensorList(descriptor="Float") |
| 163 | |
| 164 | class intSensor(metaclass=SensorMeta): |
| 165 | sensorList = intSensors |
| 166 | |
| 167 | class floatSensor(metaclass=SensorMeta): |
| 168 | sensorList = floatSensors |
| 169 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 170 | def applyPolicy(policy, destfile): |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 171 | """Given a sensor policy, apply it to all known sensor types""" |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 172 | print(policy.sensors(intSensors), file=destfile) |
| 173 | print(policy.sensors(floatSensors), file=destfile) |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 174 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 175 | def java(destfile): |
| 176 | applyPolicy(JavaSensorPolicy(), destfile) |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 177 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 178 | def intdef(destfile): |
| 179 | applyPolicy(IntDefSensorPolicy(), destfile) |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 180 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 181 | def generate(filepath): |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 182 | """Generate data for all sensors.""" |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 183 | 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 Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 218 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 219 | def 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 Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 228 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 229 | import os |
Enrico Granata | 6988f00 | 2017-02-13 12:07:52 -0800 | [diff] [blame] | 230 | |
Enrico Granata | 4c43add | 2017-03-15 18:01:34 -0700 | [diff] [blame^] | 231 | if 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) |
| 236 | load(sys.argv[1]) |
| 237 | generate(sys.argv[2]) |