1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2016 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 import logging 19 import time 20 21 from vts.runners.host import asserts 22 from vts.runners.host import base_test 23 from vts.runners.host import const 24 from vts.runners.host import keys 25 from vts.runners.host import test_runner 26 from vts.utils.python.controllers import android_device 27 from vts.utils.python.precondition import precondition_utils 28 29 30 class VtsHalAutomotiveVehicleV2_0HostTest(base_test.BaseTestClass): 31 """A simple testcase for the VEHICLE HIDL HAL.""" 32 33 def setUpClass(self): 34 """Creates a mirror and init vehicle hal.""" 35 self.dut = self.registerController(android_device)[0] 36 37 self.dut.shell.InvokeTerminal("one") 38 self.dut.shell.one.Execute("setenforce 0") # SELinux permissive mode 39 if not precondition_utils.CanRunHidlHalTest( 40 self, self.dut, self.dut.shell.one): 41 self._skip_all_testcases = True 42 return 43 44 results = self.dut.shell.one.Execute("id -u system") 45 system_uid = results[const.STDOUT][0].strip() 46 logging.info("system_uid: %s", system_uid) 47 48 if self.coverage.enabled: 49 self.coverage.LoadArtifacts() 50 self.coverage.InitializeDeviceCoverage(self.dut) 51 52 if self.profiling.enabled: 53 self.profiling.EnableVTSProfiling(self.dut.shell.one) 54 55 self.dut.hal.InitHidlHal( 56 target_type="vehicle", 57 target_basepaths=self.dut.libPaths, 58 target_version=2.0, 59 target_package="android.hardware.automotive.vehicle", 60 target_component_name="IVehicle", 61 bits=int(self.abi_bitness)) 62 63 self.vehicle = self.dut.hal.vehicle # shortcut 64 self.vehicle.SetCallerUid(system_uid) 65 self.vtypes = self.dut.hal.vehicle.GetHidlTypeInterface("types") 66 logging.info("vehicle types: %s", self.vtypes) 67 asserts.assertEqual(0x00ff0000, self.vtypes.VehiclePropertyType.MASK) 68 asserts.assertEqual(0x0f000000, self.vtypes.VehicleArea.MASK) 69 70 def tearDownClass(self): 71 """Disables the profiling. 72 73 If profiling is enabled for the test, collect the profiling data 74 and disable profiling after the test is done. 75 """ 76 if self._skip_all_testcases: 77 return 78 79 if self.profiling.enabled: 80 self.profiling.ProcessTraceDataForTestCase(self.dut) 81 self.profiling.ProcessAndUploadTraceData() 82 83 if self.coverage.enabled: 84 self.coverage.SetCoverageData(dut=self.dut, isGlobal=True) 85 86 def setUp(self): 87 self.propToConfig = {} 88 for config in self.vehicle.getAllPropConfigs(): 89 self.propToConfig[config['prop']] = config 90 self.configList = self.propToConfig.values() 91 92 def testListProperties(self): 93 """Checks whether some PropConfigs are returned. 94 95 Verifies that call to getAllPropConfigs is not failing and 96 it returns at least 1 vehicle property config. 97 """ 98 logging.info("all supported properties: %s", self.configList) 99 asserts.assertLess(0, len(self.configList)) 100 101 def testMandatoryProperties(self): 102 """Verifies that all mandatory properties are supported.""" 103 # 1 property so far 104 mandatoryProps = set([self.vtypes.VehicleProperty.DRIVING_STATUS]) 105 logging.info(self.vtypes.VehicleProperty.DRIVING_STATUS) 106 107 for config in self.configList: 108 mandatoryProps.discard(config['prop']) 109 110 asserts.assertEqual(0, len(mandatoryProps)) 111 112 def emptyValueProperty(self, propertyId, areaId=0): 113 """Creates a property structure for use with the Vehicle HAL. 114 115 Args: 116 propertyId: the numeric identifier of the output property. 117 areaId: the numeric identifier of the vehicle area of the output 118 property. 0, or omitted, for global. 119 120 Returns: 121 a property structure for use with the Vehicle HAL. 122 """ 123 return { 124 'prop' : propertyId, 125 'timestamp' : 0, 126 'areaId' : areaId, 127 'value' : { 128 'int32Values' : [], 129 'floatValues' : [], 130 'int64Values' : [], 131 'bytes' : [], 132 'stringValue' : "" 133 } 134 } 135 136 def readVhalProperty(self, propertyId, areaId=0): 137 """Reads a specified property from Vehicle HAL. 138 139 Args: 140 propertyId: the numeric identifier of the property to be read. 141 areaId: the numeric identifier of the vehicle area to retrieve the 142 property for. 0, or omitted, for global. 143 144 Returns: 145 the value of the property as read from Vehicle HAL, or None 146 if it could not read successfully. 147 """ 148 vp = self.vtypes.Py2Pb("VehiclePropValue", 149 self.emptyValueProperty(propertyId, areaId)) 150 logging.info("0x%x get request: %s", propertyId, vp) 151 status, value = self.vehicle.get(vp) 152 logging.info("0x%x get response: %s, %s", propertyId, status, value) 153 if self.vtypes.StatusCode.OK == status: 154 return value 155 else: 156 logging.warning("attempt to read property 0x%x returned error %d", 157 propertyId, status) 158 159 def setVhalProperty(self, propertyId, value, areaId=0, 160 expectedStatus=0): 161 """Sets a specified property in the Vehicle HAL. 162 163 Args: 164 propertyId: the numeric identifier of the property to be set. 165 value: the value of the property, formatted as per the Vehicle HAL 166 (use emptyValueProperty() as a helper). 167 areaId: the numeric identifier of the vehicle area to set the 168 property for. 0, or omitted, for global. 169 expectedStatus: the StatusCode expected to be returned from setting 170 the property. 0, or omitted, for OK. 171 """ 172 propValue = self.emptyValueProperty(propertyId, areaId) 173 for k in propValue["value"]: 174 if k in value: 175 if k == "stringValue": 176 propValue["value"][k] += value[k] 177 else: 178 propValue["value"][k].extend(value[k]) 179 vp = self.vtypes.Py2Pb("VehiclePropValue", propValue) 180 logging.info("0x%x set request: %s", propertyId, vp) 181 status = self.vehicle.set(vp) 182 logging.info("0x%x set response: %s", propertyId, status) 183 if 0 == expectedStatus: 184 expectedStatus = self.vtypes.StatusCode.OK 185 asserts.assertEqual(expectedStatus, status, "Prop 0x%x" % propertyId) 186 187 def setAndVerifyIntProperty(self, propertyId, value, areaId=0): 188 """Sets a integer property in the Vehicle HAL and reads it back. 189 190 Args: 191 propertyId: the numeric identifier of the property to be set. 192 value: the int32 value of the property to be set. 193 areaId: the numeric identifier of the vehicle area to set the 194 property for. 0, or omitted, for global. 195 """ 196 self.setVhalProperty(propertyId, {"int32Values" : [value]}, areaId=areaId) 197 198 propValue = self.readVhalProperty(propertyId, areaId=areaId) 199 asserts.assertEqual(1, len(propValue["value"]["int32Values"])) 200 asserts.assertEqual(value, propValue["value"]["int32Values"][0]) 201 202 def testObd2SensorProperties(self): 203 """Test reading the live and freeze OBD2 frame properties. 204 205 OBD2 (On-Board Diagnostics 2) is the industry standard protocol 206 for retrieving diagnostic sensor information from vehicles. 207 """ 208 class CheckRead(object): 209 """This class wraps the logic of an actual property read. 210 211 Attributes: 212 testobject: the test case this object is used on behalf of. 213 propertyId: the identifier of the Vehiche HAL property to read. 214 name: the engineer-readable name of this test operation. 215 """ 216 217 def __init__(self, testobject, propertyId, name): 218 self.testobject = testobject 219 self.propertyId = propertyId 220 self.name = name 221 222 def onReadSuccess(self, propValue): 223 """Override this to perform any post-read validation. 224 225 Args: 226 propValue: the property value obtained from Vehicle HAL. 227 """ 228 pass 229 230 def __call__(self): 231 """Reads the specified property and validates the result.""" 232 propValue = self.testobject.readVhalProperty(self.propertyId) 233 asserts.assertNotEqual(propValue, None, 234 msg="reading %s should not return None" % 235 self.name) 236 logging.info("%s = %s", self.name, propValue) 237 self.onReadSuccess(propValue) 238 logging.info("%s pass" % self.name) 239 240 def checkLiveFrameRead(): 241 """Validates reading the OBD2_LIVE_FRAME (if available).""" 242 checker = CheckRead(self, 243 self.vtypes.VehicleProperty.OBD2_LIVE_FRAME, 244 "OBD2_LIVE_FRAME") 245 checker() 246 247 def checkFreezeFrameRead(): 248 """Validates reading the OBD2_FREEZE_FRAME (if available).""" 249 checker = CheckRead(self, 250 self.vtypes.VehicleProperty.OBD2_FREEZE_FRAME, 251 "OBD2_FREEZE_FRAME") 252 checker() 253 254 isLiveSupported = self.vtypes.VehicleProperty.OBD2_LIVE_FRAME in self.propToConfig 255 isFreezeSupported = self.vtypes.VehicleProperty.OBD2_FREEZE_FRAME in self.propToConfig 256 logging.info("isLiveSupported = %s, isFreezeSupported = %s", 257 isLiveSupported, isFreezeSupported) 258 if isLiveSupported: 259 checkLiveFrameRead() 260 if isFreezeSupported: 261 checkFreezeFrameRead() 262 263 def testDrivingStatus(self): 264 """Checks that DRIVING_STATUS property returns correct result.""" 265 propValue = self.readVhalProperty( 266 self.vtypes.VehicleProperty.DRIVING_STATUS) 267 asserts.assertEqual(1, len(propValue["value"]["int32Values"])) 268 drivingStatus = propValue["value"]["int32Values"][0] 269 270 allStatuses = (self.vtypes.VehicleDrivingStatus.UNRESTRICTED 271 | self.vtypes.VehicleDrivingStatus.NO_VIDEO 272 | self.vtypes.VehicleDrivingStatus.NO_KEYBOARD_INPUT 273 | self.vtypes.VehicleDrivingStatus.NO_VOICE_INPUT 274 | self.vtypes.VehicleDrivingStatus.NO_CONFIG 275 | self.vtypes.VehicleDrivingStatus.LIMIT_MESSAGE_LEN) 276 277 asserts.assertEqual(allStatuses, allStatuses | drivingStatus) 278 279 def extractZonesAsList(self, supportedAreas): 280 """Converts bitwise area flags to list of zones""" 281 allZones = [ 282 self.vtypes.VehicleAreaZone.ROW_1_LEFT, 283 self.vtypes.VehicleAreaZone.ROW_1_CENTER, 284 self.vtypes.VehicleAreaZone.ROW_1_RIGHT, 285 self.vtypes.VehicleAreaZone.ROW_1, 286 self.vtypes.VehicleAreaZone.ROW_2_LEFT, 287 self.vtypes.VehicleAreaZone.ROW_2_CENTER, 288 self.vtypes.VehicleAreaZone.ROW_2_RIGHT, 289 self.vtypes.VehicleAreaZone.ROW_2, 290 self.vtypes.VehicleAreaZone.ROW_3_LEFT, 291 self.vtypes.VehicleAreaZone.ROW_3_CENTER, 292 self.vtypes.VehicleAreaZone.ROW_3_RIGHT, 293 self.vtypes.VehicleAreaZone.ROW_3, 294 self.vtypes.VehicleAreaZone.ROW_4_LEFT, 295 self.vtypes.VehicleAreaZone.ROW_4_CENTER, 296 self.vtypes.VehicleAreaZone.ROW_4_RIGHT, 297 self.vtypes.VehicleAreaZone.ROW_4, 298 self.vtypes.VehicleAreaZone.WHOLE_CABIN, 299 ] 300 301 extractedZones = [] 302 for zone in allZones: 303 if (zone & supportedAreas == zone): 304 extractedZones.append(zone) 305 return extractedZones 306 307 308 def testHvacPowerOn(self): 309 """Test power on/off and properties associated with it. 310 311 Gets the list of properties that are affected by the HVAC power state 312 and validates them. 313 314 Turns power on to start in a defined state, verifies that power is on 315 and properties are available. State change from on->off and verifies 316 that properties are no longer available, then state change again from 317 off->on to verify properties are now available again. 318 """ 319 320 # Checks that HVAC_POWER_ON property is supported and returns valid 321 # result initially. 322 hvacPowerOnConfig = self.propToConfig[self.vtypes.VehicleProperty.HVAC_POWER_ON] 323 if hvacPowerOnConfig is None: 324 logging.info("HVAC_POWER_ON not supported") 325 return 326 327 zones = self.extractZonesAsList(hvacPowerOnConfig['supportedAreas']) 328 asserts.assertLess(0, len(zones), "supportedAreas for HVAC_POWER_ON property is invalid") 329 330 # TODO(pavelm): consider to check for all zones 331 zone = zones[0] 332 333 propValue = self.readVhalProperty( 334 self.vtypes.VehicleProperty.HVAC_POWER_ON, areaId=zone) 335 336 asserts.assertEqual(1, len(propValue["value"]["int32Values"])) 337 asserts.assertTrue( 338 propValue["value"]["int32Values"][0] in [0, 1], 339 "%d not a valid value for HVAC_POWER_ON" % 340 propValue["value"]["int32Values"][0] 341 ) 342 343 # Checks that HVAC_POWER_ON config string returns valid result. 344 requestConfig = [self.vtypes.Py2Pb( 345 "VehicleProperty", self.vtypes.VehicleProperty.HVAC_POWER_ON)] 346 logging.info("HVAC power on config request: %s", requestConfig) 347 responseConfig = self.vehicle.getPropConfigs(requestConfig) 348 logging.info("HVAC power on config response: %s", responseConfig) 349 hvacTypes = set([ 350 self.vtypes.VehicleProperty.HVAC_FAN_SPEED, 351 self.vtypes.VehicleProperty.HVAC_FAN_DIRECTION, 352 self.vtypes.VehicleProperty.HVAC_TEMPERATURE_CURRENT, 353 self.vtypes.VehicleProperty.HVAC_TEMPERATURE_SET, 354 self.vtypes.VehicleProperty.HVAC_DEFROSTER, 355 self.vtypes.VehicleProperty.HVAC_AC_ON, 356 self.vtypes.VehicleProperty.HVAC_MAX_AC_ON, 357 self.vtypes.VehicleProperty.HVAC_MAX_DEFROST_ON, 358 self.vtypes.VehicleProperty.HVAC_RECIRC_ON, 359 self.vtypes.VehicleProperty.HVAC_DUAL_ON, 360 self.vtypes.VehicleProperty.HVAC_AUTO_ON, 361 self.vtypes.VehicleProperty.HVAC_ACTUAL_FAN_SPEED_RPM, 362 ]) 363 status = responseConfig[0] 364 asserts.assertEqual(self.vtypes.StatusCode.OK, status) 365 configString = responseConfig[1][0]["configString"] 366 configProps = [] 367 if configString != "": 368 for prop in configString.split(","): 369 configProps.append(int(prop, 16)) 370 for prop in configProps: 371 asserts.assertTrue(prop in hvacTypes, 372 "0x%X not an HVAC type" % prop) 373 374 # Turn power on. 375 self.setAndVerifyIntProperty( 376 self.vtypes.VehicleProperty.HVAC_POWER_ON, 1, areaId=zone) 377 378 # Check that properties that require power to be on can be set. 379 propVals = {} 380 for prop in configProps: 381 v = self.readVhalProperty(prop, areaId=zone)["value"] 382 self.setVhalProperty(prop, v, areaId=zone) 383 # Save the value for use later when trying to set the property when 384 # HVAC is off. 385 propVals[prop] = v 386 387 # Turn power off. 388 self.setAndVerifyIntProperty( 389 self.vtypes.VehicleProperty.HVAC_POWER_ON, 0, areaId=zone) 390 391 # Check that properties that require power to be on can't be set. 392 for prop in configProps: 393 self.setVhalProperty( 394 prop, propVals[prop], 395 areaId=zone, 396 expectedStatus=self.vtypes.StatusCode.NOT_AVAILABLE) 397 398 # Turn power on. 399 self.setAndVerifyIntProperty( 400 self.vtypes.VehicleProperty.HVAC_POWER_ON, 1, areaId=zone) 401 402 # Check that properties that require power to be on can be set. 403 for prop in configProps: 404 self.setVhalProperty(prop, propVals[prop], areaId=zone) 405 406 def testVehicleStaticProps(self): 407 """Verifies that static properties are configured correctly""" 408 staticProperties = set([ 409 self.vtypes.VehicleProperty.INFO_VIN, 410 self.vtypes.VehicleProperty.INFO_MAKE, 411 self.vtypes.VehicleProperty.INFO_MODEL, 412 self.vtypes.VehicleProperty.INFO_MODEL_YEAR, 413 self.vtypes.VehicleProperty.INFO_FUEL_CAPACITY, 414 self.vtypes.VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE, 415 self.vtypes.VehicleProperty.AUDIO_HW_VARIANT, 416 self.vtypes.VehicleProperty.AP_POWER_BOOTUP_REASON, 417 ]) 418 for c in self.configList: 419 prop = c['prop'] 420 msg = "Prop 0x%x" % prop 421 if (c["prop"] in staticProperties): 422 asserts.assertEqual(self.vtypes.VehiclePropertyChangeMode.STATIC, c["changeMode"], msg) 423 asserts.assertEqual(self.vtypes.VehiclePropertyAccess.READ, c["access"], msg) 424 propValue = self.readVhalProperty(prop) 425 asserts.assertEqual(prop, propValue['prop']) 426 self.setVhalProperty(prop, propValue["value"], 427 expectedStatus=self.vtypes.StatusCode.ACCESS_DENIED) 428 else: # Non-static property 429 asserts.assertNotEqual(self.vtypes.VehiclePropertyChangeMode.STATIC, c["changeMode"], msg) 430 431 def testPropertyRanges(self): 432 """Retrieve the property ranges for all areas. 433 434 This checks that the areas noted in the config all give valid area 435 configs. Once these are validated, the values for all these areas 436 retrieved from the HIDL must be within the ranges defined.""" 437 for c in self.configList: 438 # Continuous properties need to have a sampling frequency. 439 if c["changeMode"] & self.vtypes.VehiclePropertyChangeMode.CONTINUOUS != 0: 440 asserts.assertLess(0.0, c["minSampleRate"], 441 "minSampleRate should be > 0. Config list: %s" % c) 442 asserts.assertLess(0.0, c["maxSampleRate"], 443 "maxSampleRate should be > 0. Config list: %s" % c) 444 asserts.assertFalse(c["minSampleRate"] > c["maxSampleRate"], 445 "Prop 0x%x minSampleRate > maxSampleRate" % 446 c["prop"]) 447 448 areasFound = 0 449 for a in c["areaConfigs"]: 450 # Make sure this doesn't override one of the other areas found. 451 asserts.assertEqual(0, areasFound & a["areaId"]) 452 areasFound |= a["areaId"] 453 454 # Do some basic checking the min and max aren't mixed up. 455 checks = [ 456 ("minInt32Value", "maxInt32Value"), 457 ("minInt64Value", "maxInt64Value"), 458 ("minFloatValue", "maxFloatValue") 459 ] 460 for minName, maxName in checks: 461 asserts.assertFalse( 462 a[minName] > a[maxName], 463 "Prop 0x%x Area 0x%X %s > %s: %d > %d" % 464 (c["prop"], a["areaId"], 465 minName, maxName, a[minName], a[maxName])) 466 467 # Get a value and make sure it's within the bounds. 468 propVal = self.readVhalProperty(c["prop"], a["areaId"]) 469 # Some values may not be available, which is not an error. 470 if propVal is None: 471 continue 472 val = propVal["value"] 473 valTypes = { 474 "int32Values": ("minInt32Value", "maxInt32Value"), 475 "int64Values": ("minInt64Value", "maxInt64Value"), 476 "floatValues": ("minFloatValue", "maxFloatValue"), 477 } 478 for valType, valBoundNames in valTypes.items(): 479 for v in val[valType]: 480 # Make sure value isn't less than the minimum. 481 asserts.assertFalse( 482 v < a[valBoundNames[0]], 483 "Prop 0x%x Area 0x%X %s < min: %s < %s" % 484 (c["prop"], a["areaId"], 485 valType, v, a[valBoundNames[0]])) 486 # Make sure value isn't greater than the maximum. 487 asserts.assertFalse( 488 v > a[valBoundNames[1]], 489 "Prop 0x%x Area 0x%X %s > max: %s > %s" % 490 (c["prop"], a["areaId"], 491 valType, v, a[valBoundNames[1]])) 492 493 def getValueIfPropSupported(self, propertyId): 494 """Returns tuple of boolean (indicating value supported or not) and the value itself""" 495 if (propertyId in self.propToConfig): 496 propValue = self.readVhalProperty(propertyId) 497 asserts.assertNotEqual(None, propValue, "expected value, prop: 0x%x" % propertyId) 498 asserts.assertEqual(propertyId, propValue['prop']) 499 return True, self.extractValue(propValue) 500 else: 501 return False, None 502 503 def testInfoVinMakeModel(self): 504 """Verifies INFO_VIN, INFO_MAKE, INFO_MODEL properties""" 505 stringProperties = set([ 506 self.vtypes.VehicleProperty.INFO_VIN, 507 self.vtypes.VehicleProperty.INFO_MAKE, 508 self.vtypes.VehicleProperty.INFO_MODEL]) 509 for prop in stringProperties: 510 supported, val = self.getValueIfPropSupported(prop) 511 if supported: 512 asserts.assertEqual(str, type(val), "prop: 0x%x" % prop) 513 asserts.assertLess(0, (len(val)), "prop: 0x%x" % prop) 514 515 def testGlobalFloatProperties(self): 516 """Verifies that values of global float properties are in the correct range""" 517 floatProperties = { 518 self.vtypes.VehicleProperty.ENV_CABIN_TEMPERATURE: (-50, 100), # celsius 519 self.vtypes.VehicleProperty.ENV_OUTSIDE_TEMPERATURE: (-50, 100), # celsius 520 self.vtypes.VehicleProperty.ENGINE_RPM : (0, 30000), # RPMs 521 self.vtypes.VehicleProperty.ENGINE_OIL_TEMP : (-50, 150), # celsius 522 self.vtypes.VehicleProperty.ENGINE_COOLANT_TEMP : (-50, 150), # 523 self.vtypes.VehicleProperty.PERF_VEHICLE_SPEED : (0, 150), # m/s, 150 m/s = 330 mph 524 self.vtypes.VehicleProperty.PERF_ODOMETER : (0, 1000000), # km 525 self.vtypes.VehicleProperty.INFO_FUEL_CAPACITY : (0, 1000000), # milliliter 526 self.vtypes.VehicleProperty.INFO_MODEL_YEAR : (1901, 2101), # year 527 } 528 529 for prop, validRange in floatProperties.iteritems(): 530 supported, val = self.getValueIfPropSupported(prop) 531 if supported: 532 asserts.assertEqual(float, type(val)) 533 self.assertValueInRangeForProp(val, validRange[0], validRange[1], prop) 534 535 def testGlobalBoolProperties(self): 536 """Verifies that values of global boolean properties are in the correct range""" 537 booleanProperties = set([ 538 self.vtypes.VehicleProperty.PARKING_BRAKE_ON, 539 self.vtypes.VehicleProperty.FUEL_LEVEL_LOW, 540 self.vtypes.VehicleProperty.NIGHT_MODE, 541 self.vtypes.VehicleProperty.DOOR_LOCK, 542 self.vtypes.VehicleProperty.MIRROR_LOCK, 543 self.vtypes.VehicleProperty.MIRROR_FOLD, 544 self.vtypes.VehicleProperty.SEAT_BELT_BUCKLED, 545 self.vtypes.VehicleProperty.WINDOW_LOCK, 546 ]) 547 for prop in booleanProperties: 548 self.verifyEnumPropIfSupported(prop, [0, 1]) 549 550 def testGlobalEnumProperties(self): 551 """Verifies that values of global enum properties are in the correct range""" 552 enumProperties = { 553 self.vtypes.VehicleProperty.GEAR_SELECTION : self.vtypes.VehicleGear, 554 self.vtypes.VehicleProperty.CURRENT_GEAR : self.vtypes.VehicleGear, 555 self.vtypes.VehicleProperty.TURN_SIGNAL_STATE : self.vtypes.VehicleTurnSignal, 556 self.vtypes.VehicleProperty.IGNITION_STATE : self.vtypes.VehicleIgnitionState, 557 } 558 for prop, enum in enumProperties.iteritems(): 559 self.verifyEnumPropIfSupported(prop, vars(enum).values()) 560 561 def testDebugDump(self): 562 """Verifies that call to IVehicle#debugDump is not failing""" 563 dumpStr = self.vehicle.debugDump() 564 asserts.assertNotEqual(None, dumpStr) 565 566 def extractValue(self, propValue): 567 """Extracts value depending on data type of the property""" 568 if propValue == None: 569 return None 570 571 # Extract data type 572 dataType = propValue['prop'] & self.vtypes.VehiclePropertyType.MASK 573 val = propValue['value'] 574 if self.vtypes.VehiclePropertyType.STRING == dataType: 575 asserts.assertNotEqual(None, val['stringValue']) 576 return val['stringValue'] 577 elif self.vtypes.VehiclePropertyType.INT32 == dataType or \ 578 self.vtypes.VehiclePropertyType.BOOLEAN == dataType: 579 asserts.assertEqual(1, len(val["int32Values"])) 580 return val["int32Values"][0] 581 elif self.vtypes.VehiclePropertyType.INT64 == dataType: 582 asserts.assertEqual(1, len(val["int64Values"])) 583 return val["int64Values"][0] 584 elif self.vtypes.VehiclePropertyType.FLOAT == dataType: 585 asserts.assertEqual(1, len(val["floatValues"])) 586 return val["floatValues"][0] 587 elif self.vtypes.VehiclePropertyType.INT32_VEC == dataType: 588 asserts.assertLess(0, len(val["int32Values"])) 589 return val["int32Values"] 590 elif self.vtypes.VehiclePropertyType.FLOAT_VEC == dataType: 591 asserts.assertLess(0, len(val["floatValues"])) 592 return val["floatValues"] 593 elif self.vtypes.VehiclePropertyType.BYTES == dataType: 594 asserts.assertLess(0, len(val["bytes"])) 595 return val["bytes"] 596 else: 597 return val 598 599 def verifyEnumPropIfSupported(self, propertyId, validValues): 600 """Verifies that if given property supported it is one of the value in validValues set""" 601 supported, val = self.getValueIfPropSupported(propertyId) 602 if supported: 603 asserts.assertEqual(int, type(val)) 604 self.assertIntValueInRangeForProp(val, validValues, propertyId) 605 606 def assertLessOrEqual(self, first, second, msg=None): 607 """Asserts that first <= second""" 608 if second < first: 609 fullMsg = "%s is not less or equal to %s" % (first, second) 610 if msg: 611 fullMsg = "%s %s" % (fullMsg, msg) 612 fail(fullMsg) 613 614 def assertIntValueInRangeForProp(self, value, validValues, prop): 615 """Asserts that given value is in the validValues range""" 616 asserts.assertTrue(value in validValues, 617 "Invalid value %d for property: 0x%x, expected one of: %s" % (value, prop, validValues)) 618 619 def assertValueInRangeForProp(self, value, rangeBegin, rangeEnd, prop): 620 """Asserts that given value is in the range [rangeBegin, rangeEnd]""" 621 msg = "Value %s is out of range [%s, %s] for property 0x%x" % (value, rangeBegin, rangeEnd, prop) 622 self.assertLessOrEqual(rangeBegin, value, msg) 623 self.assertLessOrEqual(value, rangeEnd, msg) 624 625 def getPropConfig(self, propertyId): 626 return self.propToConfig[propertyId] 627 628 def isPropSupported(self, propertyId): 629 return self.getPropConfig(propertyId) is not None 630 631 def testEngineOilTemp(self): 632 """tests engine oil temperature. 633 634 This also tests an HIDL async callback. 635 """ 636 self.onPropertyEventCalled = 0 637 self.onPropertySetCalled = 0 638 self.onPropertySetErrorCalled = 0 639 640 def onPropertyEvent(vehiclePropValues): 641 logging.info("onPropertyEvent received: %s", vehiclePropValues) 642 self.onPropertyEventCalled += 1 643 644 def onPropertySet(vehiclePropValue): 645 logging.info("onPropertySet notification received: %s", vehiclePropValue) 646 self.onPropertySetCalled += 1 647 648 def onPropertySetError(erroCode, propId, areaId): 649 logging.info("onPropertySetError, error: %d, prop: 0x%x, area: 0x%x", 650 erroCode, prop, area) 651 self.onPropertySetErrorCalled += 1 652 653 config = self.getPropConfig(self.vtypes.VehicleProperty.ENGINE_OIL_TEMP) 654 if (config is None): 655 logging.info("ENGINE_OIL_TEMP property is not supported") 656 return # Property not supported, we are done here. 657 658 propValue = self.readVhalProperty(self.vtypes.VehicleProperty.ENGINE_OIL_TEMP) 659 asserts.assertEqual(1, len(propValue['value']['floatValues'])) 660 oilTemp = propValue['value']['floatValues'][0] 661 logging.info("Current oil temperature: %f C", oilTemp) 662 asserts.assertLess(oilTemp, 200) # Check it is in reasinable range 663 asserts.assertLess(-50, oilTemp) 664 665 if (config["changeMode"] == self.vtypes.VehiclePropertyChangeMode.CONTINUOUS): 666 logging.info("ENGINE_OIL_TEMP is continuous property, subscribing...") 667 callback = self.vehicle.GetHidlCallbackInterface("IVehicleCallback", 668 onPropertyEvent=onPropertyEvent, 669 onPropertySet=onPropertySet, 670 onPropertySetError=onPropertySetError) 671 672 subscribeOptions = { 673 "propId" : self.vtypes.VehicleProperty.ENGINE_OIL_TEMP, 674 "vehicleAreas" : 0, 675 "sampleRate" : 10.0, # Hz 676 "flags" : self.vtypes.SubscribeFlags.HAL_EVENT, 677 } 678 pbSubscribeOptions = self.vtypes.Py2Pb("SubscribeOptions", subscribeOptions) 679 680 self.vehicle.subscribe(callback, [pbSubscribeOptions]) 681 for _ in range(5): 682 if (self.onPropertyEventCalled > 0 or 683 self.onPropertySetCalled > 0 or 684 self.onPropertySetErrorCalled > 0): 685 return 686 time.sleep(1) 687 asserts.fail("Callback not called in 5 seconds.") 688 689 if __name__ == "__main__": 690 test_runner.main() 691