1#!/usr/bin/env python3.4 2# 3# Copyright (C) 2017 The Android Open Source Project 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 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. 22 23import sys 24sys.dont_write_bytecode = True 25 26import hidl_parser.parser 27 28class 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 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 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 103class 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): 112 s = " public static final class Obd2%sSensorIndex {\n" % \ 113 theSensors.descriptor 114 s += " private Obd2%sSensorIndex() {}\n" % \ 115 theSensors.descriptor 116 return s 117 118 def suffix(self, theSensors): 119 return " }" 120 121 def indent(self): 122 return 8 123 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): 131 return " @Retention(RetentionPolicy.SOURCE)\n @IntDef({" 132 133 def indent(self): 134 return 8 135 136 def suffix(self, theSensors): 137 return " })\n public @interface %sSensorIndex {}" % \ 138 theSensors.descriptor 139 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 170def applyPolicy(policy, destfile): 171 """Given a sensor policy, apply it to all known sensor types""" 172 print(policy.sensors(intSensors), file=destfile) 173 print(policy.sensors(floatSensors), file=destfile) 174 175def java(destfile): 176 applyPolicy(JavaSensorPolicy(), destfile) 177 178def intdef(destfile): 179 applyPolicy(IntDefSensorPolicy(), destfile) 180 181def generate(filepath): 182 """Generate data for all sensors.""" 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) 218 219def 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) 228 229import os 230 231if 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]) 238